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);
}
}
}