@@ -54,6 +54,10 @@ public class LocalVariableTableRenamer extends ClassVisitor {
54
54
private final String toNamespace ;
55
55
private final ClassMapping <NamespacedMapping > mapping ;
56
56
57
+ private boolean isRecord ;
58
+ private ObjectArrayList <String > recordNames ;
59
+ private StringBuilder recordDesc ;
60
+
57
61
public LocalVariableTableRenamer (ClassVisitor classVisitor , boolean rvn ) {
58
62
super (Info .ASM_VERSION , classVisitor );
59
63
this .rvn = rvn ;
@@ -75,13 +79,33 @@ public void visit(int version, int access, String name, String signature, String
75
79
if (mapping != null && !mapping .mapping .getName (fromNamespace ).equals (name ))
76
80
throw new IllegalArgumentException ("Mapping mismatch" );
77
81
this .className = name ;
82
+ this .isRecord = (access & Opcodes .ACC_RECORD ) != 0 ;
83
+ if (isRecord ) {
84
+ recordDesc = new StringBuilder ("<init>(" );
85
+ recordNames = new ObjectArrayList <>();
86
+ }
78
87
super .visit (version , access , name , signature , superName , interfaces );
79
88
}
80
89
90
+ @ Override
91
+ public RecordComponentVisitor visitRecordComponent (String name , String descriptor , String signature ) {
92
+ recordDesc .append (descriptor );
93
+ recordNames .add (name );
94
+ return super .visitRecordComponent (name , descriptor , signature );
95
+ }
96
+
81
97
@ Override
82
98
public MethodVisitor visitMethod (int access , String name , String descriptor , String signature , String [] exceptions ) {
99
+ if (isRecord && recordDesc .charAt (recordDesc .length () - 2 ) != ')' ) recordDesc .append (")V" );
100
+ boolean maySkip = false ;
101
+ if (isRecord ) {
102
+ String nd = name .concat (descriptor );
103
+ if (nd .equals ("equals(Ljava/lang/Object;)Z" ) || nd .equals ("hashCode()I" ) || nd .equals ("toString()Ljava/lang/String" ))
104
+ return super .visitMethod (access , name , descriptor , signature , exceptions );
105
+ if (nd .contentEquals (recordDesc )) maySkip = true ;
106
+ }
83
107
// Filter some methods because only lambda methods need to share renamer with the caller
84
- Renamer renamer = (access & (Opcodes .ACC_SYNTHETIC | Opcodes .ACC_PRIVATE )) == ( Opcodes . ACC_SYNTHETIC | Opcodes . ACC_PRIVATE ) ?
108
+ Renamer renamer = (access & (Opcodes .ACC_SYNTHETIC | Opcodes .ACC_PRIVATE )) != 0 ?
85
109
sharedRenamers .getOrDefault (String .join ("." , className , name , descriptor ), new Renamer ()) : new Renamer ();
86
110
if ((access & Opcodes .ACC_ABSTRACT ) != 0 && recordStarted && !descriptor .startsWith ("()" )) {
87
111
StringJoiner joiner = new StringJoiner (" " ).add (className ).add (name ).add (descriptor );
@@ -106,9 +130,19 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str
106
130
}).toArray (NamespacedMapping []::new );
107
131
if (m .length > 1 ) throw new IllegalArgumentException ("Method duplicated" );
108
132
return m .length == 1 && m [0 ].hasComponent (LocalVariableTable .Namespaced .class ) ? Optional .of (m [0 ]) : Optional .empty ();
109
- })
110
- . map ( LocalVariableTable . Namespaced . class :: cast ) ;
133
+ }). map ( m -> m . getComponent ( LocalVariableTable . Namespaced . class ));
134
+ final boolean finalMaySkip = maySkip ;
111
135
return new MethodVisitor (api , super .visitMethod (access , name , descriptor , signature , exceptions )) {
136
+ private boolean skip ;
137
+ private int i ;
138
+ @ Override
139
+ public void visitMethodInsn (int opcode , String owner , String name , String descriptor , boolean isInterface ) {
140
+ if (finalMaySkip && !skip && opcode == Opcodes .INVOKESPECIAL && owner .equals ("java/lang/Record" ) &&
141
+ name .equals ("<init>" ) && descriptor .equals ("()V" ))
142
+ skip = true ;
143
+ super .visitMethodInsn (opcode , owner , name , descriptor , isInterface );
144
+ }
145
+
112
146
@ Override
113
147
public void visitInvokeDynamicInsn (String n , String desc , Handle bootstrapMethodHandle , Object ... bootstrapMethodArguments ) {
114
148
if ("java/lang/invoke/LambdaMetafactory" .equals (bootstrapMethodHandle .getOwner ())) {
@@ -124,9 +158,11 @@ public void visitInvokeDynamicInsn(String n, String desc, Handle bootstrapMethod
124
158
125
159
@ Override
126
160
public void visitLocalVariable (String name , String descriptor , String signature , Label start , Label end , int index ) {
127
- if (index == 0 && (access & Opcodes .ACC_STATIC ) == 0 ) {
128
- super .visitLocalVariable ("this" , descriptor , signature , start , end , index );
129
- } else {
161
+ if (index != 0 || (access & Opcodes .ACC_STATIC ) != 0 ) {
162
+ if (skip && i < recordNames .size ()) {
163
+ super .visitLocalVariable (recordNames .get (i ++), descriptor , signature , start , end , index );
164
+ return ;
165
+ }
130
166
if (lvt .isPresent ()) {
131
167
String s = lvt .get ().getLocalVariableName (index , toNamespace );
132
168
if (s != null && !s .isBlank () && !placeholderMatcher .reset (s ).matches ()) {
@@ -138,8 +174,8 @@ public void visitLocalVariable(String name, String descriptor, String signature,
138
174
super .visitLocalVariable (renamer .getVarName (Type .getType (descriptor )), descriptor , signature , start , end , index );
139
175
return ;
140
176
}
141
- super .visitLocalVariable (name , descriptor , signature , start , end , index );
142
177
}
178
+ super .visitLocalVariable (name , descriptor , signature , start , end , index );
143
179
}
144
180
};
145
181
}
@@ -168,12 +204,12 @@ public static void endRecord(Path writeTo) throws IOException {
168
204
public static class Renamer {
169
205
private static class Holder {
170
206
public final int id ;
171
- public final boolean skip_zero ;
207
+ public final boolean skipZero ;
172
208
public final ObjectArrayList <String > names = new ObjectArrayList <>();
173
209
174
- public Holder (int id , boolean skip_zero , String ... names ) {
210
+ public Holder (int id , boolean skipZero , String ... names ) {
175
211
this .id = id ;
176
- this .skip_zero = skip_zero ;
212
+ this .skipZero = skipZero ;
177
213
this .names .addElements (0 , names );
178
214
}
179
215
}
@@ -219,7 +255,7 @@ public String getVarName(Type type) {
219
255
varBaseName = holder .names .get (0 );
220
256
int count = vars .getOrDefault (varBaseName , holder .id );
221
257
vars .put (varBaseName , count + 1 );
222
- return varBaseName + (count == 0 && holder .skip_zero ? "" : count );
258
+ return varBaseName + (count == 0 && holder .skipZero ? "" : count );
223
259
} else {
224
260
ids .computeIfAbsent (holder , (ToIntFunction <? super Holder >) h -> h .id );
225
261
for (;;) {
@@ -228,7 +264,7 @@ public String getVarName(Type type) {
228
264
if (!vars .containsKey (varBaseName )) {
229
265
int j = ids .getInt (holder );
230
266
vars .put (varBaseName , j );
231
- return varBaseName + (j == 0 && holder .skip_zero ? "" : j );
267
+ return varBaseName + (j == 0 && holder .skipZero ? "" : j );
232
268
}
233
269
}
234
270
ids .addTo (holder , 1 );
0 commit comments