Search in sources :

Example 1 with StringConversionNode

use of org.checkerframework.dataflow.cfg.node.StringConversionNode in project bazel by bazelbuild.

the class FlowExpressions method internalReprOf.

/**
     * We ignore operations such as widening and
     * narrowing when computing the internal representation.
     *
     * @return The internal representation (as {@link Receiver}) of any
     *         {@link Node}. Might contain {@link Unknown}.
     */
public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode, boolean allowNonDeterminitic) {
    Receiver receiver = null;
    if (receiverNode instanceof FieldAccessNode) {
        FieldAccessNode fan = (FieldAccessNode) receiverNode;
        if (fan.getFieldName().equals("this")) {
            // For some reason, "className.this" is considered a field access.
            // We right this wrong here.
            receiver = new ThisReference(fan.getReceiver().getType());
        } else {
            receiver = internalReprOfFieldAccess(provider, fan);
        }
    } else if (receiverNode instanceof ExplicitThisLiteralNode) {
        receiver = new ThisReference(receiverNode.getType());
    } else if (receiverNode instanceof ThisLiteralNode) {
        receiver = new ThisReference(receiverNode.getType());
    } else if (receiverNode instanceof SuperNode) {
        receiver = new ThisReference(receiverNode.getType());
    } else if (receiverNode instanceof LocalVariableNode) {
        LocalVariableNode lv = (LocalVariableNode) receiverNode;
        receiver = new LocalVariable(lv);
    } else if (receiverNode instanceof ArrayAccessNode) {
        ArrayAccessNode a = (ArrayAccessNode) receiverNode;
        receiver = internalReprOfArrayAccess(provider, a);
    } else if (receiverNode instanceof StringConversionNode) {
        // ignore string conversion
        return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand());
    } else if (receiverNode instanceof WideningConversionNode) {
        // ignore widening
        return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand());
    } else if (receiverNode instanceof NarrowingConversionNode) {
        // ignore narrowing
        return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand());
    } else if (receiverNode instanceof ClassNameNode) {
        ClassNameNode cn = (ClassNameNode) receiverNode;
        receiver = new ClassName(cn.getType());
    } else if (receiverNode instanceof ValueLiteralNode) {
        ValueLiteralNode vn = (ValueLiteralNode) receiverNode;
        receiver = new ValueLiteral(vn.getType(), vn);
    } else if (receiverNode instanceof MethodInvocationNode) {
        MethodInvocationNode mn = (MethodInvocationNode) receiverNode;
        ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree());
        // check if this represents a boxing operation of a constant, in which
        // case we treat the method call as deterministic, because there is no way
        // to behave differently in two executions where two constants are being used.
        boolean considerDeterministic = false;
        if (invokedMethod.toString().equals("valueOf(long)") && mn.getTarget().getReceiver().toString().equals("Long")) {
            Node arg = mn.getArgument(0);
            if (arg instanceof ValueLiteralNode) {
                considerDeterministic = true;
            }
        }
        if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterminitic || considerDeterministic) {
            List<Receiver> parameters = new ArrayList<>();
            for (Node p : mn.getArguments()) {
                parameters.add(internalReprOf(provider, p));
            }
            Receiver methodReceiver;
            if (ElementUtils.isStatic(invokedMethod)) {
                methodReceiver = new ClassName(mn.getTarget().getReceiver().getType());
            } else {
                methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver());
            }
            receiver = new PureMethodCall(mn.getType(), invokedMethod, methodReceiver, parameters);
        }
    }
    if (receiver == null) {
        receiver = new Unknown(receiverNode.getType());
    }
    return receiver;
}
Also used : MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) SuperNode(org.checkerframework.dataflow.cfg.node.SuperNode) ArrayAccessNode(org.checkerframework.dataflow.cfg.node.ArrayAccessNode) ExecutableElement(javax.lang.model.element.ExecutableElement) ThisLiteralNode(org.checkerframework.dataflow.cfg.node.ThisLiteralNode) ValueLiteralNode(org.checkerframework.dataflow.cfg.node.ValueLiteralNode) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) WideningConversionNode(org.checkerframework.dataflow.cfg.node.WideningConversionNode) ClassNameNode(org.checkerframework.dataflow.cfg.node.ClassNameNode) ArrayAccessNode(org.checkerframework.dataflow.cfg.node.ArrayAccessNode) SuperNode(org.checkerframework.dataflow.cfg.node.SuperNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) NarrowingConversionNode(org.checkerframework.dataflow.cfg.node.NarrowingConversionNode) ExplicitThisLiteralNode(org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode) Node(org.checkerframework.dataflow.cfg.node.Node) ClassNameNode(org.checkerframework.dataflow.cfg.node.ClassNameNode) ExplicitThisLiteralNode(org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) ValueLiteralNode(org.checkerframework.dataflow.cfg.node.ValueLiteralNode) WideningConversionNode(org.checkerframework.dataflow.cfg.node.WideningConversionNode) NarrowingConversionNode(org.checkerframework.dataflow.cfg.node.NarrowingConversionNode) ThisLiteralNode(org.checkerframework.dataflow.cfg.node.ThisLiteralNode) ExplicitThisLiteralNode(org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode) ArrayList(java.util.ArrayList) List(java.util.List)

