Skip to content

Commit 19f3899

Browse files
committed
GROOVY-11907: trait field reference transform restructure
1 parent bc8bc7a commit 19f3899

1 file changed

Lines changed: 36 additions & 57 deletions

File tree

src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java

Lines changed: 36 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@
5151
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
5252
import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
5353
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
54-
import static org.codehaus.groovy.ast.tools.GeneralUtils.isInstanceOfX;
5554
import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
56-
import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX;
5755
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
5856

5957
/**
@@ -71,18 +69,18 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
7169
private final VariableExpression weaved;
7270
private final SourceUnit unit;
7371
private final ClassNode traitClass;
74-
private final ClassNode traitHelperClass;
72+
private final ClassNode traitHelper;
7573
private final ClassNode fieldHelper;
7674
private final Collection<String> knownFields;
7775

7876
private boolean inClosure;
7977

8078
public TraitReceiverTransformer(final VariableExpression thisObject, final SourceUnit unit, final ClassNode traitClass,
81-
final ClassNode traitHelperClass, final ClassNode fieldHelper, final Collection<String> knownFields) {
79+
final ClassNode traitHelper, final ClassNode fieldHelper, final Collection<String> knownFields) {
8280
this.weaved = thisObject;
8381
this.unit = unit;
8482
this.traitClass = traitClass;
85-
this.traitHelperClass = traitHelperClass;
83+
this.traitHelper = traitHelper;
8684
this.fieldHelper = fieldHelper;
8785
this.knownFields = knownFields;
8886
}
@@ -94,9 +92,8 @@ protected SourceUnit getSourceUnit() {
9492

9593
@Override
9694
public Expression transform(final Expression exp) {
97-
ClassNode weavedType = weaved.getOriginType();
9895
if (exp instanceof BinaryExpression) {
99-
return transformBinaryExpression((BinaryExpression) exp, weavedType);
96+
return transformBinaryExpression((BinaryExpression) exp);
10097
} else if (exp instanceof MethodCallExpression mce) {
10198
String obj = mce.getObjectExpression().getText();
10299
if ("super".equals(obj)) {
@@ -105,15 +102,13 @@ public Expression transform(final Expression exp) {
105102
return transformMethodCallOnThis(mce); // this.m(x) --> $self.m(x) or this.m($self, x)
106103
}
107104
} else if (exp instanceof FieldExpression) {
108-
FieldNode fn = ((FieldExpression) exp).getField();
109-
return transformFieldReference(exp, fn, fn.isStatic());
105+
return transformFieldReference(exp, ((FieldExpression) exp).getField(), null);
110106
} else if (exp instanceof VariableExpression vexp) {
111107
Variable accessedVariable = vexp.getAccessedVariable();
112108
if (accessedVariable instanceof FieldNode || accessedVariable instanceof PropertyNode) {
113109
if (knownFields.contains(vexp.getName())) {
114-
boolean isStatic = accessedVariable.isStatic();
115110
return transformFieldReference(exp, accessedVariable instanceof FieldNode
116-
? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField(), isStatic);
111+
? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField(), null);
117112
} else {
118113
PropertyExpression propertyExpression = propX(varX(weaved), vexp.getName());
119114
propertyExpression.getProperty().setSourcePosition(exp);
@@ -137,8 +132,8 @@ public Expression transform(final Expression exp) {
137132
if (pexp.isImplicitThis() || "this".equals(obj)) {
138133
String propName = pexp.getPropertyAsString();
139134
if (knownFields.contains(propName)) {
140-
FieldNode fn = new FieldNode(propName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
141-
return transformFieldReference(exp, fn, false);
135+
FieldNode fn = new FieldNode(propName, 0, ClassHelper.OBJECT_TYPE, weaved.getOriginType(), null);
136+
return transformFieldReference(exp, fn, null);
142137
}
143138
}
144139
} else if (exp instanceof ClosureExpression) {
@@ -164,7 +159,7 @@ public Expression transform(final Expression exp) {
164159
return super.transform(exp);
165160
}
166161

167-
private Expression transformBinaryExpression(final BinaryExpression exp, final ClassNode weavedType) {
162+
private Expression transformBinaryExpression(final BinaryExpression exp) {
168163
Expression leftExpression = exp.getLeftExpression();
169164
Expression rightExpression = exp.getRightExpression();
170165
Token operation = exp.getOperation();
@@ -179,29 +174,13 @@ private Expression transformBinaryExpression(final BinaryExpression exp, final C
179174
leftFieldName = ((PropertyExpression) leftExpression).getPropertyAsString();
180175
}
181176
if (leftFieldName != null) {
182-
FieldNode staticField = tryGetFieldNode(weavedType, leftFieldName);
183-
if (fieldHelper == null || staticField == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
177+
ClassNode weavedType = weaved.getOriginType();
178+
FieldNode traitField = tryGetFieldNode(weavedType, leftFieldName);
179+
FieldNode dummyField = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
180+
if (fieldHelper == null || traitField == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(dummyField), rightExpression)) {
184181
return binX(propX(varX(weaved), leftFieldName), operation, transform(rightExpression)); // GROOVY-7342, GROOVY-7456, GROOVY-9739, GROOVY-10143, et al.
185182
}
186-
FieldNode fn = weavedType.getDeclaredField(leftFieldName);
187-
if (fn == null) {
188-
fn = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
189-
}
190-
Expression receiver = createFieldHelperReceiver();
191-
boolean isStatic = staticField != null && staticField.isStatic();
192-
if (fn.isStatic()) { // DO NOT USE isStatic variable here!
193-
receiver = propX(receiver, "class");
194-
}
195-
String method = Traits.helperSetterName(fn);
196-
MethodCallExpression mce = callX(
197-
receiver,
198-
method,
199-
super.transform(rightExpression)
200-
);
201-
mce.setImplicitThis(false);
202-
mce.setSourcePosition(exp);
203-
markDynamicCall(mce, staticField, isStatic);
204-
return mce;
183+
return transformFieldReference(exp, traitField != null ? traitField : dummyField, rightExpression);
205184
}
206185
}
207186

@@ -214,23 +193,32 @@ private Expression transformBinaryExpression(final BinaryExpression exp, final C
214193
return ret;
215194
}
216195

217-
private Expression transformFieldReference(final Expression exp, final FieldNode fn, final boolean isStatic) {
218-
Expression receiver = createFieldHelperReceiver();
219-
if (isStatic) {
220-
receiver = asClass(receiver);
196+
private Expression transformFieldReference(final Expression exp, final FieldNode fn, final Expression value) {
197+
Expression receiver;
198+
if (ClassHelper.isClassType(weaved.getOriginType())) {
199+
receiver = varX(weaved); // $static$self
200+
} else if (fn.isStatic()) {
201+
var call = callX(varX(weaved), "getClass"); // $self.getClass()
202+
call.setImplicitThis(false);
203+
call.setMethodTarget(ClassHelper.OBJECT_TYPE.getGetterMethod("getClass", false));
204+
receiver = call;
205+
} else {
206+
receiver = castX(fieldHelper, varX(weaved)); // (<trait class>$Trait$FieldHelper) $self
221207
}
222208

223-
MethodCallExpression mce = callX(receiver, Traits.helperGetterName(fn));
209+
MethodCallExpression mce;
210+
if (value == null) {
211+
mce = callX(receiver, Traits.helperGetterName(fn));
212+
} else {
213+
mce = callX(receiver, Traits.helperSetterName(fn), transform(value));
214+
}
224215
mce.setImplicitThis(false);
225216
mce.setSourcePosition(exp);
226-
markDynamicCall(mce, fn, isStatic);
227-
return mce;
228-
}
229217

230-
private static void markDynamicCall(final MethodCallExpression mce, final FieldNode fn, final boolean isStatic) {
231-
if (isStatic) {
232-
mce.putNodeMetaData(TraitASTTransformation.DO_DYNAMIC, fn.getOriginType());
233-
}
218+
// GROOVY-7255: static fields are available via the implementing class, which is not checkable
219+
if (fn.isStatic()) mce.putNodeMetaData(TraitASTTransformation.DO_DYNAMIC, fn.getOriginType());
220+
221+
return mce;
234222
}
235223

236224
private static FieldNode tryGetFieldNode(final ClassNode weavedType, final String fieldName) {
@@ -287,7 +275,7 @@ private Expression transformMethodCallOnThis(final MethodCallExpression call) {
287275
if (methodNode != null) {
288276
// this.m(x) --> (this or T$Trait$Helper).m($self or $static$self or (Class)$self.getClass(), x)
289277
Expression selfClassOrObject = methodNode.isStatic() && !ClassHelper.isClassType(weaved.getOriginType()) ? castX(ClassHelper.CLASS_Type.getPlainNodeReference(), callX(weaved, "getClass")) : weaved;
290-
MethodCallExpression newCall = callX(!inClosure ? thisExpr : classX(traitHelperClass), method, createArgumentList(selfClassOrObject, arguments));
278+
MethodCallExpression newCall = callX(!inClosure ? thisExpr : classX(traitHelper), method, createArgumentList(selfClassOrObject, arguments));
291279
newCall.setGenericsTypes(call.getGenericsTypes());
292280
newCall.setSpreadSafe(call.isSpreadSafe());
293281
newCall.setSourcePosition(call);
@@ -341,13 +329,4 @@ private ArgumentListExpression createArgumentList(final Expression self, final E
341329
}
342330
return newArgs;
343331
}
344-
345-
private Expression createFieldHelperReceiver() {
346-
return ClassHelper.isClassType(weaved.getOriginType()) ? weaved : castX(fieldHelper, weaved);
347-
}
348-
349-
private Expression asClass(final Expression e) {
350-
ClassNode rawClass = ClassHelper.CLASS_Type.getPlainNodeReference();
351-
return ternaryX(isInstanceOfX(e, rawClass), e, callX(e, "getClass"));
352-
}
353332
}

0 commit comments

Comments
 (0)