12
12
import org .cadixdev .bombe .type .VoidType ;
13
13
import org .cadixdev .bombe .type .signature .MethodSignature ;
14
14
import org .jspecify .annotations .NullMarked ;
15
+ import org .jspecify .annotations .Nullable ;
15
16
import org .openrewrite .ExecutionContext ;
16
17
import org .openrewrite .Recipe ;
17
18
import org .openrewrite .TreeVisitor ;
18
19
import org .openrewrite .java .JavaIsoVisitor ;
19
20
import org .openrewrite .java .tree .J ;
20
21
import org .openrewrite .java .tree .JavaType ;
22
+ import org .openrewrite .java .tree .JavaType .FullyQualified ;
21
23
import org .openrewrite .java .tree .TypeTree ;
22
24
import org .slf4j .Logger ;
23
25
import org .slf4j .LoggerFactory ;
@@ -34,6 +36,7 @@ public class MethodATMutator extends Recipe {
34
36
private static final Logger LOGGER = LoggerFactory .getLogger (MethodATMutator .class );
35
37
36
38
private final AccessTransformSet atDictionary ;
39
+ private final AccessTransformSet inheritanceAccessTransformAtDirectory ;
37
40
private final ModifierTransformer modifierTransformer ;
38
41
private final AccessTransformerTypeConverter atTypeConverter ;
39
42
@@ -43,6 +46,12 @@ public MethodATMutator(final AccessTransformSet atDictionary,
43
46
this .atDictionary = atDictionary ;
44
47
this .modifierTransformer = modifierTransformer ;
45
48
this .atTypeConverter = atTypeConverter ;
49
+
50
+ // Create a copy of the atDirectory for inherited at lookups.
51
+ // Needed as the parent type may be processed first, removing its access transformer for tracking purposes.
52
+ // Child types hence lookup using this.
53
+ this .inheritanceAccessTransformAtDirectory = AccessTransformSet .create ();
54
+ this .inheritanceAccessTransformAtDirectory .merge (this .atDictionary );
46
55
}
47
56
48
57
@ Override
@@ -67,20 +76,14 @@ public J.MethodDeclaration visitMethodDeclaration(final J.MethodDeclaration unre
67
76
if (parentClassDeclaration == null || parentClassDeclaration .getType () == null )
68
77
return methodDeclaration ;
69
78
70
- // Find access transformers for class
71
- final AccessTransformSet .Class transformerClass = atDictionary .getClass (
72
- parentClassDeclaration .getType ().getFullyQualifiedName ()
73
- ).orElse (null );
74
- if (transformerClass == null ) return methodDeclaration ;
75
-
76
79
final String methodIdentifier = parentClassDeclaration .getType ().getFullyQualifiedName () + "#" + methodDeclaration .getName ();
77
80
78
81
if (methodDeclaration .getMethodType () == null ) {
79
82
LOGGER .warn ("Method {} did not have a method type!" , methodIdentifier );
80
83
return methodDeclaration ;
81
84
}
82
85
83
- // Fetch access transformer to apply to specific field .
86
+ // Fetch access transformer to apply to specific method .
84
87
String atMethodName = methodDeclaration .getMethodType ().getName ();
85
88
Type returnType = atTypeConverter .convert (methodDeclaration .getMethodType ().getReturnType (),
86
89
() -> "Parsing return type " + methodDeclaration .getReturnTypeExpression ().toString () + " of method " + methodIdentifier );
@@ -101,10 +104,14 @@ public J.MethodDeclaration visitMethodDeclaration(final J.MethodDeclaration unre
101
104
returnType = VoidType .INSTANCE ;
102
105
}
103
106
104
- final AccessTransform accessTransform = transformerClass .replaceMethod (new MethodSignature (
105
- atMethodName , new MethodDescriptor (parameterTypes , returnType )
106
- ), AccessTransform .EMPTY );
107
- if (accessTransform == null || accessTransform .isEmpty ()) return methodDeclaration ;
107
+ // Find access transformers for method
108
+ final AccessTransform accessTransform = findApplicableAccessTransformer (
109
+ parentClassDeclaration .getType (),
110
+ atMethodName ,
111
+ returnType ,
112
+ parameterTypes
113
+ );
114
+ if (accessTransform == null ) return methodDeclaration ;
108
115
109
116
final TypeTree returnTypeExpression = methodDeclaration .getReturnTypeExpression ();
110
117
final ModifierTransformationResult transformationResult = modifierTransformer .transformModifiers (
@@ -125,4 +132,48 @@ atMethodName, new MethodDescriptor(parameterTypes, returnType)
125
132
};
126
133
}
127
134
135
+ /**
136
+ * Finds the applicable access transformer for a method and *optionally* removes it from the atDirectory.
137
+ *
138
+ * @param owningType the owning type of the method, e.g. the type it is defined in.
139
+ * @param atMethodName the method name.
140
+ * @param returnType the return type.
141
+ * @param parameterTypes the method parameters.
142
+ *
143
+ * @return the access transformer or null.
144
+ */
145
+ @ Nullable
146
+ private AccessTransform findApplicableAccessTransformer (
147
+ final FullyQualified owningType ,
148
+ final String atMethodName ,
149
+ final Type returnType ,
150
+ final List <FieldType > parameterTypes
151
+ ) {
152
+ final MethodSignature methodSignature = new MethodSignature (
153
+ atMethodName ,
154
+ new MethodDescriptor (parameterTypes , returnType )
155
+ );
156
+
157
+ for (FullyQualified currentCheckedType = owningType ; currentCheckedType != null ; currentCheckedType = currentCheckedType .getSupertype ()) {
158
+ // The class at data from the copy of the at dir.
159
+ // Removal of these happens later but we need the original state to ensure overrides are updated.
160
+ final AccessTransformSet .Class transformerClass = inheritanceAccessTransformAtDirectory
161
+ .getClass (currentCheckedType .getFullyQualifiedName ())
162
+ .orElse (null );
163
+ if (transformerClass == null ) continue ;
164
+
165
+ // Only get the method here.
166
+ final AccessTransform accessTransform = transformerClass .getMethod (methodSignature );
167
+ if (accessTransform == null || accessTransform .isEmpty ()) continue ;
168
+
169
+ // If we *did* find an AT here and this *is* the direct owning type, remove it from the original atDirectory.
170
+ if (currentCheckedType == owningType ) {
171
+ atDictionary .getClass (transformerClass .getName ()).ifPresent (c -> c .replaceMethod (methodSignature , AccessTransform .EMPTY ));
172
+ }
173
+ return accessTransform ;
174
+ }
175
+
176
+ return null ; // We did not find anything applicable.
177
+ }
178
+
128
179
}
0 commit comments