ClassNode classNode = controller.getClassNode();
if (isThisOrSuper(objectExpression)) {
// let's use the field expression if it's available
String name = expression.getPropertyAsString();
if (name != null) {
FieldNode field = null;
boolean privateSuperField = false;
if (isSuperExpression(objectExpression)) {
field = classNode.getSuperClass().getDeclaredField(name);
if (field != null && ((field.getModifiers() & ACC_PRIVATE) != 0)) {
privateSuperField = true;
}
} else {
if (controller.isNotExplicitThisInClosure(expression.isImplicitThis())) {
field = classNode.getDeclaredField(name);
if (field==null && classNode instanceof InnerClassNode) {
ClassNode outer = classNode.getOuterClass();
FieldNode outerClassField;
while (outer!=null) {
outerClassField = outer.getDeclaredField(name);
if (outerClassField!=null && outerClassField.isStatic() && outerClassField.isFinal()) {
if (outer!=classNode.getOuterClass() && Modifier.isPrivate(outerClassField.getModifiers())) {
throw new GroovyBugError("Trying to access private constant field ["+outerClassField.getDeclaringClass()+"#"+outerClassField.getName()+"] from inner class");
}
PropertyExpression pexp = new PropertyExpression(
new ClassExpression(outer),
expression.getProperty()
);
pexp.visit(controller.getAcg());
return;
}
outer = outer.getSuperClass();
}
}
if (field==null
&& expression instanceof AttributeExpression
&& isThisExpression(objectExpression)
&& controller.isStaticContext()) {
// GROOVY-6183
ClassNode current = classNode.getSuperClass();
while (field==null && current!=null) {
field = current.getDeclaredField(name);
current = current.getSuperClass();
}
if (field!=null && (field.isProtected() || field.isPublic())) {
visitFieldExpression(new FieldExpression(field));
return;
}
}
}
}
if (field != null && !privateSuperField) {//GROOVY-4497: don't visit super field if it is private
visitFieldExpression(new FieldExpression(field));
return;
}
}
if (isSuperExpression(objectExpression)) {
String prefix;
if (controller.getCompileStack().isLHS()) {
prefix = "set";
} else {
prefix = "get";
}
String propName = prefix + MetaClassHelper.capitalize(name);
visitMethodCallExpression(new MethodCallExpression(objectExpression, propName, MethodCallExpression.NO_ARGUMENTS));
return;
}
}
final String propName = expression.getPropertyAsString();
//TODO: add support for super here too
if (expression.getObjectExpression() instanceof ClassExpression &&
propName!=null && propName.equals("this"))
{
// we have something like A.B.this, and need to make it
// into this.this$0.this$0, where this.this$0 returns
// A.B and this.this$0.this$0 return A.
ClassNode type = objectExpression.getType();
ClassNode iterType = classNode;
if (controller.getCompileStack().isInSpecialConstructorCall() && classNode instanceof InnerClassNode) {
boolean staticInnerClass = classNode.isStaticClass();
// Outer.this in a special constructor call
if (classNode.getOuterClass().equals(type)) {
ConstructorNode ctor = controller.getConstructorNode();
Expression receiver = !staticInnerClass ? new VariableExpression(ctor.getParameters()[0]) : new ClassExpression(type);
receiver.setSourcePosition(expression);
receiver.visit(this);
return;
}
}
mv.visitVarInsn(ALOAD, 0);
while (!iterType.equals(type)) {
String ownerName = BytecodeHelper.getClassInternalName(iterType);
if (iterType.getOuterClass()==null) break;
FieldNode thisField = iterType.getField("this$0");
if (thisField==null) break;
ClassNode thisFieldType = thisField.getType();
iterType = iterType.getOuterClass();
if (ClassHelper.CLOSURE_TYPE.equals(thisFieldType)) {
mv.visitFieldInsn(GETFIELD, ownerName, "this$0", BytecodeHelper.getTypeDescription(ClassHelper.CLOSURE_TYPE));
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ClassHelper.CLOSURE_TYPE), "getThisObject", "()Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(iterType));