Example 2 with StringConversionNode

use of org.checkerframework.dataflow.cfg.node.StringConversionNode in project checker-framework by typetools.

the class ValueTransfer method createAnnotationForStringConcatenation.

/**
 * Creates an annotation for a result of string concatenation.
 */
private AnnotationMirror createAnnotationForStringConcatenation(Node leftOperand, Node rightOperand, TransferInput<CFValue, CFStore> p) {
    // Try using sets of string values
    List<String> leftValues = getStringValues(leftOperand, p);
    List<String> rightValues = getStringValues(rightOperand, p);
    boolean nonNullStringConcat = atypeFactory.getChecker().hasOption("nonNullStringsConcatenation");
    if (leftValues != null && rightValues != null) {
        // Both operands have known string values, compute set of results
        if (!nonNullStringConcat) {
            if (isNullable(leftOperand)) {
                leftValues = CollectionsPlume.append(leftValues, "null");
            }
            if (isNullable(rightOperand)) {
                rightValues = CollectionsPlume.append(rightValues, "null");
            }
        } else {
            if (leftOperand instanceof StringConversionNode) {
                if (((StringConversionNode) leftOperand).getOperand().getType().getKind() == TypeKind.NULL) {
                    leftValues = CollectionsPlume.append(leftValues, "null");
                }
            }
            if (rightOperand instanceof StringConversionNode) {
                if (((StringConversionNode) rightOperand).getOperand().getType().getKind() == TypeKind.NULL) {
                    rightValues = CollectionsPlume.append(rightValues, "null");
                }
            }
        }
        List<String> concatValues = new ArrayList<>(leftValues.size() * rightValues.size());
        for (String left : leftValues) {
            for (String right : rightValues) {
                concatValues.add(left + right);
            }
        }
        return atypeFactory.createStringAnnotation(concatValues);
    }
    // Try using sets of lengths
    List<Integer> leftLengths = leftValues != null ? ValueCheckerUtils.getLengthsForStringValues(leftValues) : getStringLengths(leftOperand, p);
    List<Integer> rightLengths = rightValues != null ? ValueCheckerUtils.getLengthsForStringValues(rightValues) : getStringLengths(rightOperand, p);
    if (leftLengths != null && rightLengths != null) {
        // Both operands have known lengths, compute set of result lengths
        if (!nonNullStringConcat) {
            if (isNullable(leftOperand)) {
                leftLengths = new ArrayList<>(leftLengths);
                // "null"
                leftLengths.add(4);
            }
            if (isNullable(rightOperand)) {
                rightLengths = new ArrayList<>(rightLengths);
                // "null"
                rightLengths.add(4);
            }
        }
        List<Integer> concatLengths = calculateLengthAddition(leftLengths, rightLengths);
        return atypeFactory.createArrayLenAnnotation(concatLengths);
    }
    // Try using ranges of lengths
    Range leftLengthRange = leftLengths != null ? ValueCheckerUtils.getRangeFromValues(leftLengths) : getStringLengthRange(leftOperand, p);
    Range rightLengthRange = rightLengths != null ? ValueCheckerUtils.getRangeFromValues(rightLengths) : getStringLengthRange(rightOperand, p);
    if (leftLengthRange != null && rightLengthRange != null) {
        // Both operands have a length from a known range, compute a range of result lengths
        if (!nonNullStringConcat) {
            if (isNullable(leftOperand)) {
                // "null"
                leftLengthRange = leftLengthRange.union(Range.create(4, 4));
            }
            if (isNullable(rightOperand)) {
                // "null"
                rightLengthRange = rightLengthRange.union(Range.create(4, 4));
            }
        }
        Range concatLengthRange = calculateLengthRangeAddition(leftLengthRange, rightLengthRange);
        return atypeFactory.createArrayLenRangeAnnotation(concatLengthRange);
    }
    return atypeFactory.UNKNOWNVAL;
}
Also used : ArrayList(java.util.ArrayList) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) ArrayLenRange(org.checkerframework.common.value.qual.ArrayLenRange) Range(org.checkerframework.common.value.util.Range)

