1818 */
1919package org .codehaus .groovy .classgen ;
2020
21- import groovy .transform .CompileStatic ;
22- import groovy .transform .stc .POJO ;
23- import org .codehaus .groovy .ast .ClassHelper ;
2421import org .codehaus .groovy .ast .ClassNode ;
2522import org .codehaus .groovy .ast .ConstructorNode ;
2623import org .codehaus .groovy .ast .FieldNode ;
2724import org .codehaus .groovy .ast .InnerClassNode ;
28- import org .codehaus .groovy .ast .MethodNode ;
2925import org .codehaus .groovy .ast .Parameter ;
3026import org .codehaus .groovy .ast .expr .ConstructorCallExpression ;
3127import org .codehaus .groovy .ast .expr .Expression ;
3228import org .codehaus .groovy .ast .expr .TupleExpression ;
3329import org .codehaus .groovy .ast .expr .VariableExpression ;
3430import org .codehaus .groovy .ast .stmt .BlockStatement ;
35- import org .codehaus .groovy .ast .stmt .TryCatchStatement ;
36- import org .codehaus .groovy .classgen .asm .BytecodeHelper ;
3731import org .codehaus .groovy .control .CompilationUnit ;
3832import org .codehaus .groovy .control .SourceUnit ;
39- import org .objectweb .asm .MethodVisitor ;
4033
41- import java .util .Arrays ;
4234import java .util .List ;
4335import java .util .StringJoiner ;
44- import java .util .function .BiConsumer ;
4536
46- import static org .apache .groovy .ast .tools .AnnotatedNodeUtils .hasAnnotation ;
4737import static org .apache .groovy .ast .tools .ClassNodeUtils .addGeneratedConstructor ;
48- import static org .apache .groovy .ast .tools .ClassNodeUtils .getMethod ;
4938import static org .apache .groovy .ast .tools .ConstructorNodeUtils .getFirstIfSpecialConstructorCall ;
5039import static org .apache .groovy .ast .tools .MethodNodeUtils .getCodeAsBlock ;
51- import static org .codehaus .groovy .ast .ClassHelper .CLOSURE_TYPE ;
52- import static org .codehaus .groovy .ast .ClassHelper .OBJECT_TYPE ;
53- import static org .codehaus .groovy .ast .ClassHelper .STRING_TYPE ;
54- import static org .codehaus .groovy .ast .ClassHelper .VOID_TYPE ;
55- import static org .codehaus .groovy .ast .tools .GeneralUtils .args ;
5640import static org .codehaus .groovy .ast .tools .GeneralUtils .block ;
57- import static org .codehaus .groovy .ast .tools .GeneralUtils .callThisX ;
58- import static org .codehaus .groovy .ast .tools .GeneralUtils .callX ;
5941import static org .codehaus .groovy .ast .tools .GeneralUtils .castX ;
60- import static org .codehaus .groovy .ast .tools .GeneralUtils .catchS ;
61- import static org .codehaus .groovy .ast .tools .GeneralUtils .classX ;
6242import static org .codehaus .groovy .ast .tools .GeneralUtils .ctorSuperX ;
6343import static org .codehaus .groovy .ast .tools .GeneralUtils .ctorThisX ;
64- import static org .codehaus .groovy .ast .tools .GeneralUtils .ctorX ;
6544import static org .codehaus .groovy .ast .tools .GeneralUtils .nullX ;
66- import static org .codehaus .groovy .ast .tools .GeneralUtils .param ;
67- import static org .codehaus .groovy .ast .tools .GeneralUtils .params ;
6845import static org .codehaus .groovy .ast .tools .GeneralUtils .stmt ;
69- import static org .codehaus .groovy .ast .tools .GeneralUtils .throwS ;
70- import static org .codehaus .groovy .ast .tools .GeneralUtils .tryCatchS ;
7146import static org .codehaus .groovy .ast .tools .GeneralUtils .varX ;
7247import static org .codehaus .groovy .transform .trait .Traits .isTrait ;
7348import static org .objectweb .asm .Opcodes .ACC_FINAL ;
7449import static org .objectweb .asm .Opcodes .ACC_MANDATED ;
7550import static org .objectweb .asm .Opcodes .ACC_PUBLIC ;
7651import static org .objectweb .asm .Opcodes .ACC_STATIC ;
7752import static org .objectweb .asm .Opcodes .ACC_SYNTHETIC ;
78- import static org .objectweb .asm .Opcodes .ACONST_NULL ;
79- import static org .objectweb .asm .Opcodes .ALOAD ;
80- import static org .objectweb .asm .Opcodes .ARETURN ;
81- import static org .objectweb .asm .Opcodes .CHECKCAST ;
82- import static org .objectweb .asm .Opcodes .GETFIELD ;
83- import static org .objectweb .asm .Opcodes .INVOKEVIRTUAL ;
8453
8554public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
8655
@@ -104,25 +73,13 @@ public void visitClass(final ClassNode node) {
10473
10574 if (node .isEnum () || node .isInterface () || isTrait (node .getOuterClass ())) return ;
10675
107- // if the class has an inner class, add methods to support private member access
108- if (node .getInnerClasses ().hasNext ()) {
109- addDispatcherMethods (node );
110- }
111-
11276 if (node instanceof InnerClassNode innerClass ) {
11377 thisField = node .getDeclaredField ("this$0" );
11478 if (innerClass .getVariableScope () == null && node .getDeclaredConstructors ().isEmpty ()) {
11579 // add empty default constructor
11680 addGeneratedConstructor (innerClass , ACC_PUBLIC , Parameter .EMPTY_ARRAY , null , null );
11781 }
118-
11982 super .visitClass (node );
120-
121- boolean innerPojo = hasAnnotation (node , new ClassNode (POJO .class ))
122- && hasAnnotation (node , new ClassNode (CompileStatic .class ));
123- if (!innerPojo && !isStatic (innerClass )) {
124- addMopMethods (innerClass );
125- }
12683 }
12784 }
12885
@@ -156,195 +113,7 @@ private static void makeBridgeConstructor(final ClassNode c, final Parameter[] p
156113 }
157114 }
158115
159- private static String getTypeDescriptor (ClassNode node , boolean isStatic ) {
160- return BytecodeHelper .getTypeDescription (getClassNode (node , isStatic ));
161- }
162-
163- private static String getInternalName (ClassNode node , boolean isStatic ) {
164- return BytecodeHelper .getClassInternalName (getClassNode (node , isStatic ));
165- }
166-
167- private static void addDispatcherMethods (ClassNode classNode ) {
168- final int objectDistance = getObjectDistance (classNode );
169-
170- // since we added an anonymous inner class we should also
171- // add the dispatcher methods
172-
173- // add method dispatcher
174- BlockStatement block = new BlockStatement ();
175- MethodNode method = classNode .addSyntheticMethod (
176- "this$dist$invoke$" + objectDistance ,
177- ACC_PUBLIC ,
178- OBJECT_TYPE ,
179- params (param (STRING_TYPE , "name" ), param (OBJECT_TYPE , "args" )),
180- ClassNode .EMPTY_ARRAY ,
181- block
182- );
183- setMethodDispatcherCode (block , VariableExpression .THIS_EXPRESSION , method .getParameters ());
184-
185- // add property setter
186- block = new BlockStatement ();
187- method = classNode .addSyntheticMethod (
188- "this$dist$set$" + objectDistance ,
189- ACC_PUBLIC ,
190- VOID_TYPE ,
191- params (param (STRING_TYPE , "name" ), param (OBJECT_TYPE , "value" )),
192- ClassNode .EMPTY_ARRAY ,
193- block
194- );
195- setPropertySetterDispatcher (block , VariableExpression .THIS_EXPRESSION , method .getParameters ());
196-
197- // add property getter
198- block = new BlockStatement ();
199- method = classNode .addSyntheticMethod (
200- "this$dist$get$" + objectDistance ,
201- ACC_PUBLIC ,
202- OBJECT_TYPE ,
203- params (param (STRING_TYPE , "name" )),
204- ClassNode .EMPTY_ARRAY ,
205- block
206- );
207- setPropertyGetterDispatcher (block , VariableExpression .THIS_EXPRESSION , method .getParameters ());
208- }
209-
210- private void getThis (final MethodVisitor mv , final String classInternalName , final String outerClassDescriptor , final String innerClassInternalName ) {
211- mv .visitVarInsn (ALOAD , 0 );
212- if (thisField != null && CLOSURE_TYPE .equals (thisField .getType ())) {
213- mv .visitFieldInsn (GETFIELD , classInternalName , "this$0" , BytecodeHelper .getTypeDescription (CLOSURE_TYPE ));
214- mv .visitMethodInsn (INVOKEVIRTUAL , BytecodeHelper .getClassInternalName (CLOSURE_TYPE ), "getThisObject" , "()Ljava/lang/Object;" , false );
215- mv .visitTypeInsn (CHECKCAST , innerClassInternalName );
216- } else {
217- mv .visitFieldInsn (GETFIELD , classInternalName , "this$0" , outerClassDescriptor );
218- }
219- }
220-
221- private void addMopMethods (final InnerClassNode node ) {
222- final boolean isStatic = isStatic (node );
223- final ClassNode outerClass = node .getOuterClass ();
224- final int outerClassDistance = getObjectDistance (outerClass );
225- final String classInternalName = BytecodeHelper .getClassInternalName (node );
226- final String outerClassInternalName = getInternalName (outerClass , isStatic );
227- final String outerClassDescriptor = getTypeDescriptor (outerClass , isStatic );
228-
229- addMissingHandler (node ,
230- "methodMissing" ,
231- ACC_PUBLIC ,
232- OBJECT_TYPE ,
233- params (param (STRING_TYPE , "name" ), param (OBJECT_TYPE , "args" )),
234- (methodBody , parameters ) -> {
235- if (isStatic ) {
236- setMethodDispatcherCode (methodBody , classX (outerClass ), parameters );
237- } else {
238- methodBody .addStatement (
239- new BytecodeSequence (new BytecodeInstruction () {
240- @ Override
241- public void visit (final MethodVisitor mv ) {
242- getThis (mv , classInternalName , outerClassDescriptor , outerClassInternalName );
243- mv .visitVarInsn (ALOAD , 1 );
244- mv .visitVarInsn (ALOAD , 2 );
245- mv .visitMethodInsn (INVOKEVIRTUAL , outerClassInternalName , "this$dist$invoke$" + outerClassDistance , "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;" , false );
246- mv .visitInsn (ARETURN );
247- }
248- })
249- );
250- }
251- }
252- );
253-
254- ClassNode [] nameValueTypes = {STRING_TYPE , OBJECT_TYPE };
255- MethodNode propertyMissing = getMethod (node , "propertyMissing" , (m ) -> !m .isStatic () && !m .isPrivate ()
256- && Arrays .equals (Arrays .stream (m .getParameters ()).map (Parameter ::getType ).toArray (),nameValueTypes ));
257- ClassNode returnType = propertyMissing != null ? propertyMissing .getReturnType () : VOID_TYPE ; // GROOVY-11822
258-
259- addMissingHandler (node ,
260- "propertyMissing" ,
261- ACC_PUBLIC ,
262- returnType ,
263- params (param (STRING_TYPE , "name" ), param (OBJECT_TYPE , "value" )),
264- (methodBody , parameters ) -> {
265- if (isStatic ) {
266- setPropertySetterDispatcher (methodBody , classX (outerClass ), parameters );
267- } else {
268- methodBody .addStatement (
269- new BytecodeSequence (new BytecodeInstruction () {
270- @ Override
271- public void visit (final MethodVisitor mv ) {
272- getThis (mv , classInternalName , outerClassDescriptor , outerClassInternalName );
273- mv .visitVarInsn (ALOAD , 1 );
274- mv .visitVarInsn (ALOAD , 2 );
275- mv .visitMethodInsn (INVOKEVIRTUAL , outerClassInternalName , "this$dist$set$" + outerClassDistance , "(Ljava/lang/String;Ljava/lang/Object;)V" , false );
276- if (!ClassHelper .isPrimitiveVoid (returnType )) mv .visitInsn (ACONST_NULL );
277- BytecodeHelper .doReturn (mv , returnType );
278- }
279- })
280- );
281- }
282- }
283- );
284-
285- addMissingHandler (node ,
286- "propertyMissing" ,
287- ACC_PUBLIC ,
288- OBJECT_TYPE ,
289- params (param (STRING_TYPE , "name" )),
290- (methodBody , parameters ) -> {
291- if (isStatic ) {
292- setPropertyGetterDispatcher (methodBody , classX (outerClass ), parameters );
293- } else {
294- methodBody .addStatement (
295- new BytecodeSequence (new BytecodeInstruction () {
296- @ Override
297- public void visit (final MethodVisitor mv ) {
298- getThis (mv , classInternalName , outerClassDescriptor , outerClassInternalName );
299- mv .visitVarInsn (ALOAD , 1 );
300- mv .visitMethodInsn (INVOKEVIRTUAL , outerClassInternalName , "this$dist$get$" + outerClassDistance , "(Ljava/lang/String;)Ljava/lang/Object;" , false );
301- mv .visitInsn (ARETURN );
302- }
303- })
304- );
305- }
306- }
307- );
308- }
309-
310- private void addMissingHandler (final InnerClassNode innerClass , final String methodName , final int modifiers ,
311- final ClassNode returnType , final Parameter [] parameters , final BiConsumer <BlockStatement , Parameter []> consumer ) {
312- MethodNode method = innerClass .getDeclaredMethod (methodName , parameters );
313- if (method == null ) {
314- // try {
315- // <consumer dispatch>
316- // } catch (MissingMethodException notFound) {
317- // throw new MissingMethodException(notFound.method, this, notFound.arguments)
318- // }
319- Parameter catchParam = param (OBJECT_TYPE , "notFound" ); // dummy type
320- ClassNode exceptionT ;
321- Expression newException ;
322- if (methodName .endsWith ("methodMissing" )) {
323- exceptionT = ClassHelper .make (groovy .lang .MissingMethodException .class );
324- newException = ctorX (exceptionT , args (callX (varX (catchParam ),"getMethod" ), callThisX ("getClass" ), callX (varX (catchParam ),"getArguments" )));
325- } else {
326- exceptionT = ClassHelper .make (groovy .lang .MissingPropertyException .class );
327- newException = ctorX (exceptionT , args (callX (varX (catchParam ),"getProperty" ), callThisX ("getClass" ), callX (varX (catchParam ),"getCause" )));
328- }
329- catchParam .setType (exceptionT );
330- catchParam .setOriginType (exceptionT );
331- BlockStatement handleMissing = block ();
332- consumer .accept (handleMissing , parameters );
333- TryCatchStatement tryCatch = tryCatchS (handleMissing );
334- tryCatch .addCatch (catchS (catchParam , throwS (newException )));
335-
336- innerClass .addSyntheticMethod (methodName , modifiers , returnType , parameters , ClassNode .EMPTY_ARRAY , tryCatch );
337-
338- // if there is a user-defined method, add compiler error and continue
339- } else if (isStatic (innerClass ) && (method .getModifiers () & ACC_SYNTHETIC ) == 0 ) {
340- addError ("\" " + methodName + "\" implementations are not supported on static inner classes as " +
341- "a synthetic version of \" " + methodName + "\" is added during compilation for the purpose " +
342- "of outer class delegation." ,
343- method );
344- }
345- }
346-
347- private void addThisReference (ConstructorNode node ) {
116+ private void addThisReference (final ConstructorNode node ) {
348117 if (!shouldHandleImplicitThisForInnerClass (classNode )) return ;
349118
350119 // add "this$0" field init
@@ -396,7 +165,7 @@ private void addThisReference(ConstructorNode node) {
396165 node .setCode (block );
397166 }
398167
399- private boolean shouldImplicitlyPassThisZero (ConstructorCallExpression cce ) {
168+ private boolean shouldImplicitlyPassThisZero (final ConstructorCallExpression cce ) {
400169 boolean pass = false ;
401170 if (cce .isThisCall ()) {
402171 pass = true ;
@@ -415,7 +184,7 @@ private boolean shouldImplicitlyPassThisZero(ConstructorCallExpression cce) {
415184 return pass ;
416185 }
417186
418- private String getUniqueName (Parameter [] params , ConstructorNode node ) {
187+ private String getUniqueName (final Parameter [] params , final ConstructorNode node ) {
419188 String namePrefix = "$p" ;
420189 outer :
421190 for (int i = 0 ; i < 100 ; i ++) {
0 commit comments