18
18
19
19
package proguard .util .kotlin .asserter ;
20
20
21
- import java .util .Arrays ;
22
- import java .util .List ;
23
21
import proguard .classfile .ClassPool ;
24
22
import proguard .classfile .Clazz ;
23
+ import proguard .classfile .kotlin .KotlinDeclarationContainerMetadata ;
25
24
import proguard .classfile .kotlin .KotlinMetadata ;
25
+ import proguard .classfile .kotlin .KotlinTypeAliasMetadata ;
26
+ import proguard .classfile .kotlin .KotlinTypeMetadata ;
27
+ import proguard .classfile .kotlin .visitor .AllTypeVisitor ;
26
28
import proguard .classfile .kotlin .visitor .KotlinMetadataRemover ;
27
29
import proguard .classfile .kotlin .visitor .KotlinMetadataVisitor ;
30
+ import proguard .classfile .kotlin .visitor .KotlinTypeAliasVisitor ;
31
+ import proguard .classfile .kotlin .visitor .KotlinTypeVisitor ;
28
32
import proguard .classfile .kotlin .visitor .ReferencedKotlinMetadataVisitor ;
29
33
import proguard .classfile .util .WarningLogger ;
34
+ import proguard .classfile .visitor .ClassVisitor ;
30
35
import proguard .resources .file .ResourceFile ;
31
36
import proguard .resources .file .ResourceFilePool ;
32
37
import proguard .resources .file .visitor .ResourceFileProcessingFlagFilter ;
49
54
import proguard .util .kotlin .asserter .constraint .TypeIntegrity ;
50
55
import proguard .util .kotlin .asserter .constraint .ValueParameterIntegrity ;
51
56
57
+ import java .util .Arrays ;
58
+ import java .util .List ;
59
+
52
60
/**
53
61
* Performs a series of checks to see whether the kotlin metadata is intact.
54
62
*/
@@ -86,6 +94,11 @@ public void execute(WarningLogger warningLogger,
86
94
programClassPool .classesAccept (new ReferencedKotlinMetadataVisitor (kotlinMetadataAsserter ));
87
95
libraryClassPool .classesAccept (new ReferencedKotlinMetadataVisitor (kotlinMetadataAsserter ));
88
96
97
+ ClassVisitor aliasReferenceCleaner =
98
+ new ReferencedKotlinMetadataVisitor (new KotlinTypeAliasReferenceCleaner (reporter ));
99
+ programClassPool .classesAccept (aliasReferenceCleaner );
100
+ libraryClassPool .classesAccept (aliasReferenceCleaner );
101
+
89
102
reporter .setErrorMessage ("Warning: Kotlin module errors encountered in module %s. Not processing the metadata for this module." );
90
103
resourceFilePool .resourceFilesAccept (new ResourceFileProcessingFlagFilter (0 ,
91
104
ProcessingFlags .DONT_PROCESS_KOTLIN_MODULE ,
@@ -95,10 +108,10 @@ public void execute(WarningLogger warningLogger,
95
108
/**
96
109
* This class performs a series of checks to see whether the kotlin metadata is intact
97
110
*/
98
- public static class MyKotlinMetadataAsserter
99
- implements KotlinMetadataVisitor ,
100
- ResourceFileVisitor ,
101
- KotlinModuleVisitor
111
+ private static class MyKotlinMetadataAsserter
112
+ implements KotlinMetadataVisitor ,
113
+ ResourceFileVisitor ,
114
+ KotlinModuleVisitor
102
115
{
103
116
private final List <? extends KotlinAsserterConstraint > constraints ;
104
117
private final Reporter reporter ;
@@ -145,4 +158,84 @@ public void visitKotlinModule(KotlinModule kotlinModule)
145
158
@ Override
146
159
public void visitResourceFile (ResourceFile resourceFile ) {}
147
160
}
161
+
162
+ /**
163
+ * // TODO: This may leave behind further invalid metadata.
164
+ *
165
+ * Cleans up any dangling references caused by removing metadata.
166
+ * <p>
167
+ * A {@link KotlinTypeMetadata} can have a referencedTypeAlias, which
168
+ * refers to a type alias that is declared in a declaration container
169
+ * of which the metadata was invalid and therefore removed, from it's "owner" class.
170
+ * <p>
171
+ * To avoid visiting invalid metadata later, we check if there is a link to
172
+ * a class without metadata and remove the metadata from the class using the type alias
173
+ * if necessary.
174
+ * <p>Example, assuming `kotlin.Exception` is not available:
175
+ * <code>
176
+ * // AClass visited first.
177
+ * // AClass.kt <--- Has a reference to MyFileFacade where MyAlias is declared.
178
+ * class MyClass : MyAlias()
179
+ *
180
+ * // MyFileFacade.kt <--- Invalid because reference for kotlin.Exception not found
181
+ * typealias MyAlias = kotlin.Exception
182
+ *
183
+ * // MyClass hangs onto the reference to MyFileFacade metadata, even though the
184
+ * // metadata from its owner class (MyFileFacadeKt.class) has been removed.
185
+ * </code>
186
+ * </p>
187
+ */
188
+ private static class KotlinTypeAliasReferenceCleaner implements KotlinMetadataVisitor ,
189
+ KotlinTypeVisitor ,
190
+ KotlinTypeAliasVisitor
191
+ {
192
+ private final Reporter reporter ;
193
+ private int count ;
194
+
195
+ private KotlinTypeAliasReferenceCleaner (Reporter reporter )
196
+ {
197
+ this .reporter = reporter ;
198
+ }
199
+
200
+ @ Override
201
+ public void visitAnyKotlinMetadata (Clazz clazz , KotlinMetadata kotlinMetadata )
202
+ {
203
+ reporter .resetCounter (clazz .getName ());
204
+ kotlinMetadata .accept (clazz , new AllTypeVisitor (this ));
205
+ if (reporter .getCount () > 0 )
206
+ {
207
+ clazz .accept (new KotlinMetadataRemover ());
208
+ }
209
+ }
210
+
211
+
212
+ @ Override
213
+ public void visitAnyType (Clazz clazz , KotlinTypeMetadata kotlinTypeMetadata )
214
+ {
215
+ if (kotlinTypeMetadata .aliasName != null &&
216
+ kotlinTypeMetadata .referencedTypeAlias != null )
217
+ {
218
+ // The count will be increase if the alias' declaration container has no metadata.
219
+ count = 0 ;
220
+ kotlinTypeMetadata .referencedTypeAliasAccept (clazz , this );
221
+
222
+ boolean declarationContainerClazzHasNoMetadata = count == 0 ;
223
+
224
+ if (declarationContainerClazzHasNoMetadata )
225
+ {
226
+ reporter .report ("Type alias '" + kotlinTypeMetadata .aliasName + "' is declared in a container with no metadata" );
227
+ }
228
+ }
229
+ }
230
+
231
+
232
+ @ Override
233
+ public void visitTypeAlias (Clazz clazz ,
234
+ KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata ,
235
+ KotlinTypeAliasMetadata kotlinTypeAliasMetadata )
236
+ {
237
+ // The counter will only increase if the owner class has metadata attached.
238
+ kotlinDeclarationContainerMetadata .referencedOwnerClassAccept ((__ , metadata ) -> count ++);
239
+ }
240
+ }
148
241
}
0 commit comments