Example 3 with StringConversionNode

use of org.checkerframework.dataflow.cfg.node.StringConversionNode in project checker-framework by typetools.

the class ValueTransfer method getStringLengths.

/**
 * Returns a list of possible lengths for {@code subNode}, as casted to a String. Returns null if
 * {@code subNode}'s type is top/unknown. Returns an empty list if {@code subNode}'s type is
 * bottom.
 */
private List<Integer> getStringLengths(Node subNode, TransferInput<CFValue, CFStore> p) {
    CFValue value = p.getValueOfSubNode(subNode);
    AnnotationMirror anno = getValueAnnotation(value);
    if (anno == null) {
        return null;
    }
    String annoName = AnnotationUtils.annotationName(anno);
    if (annoName.equals(ValueAnnotatedTypeFactory.ARRAYLEN_NAME)) {
        return atypeFactory.getArrayLength(anno);
    } else if (annoName.equals(ValueAnnotatedTypeFactory.BOTTOMVAL_NAME)) {
        return Collections.emptyList();
    }
    TypeKind subNodeTypeKind = subNode.getType().getKind();
    // handle values converted to string (characters, bytes, shorts, ints with @IntRange)
    if (subNode instanceof StringConversionNode) {
        return getStringLengths(((StringConversionNode) subNode).getOperand(), p);
    } else if (subNodeTypeKind == TypeKind.CHAR) {
        // characters always have length 1
        return Collections.singletonList(1);
    } else if (isIntRange(subNode, p)) {
        // Try to get a list of lengths from a range of integer values converted to string @IntVal is
        // not checked for, because if it is present, we would already have the actual string values
        Range lengthRange = getIntRangeStringLengthRange(subNode, p);
        return ValueCheckerUtils.getValuesFromRange(lengthRange, Integer.class);
    } else if (subNodeTypeKind == TypeKind.BYTE) {
        // bytes are between 1 and 4 characters long
        return ValueCheckerUtils.getValuesFromRange(Range.create(1, 4), Integer.class);
    } else if (subNodeTypeKind == TypeKind.SHORT) {
        // shorts are between 1 and 6 characters long
        return ValueCheckerUtils.getValuesFromRange(Range.create(1, 6), Integer.class);
    } else {
        return null;
    }
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) AnnotationMirror(javax.lang.model.element.AnnotationMirror) TypeKind(javax.lang.model.type.TypeKind) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) ArrayLenRange(org.checkerframework.common.value.qual.ArrayLenRange) Range(org.checkerframework.common.value.util.Range)

Example 4 with StringConversionNode

use of org.checkerframework.dataflow.cfg.node.StringConversionNode in project checker-framework by typetools.

the class ValueTransfer method getStringValues.

/**
 * Returns a list of possible values for {@code subNode}, as casted to a String. Returns null if
 * {@code subNode}'s type is top/unknown. Returns an empty list if {@code subNode}'s type is
 * bottom.
 *
 * @param subNode a subNode of p
 * @param p TransferInput
 * @return a list of possible values for {@code subNode} or null
 */
