public void visitVariableExpression()

in src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java [625:722]


    public void visitVariableExpression(final VariableExpression vexp) {
        super.visitVariableExpression(vexp);
        if (storeTypeForSuper(vexp)) return;
        if (storeTypeForThis(vexp)) return;

        final String name = vexp.getName();
        final Variable accessedVariable = vexp.getAccessedVariable();
        final TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();

        if (accessedVariable instanceof DynamicVariable) {
            // a dynamic variable is either a closure property, a class member referenced from a closure, or an undeclared variable

            if (enclosingClosure != null) {
                switch (name) {
                  case "delegate":
                    var dm = getDelegationMetadata(enclosingClosure.getClosureExpression());
                    if (dm != null) {
                        vexp.putNodeMetaData(INFERRED_TYPE, dm.getType());
                        return;
                    }
                    // falls through
                  case "owner":
                    if (typeCheckingContext.getEnclosingClosureStack().size() > 1) {
                        vexp.putNodeMetaData(INFERRED_TYPE, CLOSURE_TYPE.getPlainNodeReference());
                        return;
                    }
                    // falls through
                  case "thisObject":
                    vexp.putNodeMetaData(INFERRED_TYPE, makeThis());
                    return;
                  case "parameterTypes":
                    vexp.putNodeMetaData(INFERRED_TYPE, CLASS_Type.getPlainNodeReference().makeArray());
                    return;
                  case "maximumNumberOfParameters":
                  case "resolveStrategy":
                  case "directive":
                    vexp.putNodeMetaData(INFERRED_TYPE, int_TYPE);
                    return;
                  case "metaClass": // GROOVY-11386
                    vexp.putNodeMetaData(INFERRED_TYPE, METACLASS_TYPE);
                    return;
                }
            }

            if (tryVariableExpressionAsProperty(vexp, name)) return;

            if (!extension.handleUnresolvedVariableExpression(vexp)) {
                addStaticTypeError("The variable [" + name + "] is undeclared.", vexp);
            }
        } else if (accessedVariable instanceof FieldNode) {
            if (tryVariableExpressionAsProperty(vexp, name)) {
                ClassNode temporaryType = getInferredTypeFromTempInfo(vexp, null); // GROOVY-9454
                if (temporaryType != null && !isObjectType(temporaryType)) {
                    vexp.putNodeMetaData(INFERRED_TYPE, temporaryType);
                }
                if (vexp.getAccessedVariable() != accessedVariable) { // GROOVY-11360: field hidden by dynamic property
                    if (vexp.getLineNumber() > 0 && !typeCheckingContext.reportedErrors.contains(((long) vexp.getLineNumber()) << 16 + vexp.getColumnNumber())) {
                        String text = "The field: " + accessedVariable.getName() + " of class: " + prettyPrintTypeName(((FieldNode) accessedVariable).getDeclaringClass()) +
                                                " is hidden by a dynamic property. A qualifier is required to reference it.";
                        Token token = new Token(0, name, vexp.getLineNumber(), vexp.getColumnNumber()); // ASTNode to CSTNode
                        typeCheckingContext.getErrorCollector().addWarning(new WarningMessage(WarningMessage.POSSIBLE_ERRORS, text, token, getSourceUnit()));
                    }
                }
            } else if (!extension.handleUnresolvedVariableExpression(vexp)) { // GROOVY-11356
                addStaticTypeError("No such property: " + name + " for class: " + prettyPrintTypeName(typeCheckingContext.getEnclosingClassNode()), vexp);
            }
        } else if (accessedVariable instanceof PropertyNode) {
            // we must be careful -- the property node may be of a wrong type:
            // if a class contains a getter and a setter of different types or
            // overloaded setters, the type of the property node is arbitrary!
            if (tryVariableExpressionAsProperty(vexp, name)) {
                BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
                if (enclosingBinaryExpression != null) {
                    Expression leftExpression = enclosingBinaryExpression.getLeftExpression();
                    SetterInfo setterInfo = removeSetterInfo(leftExpression);
                    if (setterInfo != null) {
                        Expression rightExpression = enclosingBinaryExpression.getRightExpression();
                        ensureValidSetter(vexp, leftExpression, rightExpression, setterInfo);
                    }
                }
            } else if (!extension.handleUnresolvedVariableExpression(vexp)) { // GROOVY-11356
                addStaticTypeError("No such property: " + name + " for class: " + prettyPrintTypeName(typeCheckingContext.getEnclosingClassNode()), vexp);
            }
        } else if (accessedVariable != null) {
            VariableExpression localVariable;
            if (accessedVariable instanceof Parameter) {
                Parameter prm = (Parameter) accessedVariable;
                localVariable = new ParameterVariableExpression(prm);
            } else {
                localVariable = (VariableExpression) accessedVariable;
            }

            ClassNode inferredType = getInferredTypeFromTempInfo(localVariable, localVariable.getNodeMetaData(INFERRED_TYPE));
            if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(isTraitSelf(vexp))) {
                vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
            }
        }
    }