diff --git a/jadx-core/src/main/java/jadx/api/JavaClass.java b/jadx-core/src/main/java/jadx/api/JavaClass.java index e6355a66280504a1a85c1ca5bf984699b39e240a..30f521f569cca023197092b62bafc4089a9ef7a0 100644 --- a/jadx-core/src/main/java/jadx/api/JavaClass.java +++ b/jadx-core/src/main/java/jadx/api/JavaClass.java @@ -201,9 +201,25 @@ public final class JavaClass implements JavaNode { @Override public JavaClass getTopParentClass() { + if (cls.contains(AFlag.ANONYMOUS_CLASS)) { + // moved to usage class + return getParentForAnonymousClass(); + } return parent == null ? this : parent.getTopParentClass(); } + private JavaClass getParentForAnonymousClass() { + List useIn = getUseIn(); + if (useIn.isEmpty()) { + return this; + } + JavaNode useNode = useIn.get(0); + if (useNode.equals(this)) { + return this; + } + return useNode.getTopParentClass(); + } + public AccessInfo getAccessInfo() { return cls.getAccessFlags(); } diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/DbgUtils.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/DbgUtils.java index 982b0f6adb0bee4cb3ad731a66bb68fae652ec5a..37d94ffd816e6d07ca7ffacc47f717c7a97fe7a1 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/DbgUtils.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/DbgUtils.java @@ -90,7 +90,7 @@ public class DbgUtils { clsSig = DbgUtils.classSigToFullName(clsSig); JavaClass cls = mainWindow.getWrapper().getDecompiler().searchJavaClassOrItsParentByOrigFullName(clsSig); if (cls != null) { - JClass jc = (JClass) mainWindow.getCacheObject().getNodeCache().makeFrom(cls); + JClass jc = mainWindow.getCacheObject().getNodeCache().makeFrom(cls); return jc.getRootClass(); } return null; diff --git a/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java b/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java index c6d1090b8688a1009078827ab959e5c6794f0698..dbadbdcadebfc85d8fa052b9794a813388f712e1 100644 --- a/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java +++ b/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java @@ -129,7 +129,7 @@ public class BackgroundExecutor { return cancelStatus; } setProgress(calcProgress(executor.getCompletedTaskCount())); - Thread.sleep(500); + Thread.sleep(300); } } catch (InterruptedException e) { LOG.debug("Task wait interrupted"); diff --git a/jadx-gui/src/main/java/jadx/gui/jobs/DecompileTask.java b/jadx-gui/src/main/java/jadx/gui/jobs/DecompileTask.java index 3a058bce0fbad6e454e96fa6082fe7dbbdc40426..ee8d4ab344d4c2194edf3270c9e9b2be22821df6 100644 --- a/jadx-gui/src/main/java/jadx/gui/jobs/DecompileTask.java +++ b/jadx-gui/src/main/java/jadx/gui/jobs/DecompileTask.java @@ -3,6 +3,7 @@ package jadx.gui.jobs; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import javax.swing.JOptionPane; @@ -42,15 +43,18 @@ public class DecompileTask implements IBackgroundTask { @Override public List scheduleJobs() { - List classes = wrapper.getIncludedClasses(); - expectedCompleteCount = classes.size(); - IndexService indexService = mainWindow.getCacheObject().getIndexService(); + List classesForIndex = wrapper.getIncludedClasses() + .stream() + .filter(indexService::isIndexNeeded) + .collect(Collectors.toList()); + expectedCompleteCount = classesForIndex.size(); + indexService.setComplete(false); complete.set(0); List jobs = new ArrayList<>(expectedCompleteCount + 1); - for (JavaClass cls : classes) { + for (JavaClass cls : classesForIndex) { jobs.add(() -> { cls.decompile(); indexService.indexCls(cls); diff --git a/jadx-gui/src/main/java/jadx/gui/jobs/IndexService.java b/jadx-gui/src/main/java/jadx/gui/jobs/IndexService.java index 3a538bf8a1288fd7877c94ba971be5dcc8406d92..62adac0afe578212f36f2e5ad9cad657c384f64f 100644 --- a/jadx-gui/src/main/java/jadx/gui/jobs/IndexService.java +++ b/jadx-gui/src/main/java/jadx/gui/jobs/IndexService.java @@ -1,6 +1,8 @@ package jadx.gui.jobs; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -20,6 +22,7 @@ public class IndexService { private final CacheObject cache; private boolean indexComplete; + private final Set indexSet = new HashSet<>(); public IndexService(CacheObject cache) { this.cache = cache; @@ -40,6 +43,7 @@ public class IndexService { usageInfo.processClass(cls, linesInfo, lines); index.indexCode(cls, linesInfo, lines); + indexSet.add(cls); } catch (Exception e) { LOG.error("Index error in class: {}", cls.getFullName(), e); } @@ -56,11 +60,16 @@ public class IndexService { if (index == null || usageInfo == null) { return; } + indexSet.remove(cls); index.remove(cls); usageInfo.remove(cls); indexCls(cls); } + public boolean isIndexNeeded(JavaClass cls) { + return !indexSet.contains(cls); + } + @NotNull protected static List splitLines(JavaClass cls) { List lines = StringRef.split(cls.getCode(), ICodeWriter.NL); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 36354c34b99bc22f55dd6d8b7469b9d67ba87567..5abaa67787ae9d4fbd999c10e953d1ebb5334956 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -519,6 +519,9 @@ public class MainWindow extends JFrame { public void waitDecompileTask() { synchronized (DECOMPILER_TASK_SYNC) { + if (cacheObject.getIndexService().isComplete()) { + return; + } try { DecompileTask decompileTask = new DecompileTask(this, wrapper); Future task = backgroundExecutor.execute(decompileTask); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/CommonSearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/CommonSearchDialog.java index b1e6d35f2e07cf5e02737e62c5f2c42b1df9a73f..d3baaee138ac22c68769433b645b6bc026eaa944 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/CommonSearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/CommonSearchDialog.java @@ -547,14 +547,14 @@ public abstract class CommonSearchDialog extends JDialog { } } - private void loadStartCommon() { + void loadStartCommon() { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); progressPane.setIndeterminate(true); progressPane.setVisible(true); warnLabel.setVisible(false); } - private void loadFinishedCommon() { + void loadFinishedCommon() { setCursor(null); progressPane.setVisible(false); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java index ca4d5caf55deba156491eba005fd5e52e1672869..7da37d8dcbd90012982e7ce04e0493ec122dfd64 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java @@ -3,6 +3,9 @@ package jadx.gui.ui.dialog; import java.awt.BorderLayout; import java.awt.Container; import java.awt.FlowLayout; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; import javax.swing.BorderFactory; import javax.swing.JLabel; @@ -10,10 +13,15 @@ import javax.swing.JPanel; import javax.swing.SwingConstants; import javax.swing.WindowConstants; +import jadx.api.JavaClass; +import jadx.api.JavaNode; +import jadx.gui.jobs.IndexService; +import jadx.gui.jobs.TaskStatus; import jadx.gui.treemodel.JNode; import jadx.gui.ui.MainWindow; import jadx.gui.utils.CodeUsageInfo; import jadx.gui.utils.NLS; +import jadx.gui.utils.UiUtils; public class UsageDialog extends CommonSearchDialog { @@ -32,7 +40,40 @@ public class UsageDialog extends CommonSearchDialog { @Override protected void openInit() { - prepare(); + IndexService indexService = mainWindow.getCacheObject().getIndexService(); + if (indexService.isComplete()) { + loadFinishedCommon(); + loadFinished(); + return; + } + List useIn = node.getJavaNode().getUseIn(); + List usageTopClsForIndex = useIn + .stream() + .map(JavaNode::getTopParentClass) + .filter(indexService::isIndexNeeded) + .distinct() + .sorted(Comparator.comparing(JavaClass::getFullName)) + .collect(Collectors.toList()); + if (usageTopClsForIndex.isEmpty()) { + loadFinishedCommon(); + loadFinished(); + return; + } + mainWindow.getBackgroundExecutor().execute(NLS.str("progress.load"), + () -> { + for (JavaClass cls : usageTopClsForIndex) { + cls.decompile(); + indexService.indexCls(cls); + } + }, + (status) -> { + if (status == TaskStatus.CANCEL_BY_MEMORY) { + mainWindow.showHeapUsageBar(); + UiUtils.errorMessage(this, NLS.str("message.memoryLow")); + } + loadFinishedCommon(); + loadFinished(); + }); } @Override diff --git a/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java b/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java index 85e54c12e3afde56120f58fa7e6484f150ac9789..a54bd71477c61190a024e5ba579a974703015005 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java @@ -31,25 +31,29 @@ public class JNodeCache { return jNode; } + public JClass makeFrom(JavaClass javaCls) { + if (javaCls == null) { + return null; + } + return (JClass) cache.computeIfAbsent(javaCls, + jn -> new JClass(javaCls, makeFrom(javaCls.getDeclaringClass()))); + } + private JNode convert(JavaNode node) { if (node == null) { return null; } if (node instanceof JavaClass) { - JClass p = (JClass) makeFrom(node.getDeclaringClass()); - return new JClass((JavaClass) node, p); + return new JClass((JavaClass) node, makeFrom(node.getDeclaringClass())); } if (node instanceof JavaMethod) { - JavaMethod mth = (JavaMethod) node; - return new JMethod(mth, (JClass) makeFrom(mth.getDeclaringClass())); + return new JMethod((JavaMethod) node, makeFrom(node.getDeclaringClass())); } if (node instanceof JavaField) { - JavaField fld = (JavaField) node; - return new JField(fld, (JClass) makeFrom(fld.getDeclaringClass())); + return new JField((JavaField) node, makeFrom(node.getDeclaringClass())); } if (node instanceof JavaVariable) { - JavaVariable var = (JavaVariable) node; - return new JVariable(var, (JClass) makeFrom(var.getDeclaringClass())); + return new JVariable((JavaVariable) node, makeFrom(node.getDeclaringClass())); } throw new JadxRuntimeException("Unknown type for JavaNode: " + node.getClass()); }