private List<String> getStringValues(Node subNode, TransferInput<CFValue, CFStore> p) {
    CFValue value = p.getValueOfSubNode(subNode);
    AnnotationMirror anno = getValueAnnotation(value);
    if (anno == null) {
        return null;
    }
    String annoName = AnnotationUtils.annotationName(anno);
    switch(annoName) {
        case ValueAnnotatedTypeFactory.UNKNOWN_NAME:
            return null;
        case ValueAnnotatedTypeFactory.BOTTOMVAL_NAME:
            return Collections.emptyList();
        case ValueAnnotatedTypeFactory.STRINGVAL_NAME:
            return atypeFactory.getStringValues(anno);
        default:
    }
    // @IntVal, @IntRange, @DoubleVal, @BoolVal (have to be converted to string)
    List<? extends Object> values;
    if (annoName.equals(ValueAnnotatedTypeFactory.BOOLVAL_NAME)) {
        values = getBooleanValues(subNode, p);
    } else if (subNode.getType().getKind() == TypeKind.CHAR) {
        values = getCharValues(subNode, p);
    } else if (subNode instanceof StringConversionNode) {
        return getStringValues(((StringConversionNode) subNode).getOperand(), p);
    } else if (isIntRange(subNode, p)) {
        Range range = getIntRange(subNode, p);
        List<Long> longValues = ValueCheckerUtils.getValuesFromRange(range, Long.class);
        values = NumberUtils.castNumbers(subNode.getType(), longValues);
    } else {
        values = getNumericalValues(subNode, p);
    }
    if (values == null) {
        return null;
    }
    List<String> stringValues = CollectionsPlume.mapList(Object::toString, values);
    // Empty list means bottom value
    return stringValues.isEmpty() ? Collections.singletonList("null") : stringValues;
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) AnnotationMirror(javax.lang.model.element.AnnotationMirror) List(java.util.List) ArrayList(java.util.ArrayList) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) ArrayLenRange(org.checkerframework.common.value.qual.ArrayLenRange) Range(org.checkerframework.common.value.util.Range)

Example 5 with StringConversionNode

use of org.checkerframework.dataflow.cfg.node.StringConversionNode in project checker-framework by typetools.

the class FlowExpressions method internalReprOf.

/**
 * We ignore operations such as widening and narrowing when computing the internal
 * representation.
 *
 * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain
 *     {@link Unknown}.
 */
public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode, boolean allowNonDeterministic) {
    Receiver receiver = null;
    if (receiverNode instanceof FieldAccessNode) {
        FieldAccessNode fan = (FieldAccessNode) receiverNode;
        if (fan.getFieldName().equals("this")) {
            // For some reason, "className.this" is considered a field access.
            // We right this wrong here.
            receiver = new ThisReference(fan.getReceiver().getType());
        } else if (fan.getFieldName().equals("class")) {
            // "className.class" is considered a field access. This makes sense,
            // since .class is similar to a field access which is the equivalent
            // of a call to getClass(). However for the purposes of dataflow
            // analysis, and value stores, this is the equivalent of a ClassNameNode.
            receiver = new ClassName(fan.getReceiver().getType());
        } else {
            receiver = internalReprOfFieldAccess(provider, fan);
        }
    } else if (receiverNode instanceof ExplicitThisLiteralNode) {
        receiver = new ThisReference(receiverNode.getType());
    } else if (receiverNode instanceof ThisLiteralNode) {
        receiver = new ThisReference(receiverNode.getType());
    } else if (receiverNode instanceof SuperNode) {
        receiver = new ThisReference(receiverNode.getType());
    } else if (receiverNode instanceof LocalVariableNode) {
        LocalVariableNode lv = (LocalVariableNode) receiverNode;
        receiver = new LocalVariable(lv);
    } else if (receiverNode instanceof ArrayAccessNode) {
        ArrayAccessNode a = (ArrayAccessNode) receiverNode;
        receiver = internalReprOfArrayAccess(provider, a);
    } else if (receiverNode instanceof StringConversionNode) {
        // ignore string conversion
        return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand());
    } else if (receiverNode instanceof WideningConversionNode) {
        // ignore widening
        return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand());
    } else if (receiverNode instanceof NarrowingConversionNode) {
        // ignore narrowing
        return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand());
    } else if (receiverNode instanceof ClassNameNode) {
        ClassNameNode cn = (ClassNameNode) receiverNode;
        receiver = new ClassName(cn.getType());
    } else if (receiverNode instanceof ValueLiteralNode) {
        ValueLiteralNode vn = (ValueLiteralNode) receiverNode;
        receiver = new ValueLiteral(vn.getType(), vn);
    } else if (receiverNode instanceof ArrayCreationNode) {
        ArrayCreationNode an = (ArrayCreationNode) receiverNode;
        List<Receiver> dimensions = new ArrayList<>();
        for (Node dimension : an.getDimensions()) {
            dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic));
        }
        List<Receiver> initializers = new ArrayList<>();
        for (Node initializer : an.getInitializers()) {
            initializers.add(internalReprOf(provider, initializer, allowNonDeterministic));
        }
        receiver = new ArrayCreation(an.getType(), dimensions, initializers);
    } else if (receiverNode instanceof MethodInvocationNode) {
        MethodInvocationNode mn = (MethodInvocationNode) receiverNode;
        ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree());
        // check if this represents a boxing operation of a constant, in which
        // case we treat the method call as deterministic, because there is no way
        // to behave differently in two executions where two constants are being used.
        boolean considerDeterministic = false;
        if (isLongValueOf(mn, invokedMethod)) {
            Node arg = mn.getArgument(0);
            if (arg instanceof ValueLiteralNode) {
                considerDeterministic = true;
            }
        }
        if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic || considerDeterministic) {
            List<Receiver> parameters = new ArrayList<>();
            for (Node p : mn.getArguments()) {
                parameters.add(internalReprOf(provider, p));
            }
            Receiver methodReceiver;
            if (ElementUtils.isStatic(invokedMethod)) {
                methodReceiver = new ClassName(mn.getTarget().getReceiver().getType());
            } else {
                methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver());
            }
            receiver = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters);
        }
    }
    if (receiver == null) {
        receiver = new Unknown(receiverNode.getType());
    }
    return receiver;
}
Also used : ArrayCreationNode(org.checkerframework.dataflow.cfg.node.ArrayCreationNode) ThisLiteralNode(org.checkerframework.dataflow.cfg.node.ThisLiteralNode) ValueLiteralNode(org.checkerframework.dataflow.cfg.node.ValueLiteralNode) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) WideningConversionNode(org.checkerframework.dataflow.cfg.node.WideningConversionNode) ClassNameNode(org.checkerframework.dataflow.cfg.node.ClassNameNode) ArrayAccessNode(org.checkerframework.dataflow.cfg.node.ArrayAccessNode) SuperNode(org.checkerframework.dataflow.cfg.node.SuperNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) NarrowingConversionNode(org.checkerframework.dataflow.cfg.node.NarrowingConversionNode) ExplicitThisLiteralNode(org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode) Node(org.checkerframework.dataflow.cfg.node.Node) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) ClassNameNode(org.checkerframework.dataflow.cfg.node.ClassNameNode) StringConversionNode(org.checkerframework.dataflow.cfg.node.StringConversionNode) ArrayCreationNode(org.checkerframework.dataflow.cfg.node.ArrayCreationNode) WideningConversionNode(org.checkerframework.dataflow.cfg.node.WideningConversionNode) NarrowingConversionNode(org.checkerframework.dataflow.cfg.node.NarrowingConversionNode) ThisLiteralNode(org.checkerframework.dataflow.cfg.node.ThisLiteralNode) ExplicitThisLiteralNode(org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode) ArrayList(java.util.ArrayList) List(java.util.List) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) SuperNode(org.checkerframework.dataflow.cfg.node.SuperNode) ArrayAccessNode(org.checkerframework.dataflow.cfg.node.ArrayAccessNode) ExplicitThisLiteralNode(org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) ValueLiteralNode(org.checkerframework.dataflow.cfg.node.ValueLiteralNode)

