22
22
import org .codehaus .groovy .ast .ClassHelper ;
23
23
import org .codehaus .groovy .ast .ClassNode ;
24
24
import org .codehaus .groovy .ast .ConstructorNode ;
25
+ import org .codehaus .groovy .ast .FieldNode ;
25
26
import org .codehaus .groovy .ast .GroovyCodeVisitor ;
26
27
import org .codehaus .groovy .ast .InnerClassNode ;
27
28
import org .codehaus .groovy .ast .MethodNode ;
@@ -186,7 +187,16 @@ public void writeSpecialConstructorCall(final ConstructorCallExpression call) {
186
187
/**
187
188
* Attempts to make a direct method call on a bridge method, if it exists.
188
189
*/
190
+ @ Deprecated
189
191
protected boolean tryBridgeMethod (MethodNode target , Expression receiver , boolean implicitThis , TupleExpression args ) {
192
+ return tryBridgeMethod (target , receiver , implicitThis , args , null );
193
+ }
194
+
195
+ /**
196
+ * Attempts to make a direct method call on a bridge method, if it exists.
197
+ */
198
+ protected boolean tryBridgeMethod (MethodNode target , Expression receiver , boolean implicitThis ,
199
+ TupleExpression args , ClassNode thisClass ) {
190
200
ClassNode lookupClassNode ;
191
201
if (target .isProtected ()) {
192
202
lookupClassNode = controller .getClassNode ();
@@ -203,8 +213,22 @@ protected boolean tryBridgeMethod(MethodNode target, Expression receiver, boolea
203
213
MethodNode bridge = bridges ==null ?null :bridges .get (target );
204
214
if (bridge != null ) {
205
215
Expression fixedReceiver = receiver ;
206
- if (implicitThis && !controller .isInClosure ()) {
207
- fixedReceiver = new PropertyExpression (new ClassExpression (lookupClassNode ), "this" );
216
+ if (implicitThis ) {
217
+ if (!controller .isInClosure ()) {
218
+ fixedReceiver = new PropertyExpression (new ClassExpression (lookupClassNode ), "this" );
219
+ } else if (thisClass != null ) {
220
+ ClassNode current = thisClass .getOuterClass ();
221
+ fixedReceiver = new VariableExpression ("thisObject" , current );
222
+ // adjust for multiple levels of nesting if needed
223
+ while (current != null && current instanceof InnerClassNode && !lookupClassNode .equals (current )) {
224
+ FieldNode thisField = current .getField ("this$0" );
225
+ current = current .getOuterClass ();
226
+ if (thisField != null ) {
227
+ fixedReceiver = new PropertyExpression (fixedReceiver , "this$0" );
228
+ fixedReceiver .setType (current );
229
+ }
230
+ }
231
+ }
208
232
}
209
233
ArgumentListExpression newArgs = new ArgumentListExpression (target .isStatic ()?new ConstantExpression (null ):fixedReceiver );
210
234
for (Expression expression : args .getExpressions ()) {
@@ -261,7 +285,7 @@ protected boolean writeDirectMethodCall(final MethodNode target, final boolean i
261
285
&& controller .isInClosure ()
262
286
&& !target .isPublic ()
263
287
&& target .getDeclaringClass () != classNode ) {
264
- if (!tryBridgeMethod (target , receiver , implicitThis , args )) {
288
+ if (!tryBridgeMethod (target , receiver , implicitThis , args , classNode )) {
265
289
// replace call with an invoker helper call
266
290
ArrayExpression arr = new ArrayExpression (ClassHelper .OBJECT_TYPE , args .getExpressions ());
267
291
MethodCallExpression mce = new MethodCallExpression (
@@ -281,6 +305,8 @@ protected boolean writeDirectMethodCall(final MethodNode target, final boolean i
281
305
}
282
306
return true ;
283
307
}
308
+ Expression fixedReceiver = null ;
309
+ boolean fixedImplicitThis = implicitThis ;
284
310
if (target .isPrivate ()) {
285
311
if (tryPrivateMethod (target , implicitThis , receiver , args , classNode )) return true ;
286
312
} else if (target .isProtected ()) {
@@ -295,16 +321,36 @@ protected boolean writeDirectMethodCall(final MethodNode target, final boolean i
295
321
controller .getSourceUnit ().addError (
296
322
new SyntaxException ("Method " + target .getName () + " is protected in " + target .getDeclaringClass ().toString (false ),
297
323
src .getLineNumber (), src .getColumnNumber (), src .getLastLineNumber (), src .getLastColumnNumber ()));
298
- } else if (!node .isDerivedFrom (target .getDeclaringClass ()) && tryBridgeMethod (target , receiver , implicitThis , args )) {
324
+ } else if (!node .isDerivedFrom (target .getDeclaringClass ()) && tryBridgeMethod (target , receiver , implicitThis , args , classNode )) {
299
325
return true ;
300
326
}
327
+ } else if (target .isPublic () && receiver != null ) {
328
+ if (implicitThis
329
+ && !classNode .isDerivedFrom (target .getDeclaringClass ())
330
+ && !classNode .implementsInterface (target .getDeclaringClass ())
331
+ && classNode instanceof InnerClassNode && controller .isInClosure ()) {
332
+ ClassNode current = classNode .getOuterClass ();
333
+ fixedReceiver = new VariableExpression ("thisObject" , current );
334
+ // adjust for multiple levels of nesting if needed
335
+ while (current != null && current instanceof InnerClassNode && !classNode .equals (current )) {
336
+ FieldNode thisField = current .getField ("this$0" );
337
+ current = current .getOuterClass ();
338
+ if (thisField != null ) {
339
+ fixedReceiver = new PropertyExpression (fixedReceiver , "this$0" );
340
+ fixedReceiver .setType (current );
341
+ fixedImplicitThis = false ;
342
+ }
343
+ }
344
+ }
301
345
}
302
346
if (receiver != null ) {
303
- if (!(receiver instanceof VariableExpression ) || !((VariableExpression ) receiver ).isSuperExpression ()) {
347
+ boolean callToSuper = receiver instanceof VariableExpression && ((VariableExpression ) receiver ).isSuperExpression ();
348
+ if (!callToSuper ) {
349
+ fixedReceiver = fixedReceiver == null ? receiver : fixedReceiver ;
304
350
// in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead
305
351
// then replace the top operand type
306
- Expression checkCastReceiver = new CheckcastReceiverExpression (receiver , target );
307
- return super .writeDirectMethodCall (target , implicitThis , checkCastReceiver , args );
352
+ Expression checkCastReceiver = new CheckcastReceiverExpression (fixedReceiver , target );
353
+ return super .writeDirectMethodCall (target , fixedImplicitThis , checkCastReceiver , args );
308
354
}
309
355
}
310
356
return super .writeDirectMethodCall (target , implicitThis , receiver , args );
@@ -316,7 +362,7 @@ private boolean tryPrivateMethod(final MethodNode target, final boolean implicit
316
362
if ((isPrivateBridgeMethodsCallAllowed (declaringClass , classNode ) || isPrivateBridgeMethodsCallAllowed (classNode , declaringClass ))
317
363
&& declaringClass .getNodeMetaData (PRIVATE_BRIDGE_METHODS ) != null
318
364
&& !declaringClass .equals (classNode )) {
319
- if (tryBridgeMethod (target , receiver , implicitThis , args )) {
365
+ if (tryBridgeMethod (target , receiver , implicitThis , args , classNode )) {
320
366
return true ;
321
367
} else if (declaringClass != classNode ) {
322
368
controller .getSourceUnit ().addError (new SyntaxException ("Cannot call private method " + (target .isStatic () ? "static " : "" ) +
0 commit comments