summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/gui/GuiController.java
diff options
context:
space:
mode:
authorGravatar Runemoro2020-03-09 06:04:08 -0400
committerGravatar GitHub2020-03-09 10:04:08 +0000
commit58c0aeb15a65324de08a914dfa62cc68a516a4e3 (patch)
treef45e8141c0864692051149a478c5a0a6bbe68686 /src/main/java/cuchaz/enigma/gui/GuiController.java
parentMade Enigma gui translatable (#193) (diff)
downloadenigma-fork-58c0aeb15a65324de08a914dfa62cc68a516a4e3.tar.gz
enigma-fork-58c0aeb15a65324de08a914dfa62cc68a516a4e3.tar.xz
enigma-fork-58c0aeb15a65324de08a914dfa62cc68a516a4e3.zip
CFR support (#192)
* Add decompiler API * Add CFR support
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/GuiController.java')
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java87
1 files changed, 54 insertions, 33 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index dc5010c..25a1057 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -13,8 +13,9 @@ package cuchaz.enigma.gui;
13 13
14import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
15import com.google.common.util.concurrent.ThreadFactoryBuilder; 15import com.google.common.util.concurrent.ThreadFactoryBuilder;
16import com.strobel.decompiler.languages.java.ast.CompilationUnit; 16import cuchaz.enigma.Enigma;
17import cuchaz.enigma.*; 17import cuchaz.enigma.EnigmaProfile;
18import cuchaz.enigma.EnigmaProject;
18import cuchaz.enigma.analysis.*; 19import cuchaz.enigma.analysis.*;
19import cuchaz.enigma.api.service.ObfuscationTestService; 20import cuchaz.enigma.api.service.ObfuscationTestService;
20import cuchaz.enigma.bytecode.translators.SourceFixVisitor; 21import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
@@ -23,6 +24,7 @@ import cuchaz.enigma.gui.dialog.ProgressDialog;
23import cuchaz.enigma.gui.stats.StatsGenerator; 24import cuchaz.enigma.gui.stats.StatsGenerator;
24import cuchaz.enigma.gui.stats.StatsMember; 25import cuchaz.enigma.gui.stats.StatsMember;
25import cuchaz.enigma.gui.util.History; 26import cuchaz.enigma.gui.util.History;
27import cuchaz.enigma.source.*;
26import cuchaz.enigma.throwables.MappingParseException; 28import cuchaz.enigma.throwables.MappingParseException;
27import cuchaz.enigma.translation.Translator; 29import cuchaz.enigma.translation.Translator;
28import cuchaz.enigma.translation.mapping.*; 30import cuchaz.enigma.translation.mapping.*;
@@ -36,16 +38,16 @@ import cuchaz.enigma.utils.I18n;
36import cuchaz.enigma.utils.ReadableToken; 38import cuchaz.enigma.utils.ReadableToken;
37import cuchaz.enigma.utils.Utils; 39import cuchaz.enigma.utils.Utils;
38import org.objectweb.asm.Opcodes; 40import org.objectweb.asm.Opcodes;
41import org.objectweb.asm.tree.ClassNode;
39 42
40import javax.annotation.Nullable; 43import javax.annotation.Nullable;
41import javax.swing.*; 44import javax.swing.JOptionPane;
42import java.awt.*; 45import java.awt.Desktop;
43import java.awt.event.ItemEvent; 46import java.awt.event.ItemEvent;
44import java.io.*; 47import java.io.*;
45import java.nio.file.Path; 48import java.nio.file.Path;
46import java.util.Collection; 49import java.util.Collection;
47import java.util.List; 50import java.util.List;
48import java.util.Optional;
49import java.util.Set; 51import java.util.Set;
50import java.util.concurrent.CompletableFuture; 52import java.util.concurrent.CompletableFuture;
51import java.util.concurrent.ExecutorService; 53import java.util.concurrent.ExecutorService;
@@ -65,19 +67,23 @@ public class GuiController {
65 public final Enigma enigma; 67 public final Enigma enigma;
66 68
67 public EnigmaProject project; 69 public EnigmaProject project;
68 private SourceProvider sourceProvider; 70 private DecompilerService decompilerService;
71 private Decompiler decompiler;
69 private IndexTreeBuilder indexTreeBuilder; 72 private IndexTreeBuilder indexTreeBuilder;
70 73
71 private Path loadedMappingPath; 74 private Path loadedMappingPath;
72 private MappingFormat loadedMappingFormat; 75 private MappingFormat loadedMappingFormat;
73 76
74 private DecompiledClassSource currentSource; 77 private DecompiledClassSource currentSource;
78 private Source uncommentedSource;
75 79
76 public GuiController(Gui gui, EnigmaProfile profile) { 80 public GuiController(Gui gui, EnigmaProfile profile) {
77 this.gui = gui; 81 this.gui = gui;
78 this.enigma = Enigma.builder() 82 this.enigma = Enigma.builder()
79 .setProfile(profile) 83 .setProfile(profile)
80 .build(); 84 .build();
85
86 decompilerService = Config.getInstance().decompiler.service;
81 } 87 }
82 88
83 public boolean isDirty() { 89 public boolean isDirty() {
@@ -89,19 +95,27 @@ public class GuiController {
89 95
90 return ProgressDialog.runOffThread(gui.getFrame(), progress -> { 96 return ProgressDialog.runOffThread(gui.getFrame(), progress -> {
91 project = enigma.openJar(jarPath, progress); 97 project = enigma.openJar(jarPath, progress);
92
93 indexTreeBuilder = new IndexTreeBuilder(project.getJarIndex()); 98 indexTreeBuilder = new IndexTreeBuilder(project.getJarIndex());
94 99 decompiler = createDecompiler();
95 CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(project.getClassCache());
96 typeLoader.addVisitor(visitor -> new SourceFixVisitor(Opcodes.ASM5, visitor, project.getJarIndex()));
97 sourceProvider = new SourceProvider(SourceProvider.createSettings(), typeLoader);
98
99 gui.onFinishOpenJar(jarPath.getFileName().toString()); 100 gui.onFinishOpenJar(jarPath.getFileName().toString());
100
101 refreshClasses(); 101 refreshClasses();
102 }); 102 });
103 } 103 }
104 104
105 private Decompiler createDecompiler() {
106 return decompilerService.create(name -> {
107 ClassNode node = project.getClassCache().getClassNode(name);
108
109 if (node == null) {
110 return null;
111 }
112
113 ClassNode fixedNode = new ClassNode();
114 node.accept(new SourceFixVisitor(Opcodes.ASM7, fixedNode, project.getJarIndex()));
115 return fixedNode;
116 }, new SourceSettings(true, true));
117 }
118
105 public void closeJar() { 119 public void closeJar() {
106 this.project = null; 120 this.project = null;
107 this.gui.onCloseJar(); 121 this.gui.onCloseJar();
@@ -176,7 +190,7 @@ public class GuiController {
176 190
177 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { 191 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> {
178 EnigmaProject.JarExport jar = project.exportRemappedJar(progress); 192 EnigmaProject.JarExport jar = project.exportRemappedJar(progress);
179 EnigmaProject.SourceExport source = jar.decompile(progress); 193 EnigmaProject.SourceExport source = jar.decompile(progress, decompilerService);
180 194
181 source.write(path, progress); 195 source.write(path, progress);
182 }); 196 });
@@ -210,6 +224,7 @@ public class GuiController {
210 if (this.currentSource == null) { 224 if (this.currentSource == null) {
211 return null; 225 return null;
212 } 226 }
227
213 SourceIndex index = this.currentSource.getIndex(); 228 SourceIndex index = this.currentSource.getIndex();
214 return new ReadableToken( 229 return new ReadableToken(
215 index.getLineNumber(token.start), 230 index.getLineNumber(token.start),
@@ -369,27 +384,27 @@ public class GuiController {
369 } 384 }
370 385
371 private void refreshCurrentClass(EntryReference<Entry<?>, Entry<?>> reference) { 386 private void refreshCurrentClass(EntryReference<Entry<?>, Entry<?>> reference) {
372 refreshCurrentClass(reference, false); 387 refreshCurrentClass(reference, RefreshMode.MINIMAL);
373 } 388 }
374 389
375 private void refreshCurrentClass(EntryReference<Entry<?>, Entry<?>> reference, boolean forceDecomp) { 390 private void refreshCurrentClass(EntryReference<Entry<?>, Entry<?>> reference, RefreshMode mode) {
376 if (currentSource != null) { 391 if (currentSource != null) {
377 loadClass(currentSource.getEntry(), () -> { 392 loadClass(currentSource.getEntry(), () -> {
378 if (reference != null) { 393 if (reference != null) {
379 showReference(reference); 394 showReference(reference);
380 } 395 }
381 }, forceDecomp); 396 }, mode);
382 } 397 }
383 } 398 }
384 399
385 private void loadClass(ClassEntry classEntry, Runnable callback) { 400 private void loadClass(ClassEntry classEntry, Runnable callback) {
386 loadClass(classEntry, callback, false); 401 loadClass(classEntry, callback, RefreshMode.MINIMAL);
387 } 402 }
388 403
389 private void loadClass(ClassEntry classEntry, Runnable callback, boolean forceDecomp) { 404 private void loadClass(ClassEntry classEntry, Runnable callback, RefreshMode mode) {
390 ClassEntry targetClass = classEntry.getOutermostClass(); 405 ClassEntry targetClass = classEntry.getOutermostClass();
391 406
392 boolean requiresDecompile = forceDecomp || currentSource == null || !currentSource.getEntry().equals(targetClass); 407 boolean requiresDecompile = mode == RefreshMode.FULL || currentSource == null || !currentSource.getEntry().equals(targetClass);
393 if (requiresDecompile) { 408 if (requiresDecompile) {
394 currentSource = null; // Or the GUI may try to find a nonexistent token 409 currentSource = null; // Or the GUI may try to find a nonexistent token
395 gui.setEditorText(I18n.translate("info_panel.editor.class.decompiling")); 410 gui.setEditorText(I18n.translate("info_panel.editor.class.decompiling"));
@@ -397,8 +412,8 @@ public class GuiController {
397 412
398 DECOMPILER_SERVICE.submit(() -> { 413 DECOMPILER_SERVICE.submit(() -> {
399 try { 414 try {
400 if (requiresDecompile) { 415 if (requiresDecompile || mode == RefreshMode.JAVADOCS) {
401 currentSource = decompileSource(targetClass); 416 currentSource = decompileSource(targetClass, mode == RefreshMode.JAVADOCS);
402 } 417 }
403 418
404 remapSource(project.getMapper().getDeobfuscator()); 419 remapSource(project.getMapper().getDeobfuscator());
@@ -410,21 +425,20 @@ public class GuiController {
410 }); 425 });
411 } 426 }
412 427
413 private DecompiledClassSource decompileSource(ClassEntry targetClass) { 428 private DecompiledClassSource decompileSource(ClassEntry targetClass, boolean onlyRefreshJavadocs) {
414 try { 429 try {
415 CompilationUnit sourceTree = (CompilationUnit) sourceProvider.getSources(targetClass.getFullName()).clone(); 430 if (!onlyRefreshJavadocs || currentSource == null || !currentSource.getEntry().equals(targetClass)) {
416 if (sourceTree == null) { 431 uncommentedSource = decompiler.getSource(targetClass.getFullName());
417 gui.setEditorText(I18n.translate("info_panel.editor.class.not_found") + " " + targetClass);
418 return DecompiledClassSource.text(targetClass, "Unable to find class");
419 } 432 }
420 433
421 DropImportAstTransform.INSTANCE.run(sourceTree); 434 Source source = uncommentedSource.addJavadocs(project.getMapper());
422 DropVarModifiersAstTransform.INSTANCE.run(sourceTree);
423 new AddJavadocsAstTransform(project.getMapper()).run(sourceTree);
424 435
425 String sourceString = sourceProvider.writeSourceToString(sourceTree); 436 if (source == null) {
437 gui.setEditorText(I18n.translate("info_panel.editor.class.not_found") + " " + targetClass);
438 return DecompiledClassSource.text(targetClass, "Unable to find class");
439 }
426 440
427 SourceIndex index = SourceIndex.buildIndex(sourceString, sourceTree, true); 441 SourceIndex index = source.index();
428 index.resolveReferences(project.getMapper().getObfResolver()); 442 index.resolveReferences(project.getMapper().getObfResolver());
429 443
430 return new DecompiledClassSource(targetClass, index); 444 return new DecompiledClassSource(targetClass, index);
@@ -535,7 +549,7 @@ public class GuiController {
535 public void changeDocs(EntryReference<Entry<?>, Entry<?>> reference, String updatedDocs) { 549 public void changeDocs(EntryReference<Entry<?>, Entry<?>> reference, String updatedDocs) {
536 changeDoc(reference.getNameableEntry(), updatedDocs); 550 changeDoc(reference.getNameableEntry(), updatedDocs);
537 551
538 refreshCurrentClass(reference, true); 552 refreshCurrentClass(reference, RefreshMode.JAVADOCS);
539 } 553 }
540 554
541 public void changeDoc(Entry<?> obfEntry, String newDoc) { 555 public void changeDoc(Entry<?> obfEntry, String newDoc) {
@@ -582,4 +596,11 @@ public class GuiController {
582 } 596 }
583 }); 597 });
584 } 598 }
599
600 public void setDecompiler(DecompilerService service) {
601 uncommentedSource = null;
602 decompilerService = service;
603 decompiler = createDecompiler();
604 refreshCurrentClass(null, RefreshMode.FULL);
605 }
585} 606}