summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/Deobfuscator.java
diff options
context:
space:
mode:
authorGravatar Gegy2019-01-30 21:05:32 +0200
committerGravatar GitHub2019-01-30 21:05:32 +0200
commitba7a354efae7d49833c887cf147ac940c975a1fa (patch)
tree02e14fda81dd5984e24f2df392c57c6e829fc875 /src/main/java/cuchaz/enigma/Deobfuscator.java
parentRewrite the Jenkinsfile to use the new declarative pipeline syntax, lets hope... (diff)
downloadenigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.gz
enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.xz
enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.zip
Remap sources (#106)
* Source remapping beginnings * Fix navigation to remapped classes * Translate identifier info reference * Remap local variables with default names in source * Caching translator * Fix lack of highlighting for first opened class * Fix unicode variable names * Unicode checker shouldn't be checking just alphanumeric * Fix package tree being built from obf names * Don't index `this` as method call for method::reference * Apply proposed names * Fix source export issues * Replace unicode var names at bytecode level uniquely * Drop imports from editor source * Class selector fixes * Delta keep track of base mappings to enable lookup of old names * Optimize source remapping by remapping source with a StringBuffer instead of copying * Bump version
Diffstat (limited to 'src/main/java/cuchaz/enigma/Deobfuscator.java')
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java267
1 files changed, 115 insertions, 152 deletions
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index 076c546..ef452b0 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -11,36 +11,39 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import com.google.common.base.Functions;
14import com.google.common.base.Stopwatch; 15import com.google.common.base.Stopwatch;
15import com.google.common.collect.Lists;
16import com.strobel.assembler.metadata.ITypeLoader; 16import com.strobel.assembler.metadata.ITypeLoader;
17import com.strobel.assembler.metadata.MetadataSystem; 17import com.strobel.assembler.metadata.MetadataSystem;
18import com.strobel.assembler.metadata.TypeDefinition; 18import com.strobel.assembler.metadata.TypeDefinition;
19import com.strobel.assembler.metadata.TypeReference; 19import com.strobel.assembler.metadata.TypeReference;
20import com.strobel.decompiler.DecompilerContext;
21import com.strobel.decompiler.DecompilerSettings; 20import com.strobel.decompiler.DecompilerSettings;
22import com.strobel.decompiler.PlainTextOutput;
23import com.strobel.decompiler.languages.java.JavaOutputVisitor;
24import com.strobel.decompiler.languages.java.ast.AstBuilder;
25import com.strobel.decompiler.languages.java.ast.CompilationUnit; 21import com.strobel.decompiler.languages.java.ast.CompilationUnit;
26import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; 22import cuchaz.enigma.analysis.EntryReference;
27import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; 23import cuchaz.enigma.analysis.IndexTreeBuilder;
28import cuchaz.enigma.analysis.*; 24import cuchaz.enigma.analysis.ParsedJar;
29import cuchaz.enigma.analysis.index.JarIndex; 25import cuchaz.enigma.analysis.index.JarIndex;
30import cuchaz.enigma.api.EnigmaPlugin; 26import cuchaz.enigma.api.EnigmaPlugin;
27import cuchaz.enigma.bytecode.translators.TranslationClassVisitor;
28import cuchaz.enigma.translation.Translatable;
29import cuchaz.enigma.translation.Translator;
31import cuchaz.enigma.translation.mapping.*; 30import cuchaz.enigma.translation.mapping.*;
32import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree; 31import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree;
33import cuchaz.enigma.translation.mapping.tree.EntryTree; 32import cuchaz.enigma.translation.mapping.tree.EntryTree;
34import cuchaz.enigma.translation.representation.ReferencedEntryPool;
35import cuchaz.enigma.translation.representation.entry.ClassEntry; 33import cuchaz.enigma.translation.representation.entry.ClassEntry;
36import cuchaz.enigma.translation.representation.entry.Entry; 34import cuchaz.enigma.translation.representation.entry.Entry;
37import cuchaz.enigma.translation.representation.entry.MethodEntry; 35import cuchaz.enigma.translation.representation.entry.MethodEntry;
38import cuchaz.enigma.utils.Utils; 36import org.objectweb.asm.ClassVisitor;
39import oml.ast.transformers.*;
40import org.objectweb.asm.ClassWriter; 37import org.objectweb.asm.ClassWriter;
38import org.objectweb.asm.Opcodes;
41import org.objectweb.asm.tree.ClassNode; 39import org.objectweb.asm.tree.ClassNode;
42 40
43import java.io.*; 41import java.io.File;
42import java.io.FileOutputStream;
43import java.io.IOException;
44import java.io.Writer;
45import java.nio.file.Files;
46import java.nio.file.Path;
44import java.util.*; 47import java.util.*;
45import java.util.concurrent.ConcurrentHashMap; 48import java.util.concurrent.ConcurrentHashMap;
46import java.util.concurrent.atomic.AtomicInteger; 49import java.util.concurrent.atomic.AtomicInteger;
@@ -53,11 +56,12 @@ import java.util.stream.Collectors;
53public class Deobfuscator { 56public class Deobfuscator {
54 57
55 private final ServiceLoader<EnigmaPlugin> plugins = ServiceLoader.load(EnigmaPlugin.class); 58 private final ServiceLoader<EnigmaPlugin> plugins = ServiceLoader.load(EnigmaPlugin.class);
56 private final ReferencedEntryPool entryPool = new ReferencedEntryPool();
57 private final ParsedJar parsedJar; 59 private final ParsedJar parsedJar;
58 private final DecompilerSettings settings;
59 private final JarIndex jarIndex; 60 private final JarIndex jarIndex;
60 private final IndexTreeBuilder indexTreeBuilder; 61 private final IndexTreeBuilder indexTreeBuilder;
62
63 private final SourceProvider obfSourceProvider;
64
61 private EntryRemapper mapper; 65 private EntryRemapper mapper;
62 66
63 public Deobfuscator(ParsedJar jar, Consumer<String> listener) { 67 public Deobfuscator(ParsedJar jar, Consumer<String> listener) {
@@ -75,15 +79,8 @@ public class Deobfuscator {
75 this.indexTreeBuilder = new IndexTreeBuilder(jarIndex); 79 this.indexTreeBuilder = new IndexTreeBuilder(jarIndex);
76 80
77 listener.accept("Preparing..."); 81 listener.accept("Preparing...");
78 // config the decompiler 82
79 this.settings = DecompilerSettings.javaDefaults(); 83 this.obfSourceProvider = new SourceProvider(SourceProvider.createSettings(), new CompiledSourceTypeLoader(parsedJar));
80 this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true));
81 this.settings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true));
82 this.settings.setForceExplicitTypeArguments(
83 Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true));
84 // DEBUG
85 this.settings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false));
86 this.settings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false));
87 84
88 // init mappings 85 // init mappings
89 mapper = new EntryRemapper(jarIndex); 86 mapper = new EntryRemapper(jarIndex);
@@ -93,7 +90,7 @@ public class Deobfuscator {
93 this(new ParsedJar(jar), listener); 90 this(new ParsedJar(jar), listener);
94 } 91 }
95 92
96 public Deobfuscator(ParsedJar jar) throws IOException { 93 public Deobfuscator(ParsedJar jar) {
97 this(jar, (msg) -> { 94 this(jar, (msg) -> {
98 }); 95 });
99 } 96 }
@@ -128,9 +125,9 @@ public class Deobfuscator {
128 Collection<Entry<?>> dropped = dropMappings(mappings); 125 Collection<Entry<?>> dropped = dropMappings(mappings);
129 mapper = new EntryRemapper(jarIndex, mappings); 126 mapper = new EntryRemapper(jarIndex, mappings);
130 127
131 DeltaTrackingTree<EntryMapping> deobfToObf = mapper.getDeobfToObf(); 128 DeltaTrackingTree<EntryMapping> obfToDeobf = mapper.getObfToDeobf();
132 for (Entry<?> entry : dropped) { 129 for (Entry<?> entry : dropped) {
133 deobfToObf.trackDeletion(entry); 130 obfToDeobf.trackDeletion(entry);
134 } 131 }
135 } else { 132 } else {
136 mapper = new EntryRemapper(jarIndex); 133 mapper = new EntryRemapper(jarIndex);
@@ -161,7 +158,7 @@ public class Deobfuscator {
161 ClassEntry deobfClassEntry = mapper.deobfuscate(obfClassEntry); 158 ClassEntry deobfClassEntry = mapper.deobfuscate(obfClassEntry);
162 if (!deobfClassEntry.equals(obfClassEntry)) { 159 if (!deobfClassEntry.equals(obfClassEntry)) {
163 // if the class has a mapping, clearly it's deobfuscated 160 // if the class has a mapping, clearly it's deobfuscated
164 deobfClasses.add(deobfClassEntry); 161 deobfClasses.add(obfClassEntry);
165 } else if (obfClassEntry.getPackageName() != null) { 162 } else if (obfClassEntry.getPackageName() != null) {
166 // also call it deobufscated if it's not in the none package 163 // also call it deobufscated if it's not in the none package
167 deobfClasses.add(obfClassEntry); 164 deobfClasses.add(obfClassEntry);
@@ -172,151 +169,126 @@ public class Deobfuscator {
172 } 169 }
173 } 170 }
174 171
175 public TranslatingTypeLoader createTypeLoader() { 172 public SourceProvider getObfSourceProvider() {
176 return new TranslatingTypeLoader( 173 return obfSourceProvider;
177 this.parsedJar,
178 this.jarIndex,
179 this.entryPool,
180 this.mapper.getObfuscator(),
181 this.mapper.getDeobfuscator()
182 );
183 }
184
185 public CompilationUnit getSourceTree(String className) {
186 return getSourceTree(className, createTypeLoader());
187 } 174 }
188 175
189 public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader) { 176 public void writeSources(Path outputDirectory, ProgressListener progress) {
190 return getSourceTree(className, loader, new NoRetryMetadataSystem(loader)); 177 // get the classes to decompile
191 } 178 Collection<ClassEntry> classEntries = jarIndex.getEntryIndex().getClasses();
192 179
193 public CompilationUnit getSourceTree(String className, ITranslatingTypeLoader loader, MetadataSystem metadataSystem) { 180 Stopwatch stopwatch = Stopwatch.createStarted();
194 181
195 // we don't know if this class name is obfuscated or deobfuscated 182 try {
196 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out 183 Translator deobfuscator = mapper.getDeobfuscator();
197 // the decompiler only sees classes after deobfuscation, so we need to load it by the deobfuscated name if there is one
198 184
199 String deobfClassName = mapper.deobfuscate(new ClassEntry(className)).getFullName(); 185 // deobfuscate everything first
186 Map<String, ClassNode> translatedNodes = deobfuscateClasses(progress, classEntries, deobfuscator);
200 187
201 // set the desc loader 188 decompileClasses(outputDirectory, progress, translatedNodes);
202 this.settings.setTypeLoader(loader); 189 } finally {
190 stopwatch.stop();
203 191
204 // see if procyon can find the desc 192 System.out.println("writeSources Done in : " + stopwatch.toString());
205 TypeReference type = metadataSystem.lookupType(deobfClassName);
206 if (type == null) {
207 throw new Error(String.format("Unable to find desc: %s (deobf: %s)\nTried class names: %s",
208 className, deobfClassName, loader.getClassNamesToTry(deobfClassName)
209 ));
210 } 193 }
211 TypeDefinition resolvedType = type.resolve();
212
213 // decompile it!
214 DecompilerContext context = new DecompilerContext();
215 context.setCurrentType(resolvedType);
216 context.setSettings(this.settings);
217 AstBuilder builder = new AstBuilder(context);
218 builder.addType(resolvedType);
219 builder.runTransformations(null);
220 runCustomTransforms(builder, context);
221 return builder.getCompilationUnit();
222 } 194 }
223 195
224 public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) { 196 private Map<String, ClassNode> deobfuscateClasses(ProgressListener progress, Collection<ClassEntry> classEntries, Translator translator) {
225 return getSourceIndex(sourceTree, source, true); 197 AtomicInteger count = new AtomicInteger();
226 } 198 if (progress != null) {
227 199 progress.init(classEntries.size(), "Deobfuscating classes...");
228 public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source, boolean ignoreBadTokens) {
229
230 // build the source index
231 SourceIndex index = new SourceIndex(source, ignoreBadTokens);
232 sourceTree.acceptVisitor(new SourceIndexVisitor(entryPool), index);
233
234 EntryResolver resolver = mapper.getDeobfResolver();
235
236 Collection<Token> tokens = Lists.newArrayList(index.referenceTokens());
237
238 // resolve all the classes in the source references
239 for (Token token : tokens) {
240 EntryReference<Entry<?>, Entry<?>> deobfReference = index.getDeobfReference(token);
241 index.replaceDeobfReference(token, resolver.resolveFirstReference(deobfReference, ResolutionStrategy.RESOLVE_CLOSEST));
242 } 200 }
243 201
244 return index; 202 return classEntries.parallelStream()
245 } 203 .map(entry -> {
204 ClassEntry translatedEntry = translator.translate(entry);
205 if (progress != null) {
206 progress.step(count.getAndIncrement(), translatedEntry.toString());
207 }
208
209 ClassNode node = parsedJar.getClassNode(entry.getFullName());
210 if (node != null) {
211 ClassNode translatedNode = new ClassNode();
212 node.accept(new TranslationClassVisitor(translator, Opcodes.ASM5, translatedNode));
213 return translatedNode;
214 }
246 215
247 public String getSource(CompilationUnit sourceTree) { 216 return null;
248 // render the AST into source 217 })
249 StringWriter buf = new StringWriter(); 218 .filter(Objects::nonNull)
250 sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); 219 .collect(Collectors.toMap(n -> n.name, Functions.identity()));
251 sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), this.settings), null);
252 return buf.toString();
253 } 220 }
254 221
255 public void writeSources(File dirOut, ProgressListener progress) { 222 private void decompileClasses(Path outputDirectory, ProgressListener progress, Map<String, ClassNode> translatedClasses) {
256 // get the classes to decompile 223 Collection<ClassNode> decompileClasses = translatedClasses.values().stream()
257 Set<ClassEntry> classEntries = jarIndex.getEntryIndex().getClasses().stream() 224 .filter(classNode -> classNode.name.indexOf('$') == -1)
258 .filter(classEntry -> !classEntry.isInnerClass()) 225 .collect(Collectors.toList());
259 .collect(Collectors.toSet());
260 226
261 if (progress != null) { 227 if (progress != null) {
262 progress.init(classEntries.size(), "Decompiling classes..."); 228 progress.init(decompileClasses.size(), "Decompiling classes...");
263 } 229 }
264 230
265 //create a common instance outside the loop as mappings shouldn't be changing while this is happening 231 //create a common instance outside the loop as mappings shouldn't be changing while this is happening
266 //synchronized to make sure the parallelStream doesn't CME with the cache 232 //synchronized to make sure the parallelStream doesn't CME with the cache
267 ITranslatingTypeLoader typeLoader = new SynchronizedTypeLoader(createTypeLoader()); 233 ITypeLoader typeLoader = new SynchronizedTypeLoader(new CompiledSourceTypeLoader(translatedClasses::get));
268 234
269 MetadataSystem metadataSystem = new NoRetryMetadataSystem(typeLoader); 235 MetadataSystem metadataSystem = new Deobfuscator.NoRetryMetadataSystem(typeLoader);
270 metadataSystem.setEagerMethodLoadingEnabled(true);//ensures methods are loaded on classload and prevents race conditions 236
237 //ensures methods are loaded on classload and prevents race conditions
238 metadataSystem.setEagerMethodLoadingEnabled(true);
239
240 DecompilerSettings settings = SourceProvider.createSettings();
241 SourceProvider sourceProvider = new SourceProvider(settings, typeLoader, metadataSystem);
271 242
272 // DEOBFUSCATE ALL THE THINGS!! @_@
273 Stopwatch stopwatch = Stopwatch.createStarted();
274 AtomicInteger count = new AtomicInteger(); 243 AtomicInteger count = new AtomicInteger();
275 classEntries.parallelStream().forEach(obfClassEntry -> { 244
276 ClassEntry deobfClassEntry = mapper.deobfuscate(obfClassEntry); 245 decompileClasses.parallelStream().forEach(translatedNode -> {
277 if (progress != null) { 246 if (progress != null) {
278 progress.step(count.getAndIncrement(), deobfClassEntry.toString()); 247 progress.step(count.getAndIncrement(), translatedNode.name);
279 } 248 }
280 249
281 try { 250 decompileClass(outputDirectory, translatedNode, sourceProvider);
282 // get the source 251 });
283 CompilationUnit sourceTree = getSourceTree(obfClassEntry.getName(), typeLoader, metadataSystem); 252 }
284 253
285 // write the file 254 private void decompileClass(Path outputDirectory, ClassNode translatedNode, SourceProvider sourceProvider) {
286 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); 255 try {
287 file.getParentFile().mkdirs(); 256 // get the source
288 try (Writer writer = new BufferedWriter(new FileWriter(file))) { 257 CompilationUnit sourceTree = sourceProvider.getSources(translatedNode.name);
289 sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); 258
290 sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null); 259 Path path = outputDirectory.resolve(translatedNode.name.replace('.', '/') + ".java");
291 } 260 Files.createDirectories(path.getParent());
292 } catch (Throwable t) { 261
293 // don't crash the whole world here, just log the error and keep going 262 try (Writer writer = Files.newBufferedWriter(path)) {
294 // TODO: set up logback via log4j 263 sourceProvider.writeSource(writer, sourceTree);
295 System.err.println("Unable to decompile class " + deobfClassEntry + " (" + obfClassEntry + ")");
296 t.printStackTrace(System.err);
297 } 264 }
298 }); 265 } catch (Throwable t) {
299 stopwatch.stop(); 266 // don't crash the whole world here, just log the error and keep going
300 System.out.println("writeSources Done in : " + stopwatch.toString()); 267 // TODO: set up logback via log4j
301 if (progress != null) { 268 System.err.println("Unable to decompile class " + translatedNode.name);
302 progress.step(count.get(), "Done:"); 269 t.printStackTrace(System.err);
303 } 270 }
304 } 271 }
305 272
306 public void writeJar(File out, ProgressListener progress) { 273 public void writeTransformedJar(File out, ProgressListener progress) {
307 transformJar(out, progress, createTypeLoader()::transformInto); 274 Translator deobfuscator = mapper.getDeobfuscator();
275 writeTransformedJar(out, progress, (node, visitor) -> {
276 ClassEntry entry = new ClassEntry(node.name);
277 node.accept(new TranslationClassVisitor(deobfuscator, Opcodes.ASM5, visitor));
278 return deobfuscator.translate(entry).getFullName();
279 });
308 } 280 }
309 281
310 public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { 282 public void writeTransformedJar(File out, ProgressListener progress, ClassTransformer transformer) {
311 try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { 283 try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) {
312 if (progress != null) { 284 if (progress != null) {
313 progress.init(parsedJar.getClassCount(), "Transforming classes..."); 285 progress.init(parsedJar.getClassCount(), "Transforming classes...");
314 } 286 }
315 287
316 AtomicInteger i = new AtomicInteger(); 288 AtomicInteger count = new AtomicInteger();
317 parsedJar.visitNode(node -> { 289 parsedJar.visitNode(node -> {
318 if (progress != null) { 290 if (progress != null) {
319 progress.step(i.getAndIncrement(), node.name); 291 progress.step(count.getAndIncrement(), node.name);
320 } 292 }
321 293
322 try { 294 try {
@@ -329,10 +301,6 @@ public class Deobfuscator {
329 throw new Error("Unable to transform class " + node.name, t); 301 throw new Error("Unable to transform class " + node.name, t);
330 } 302 }
331 }); 303 });
332
333 if (progress != null) {
334 progress.step(i.get(), "Done!");
335 }
336 } catch (IOException ex) { 304 } catch (IOException ex) {
337 throw new Error("Unable to write to Jar file!"); 305 throw new Error("Unable to write to Jar file!");
338 } 306 }
@@ -355,7 +323,7 @@ public class Deobfuscator {
355 } 323 }
356 } 324 }
357 325
358 public boolean isObfuscatedIdentifier(Entry<?> obfEntry) { 326 public boolean isRenamable(Entry<?> obfEntry) {
359 if (obfEntry instanceof MethodEntry) { 327 if (obfEntry instanceof MethodEntry) {
360 // HACKHACK: Object methods are not obfuscated identifiers 328 // HACKHACK: Object methods are not obfuscated identifiers
361 MethodEntry obfMethodEntry = (MethodEntry) obfEntry; 329 MethodEntry obfMethodEntry = (MethodEntry) obfEntry;
@@ -389,12 +357,15 @@ public class Deobfuscator {
389 return this.jarIndex.getEntryIndex().hasEntry(obfEntry); 357 return this.jarIndex.getEntryIndex().hasEntry(obfEntry);
390 } 358 }
391 359
392 public boolean isRenameable(EntryReference<Entry<?>, Entry<?>> obfReference) { 360 public boolean isRenamable(EntryReference<Entry<?>, Entry<?>> obfReference) {
393 return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry()); 361 return obfReference.isNamed() && isRenamable(obfReference.getNameableEntry());
394 } 362 }
395 363
396 public boolean hasDeobfuscatedName(Entry<?> obfEntry) { 364 public boolean isRemapped(Entry<?> entry) {
397 return mapper.hasDeobfMapping(obfEntry); 365 EntryResolver resolver = mapper.getObfResolver();
366 DeltaTrackingTree<EntryMapping> mappings = mapper.getObfToDeobf();
367 return resolver.resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT).stream()
368 .anyMatch(mappings::contains);
398 } 369 }
399 370
400 public void rename(Entry<?> obfEntry, String newName) { 371 public void rename(Entry<?> obfEntry, String newName) {
@@ -409,21 +380,12 @@ public class Deobfuscator {
409 mapper.mapFromObf(obfEntry, new EntryMapping(mapper.deobfuscate(obfEntry).getName())); 380 mapper.mapFromObf(obfEntry, new EntryMapping(mapper.deobfuscate(obfEntry).getName()));
410 } 381 }
411 382
412 public static void runCustomTransforms(AstBuilder builder, DecompilerContext context) { 383 public <T extends Translatable> T deobfuscate(T translatable) {
413 List<IAstTransform> transformers = Arrays.asList( 384 return mapper.deobfuscate(translatable);
414 new ObfuscatedEnumSwitchRewriterTransform(context),
415 new VarargsFixer(context),
416 new RemoveObjectCasts(context),
417 new Java8Generics(),
418 new InvalidIdentifierFix()
419 );
420 for (IAstTransform transform : transformers) {
421 transform.run(builder.getCompilationUnit());
422 }
423 } 385 }
424 386
425 public interface ClassTransformer { 387 public interface ClassTransformer {
426 String transform(ClassNode node, ClassWriter writer); 388 String transform(ClassNode node, ClassVisitor visitor);
427 } 389 }
428 390
429 public static class NoRetryMetadataSystem extends MetadataSystem { 391 public static class NoRetryMetadataSystem extends MetadataSystem {
@@ -448,6 +410,7 @@ public class Deobfuscator {
448 return result; 410 return result;
449 } 411 }
450 412
413 @Override
451 public synchronized TypeDefinition resolve(final TypeReference type) { 414 public synchronized TypeDefinition resolve(final TypeReference type) {
452 return super.resolve(type); 415 return super.resolve(type);
453 } 416 }