Aggregations

StringConversionNode (org.checkerframework.dataflow.cfg.node.StringConversionNode)8 ArrayList (java.util.ArrayList)5 List (java.util.List)4 ArrayAccessNode (org.checkerframework.dataflow.cfg.node.ArrayAccessNode)4 ClassNameNode (org.checkerframework.dataflow.cfg.node.ClassNameNode)4 FieldAccessNode (org.checkerframework.dataflow.cfg.node.FieldAccessNode)4 LocalVariableNode (org.checkerframework.dataflow.cfg.node.LocalVariableNode)4 MethodInvocationNode (org.checkerframework.dataflow.cfg.node.MethodInvocationNode)4 NarrowingConversionNode (org.checkerframework.dataflow.cfg.node.NarrowingConversionNode)4 SuperNode (org.checkerframework.dataflow.cfg.node.SuperNode)4 ValueLiteralNode (org.checkerframework.dataflow.cfg.node.ValueLiteralNode)4 WideningConversionNode (org.checkerframework.dataflow.cfg.node.WideningConversionNode)4 AnnotationMirror (javax.lang.model.element.AnnotationMirror)3 ExecutableElement (javax.lang.model.element.ExecutableElement)3 ArrayLenRange (org.checkerframework.common.value.qual.ArrayLenRange)3 Range (org.checkerframework.common.value.util.Range)3 ArrayCreationNode (org.checkerframework.dataflow.cfg.node.ArrayCreationNode)3 Node (org.checkerframework.dataflow.cfg.node.Node)3 TypeKind (javax.lang.model.type.TypeKind)2 ExplicitThisLiteralNode (org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode)2