diff --git a/jadx-core/src/main/java/jadx/core/Consts.java b/jadx-core/src/main/java/jadx/core/Consts.java index 32b98286c2c..db6154ee3f8 100644 --- a/jadx-core/src/main/java/jadx/core/Consts.java +++ b/jadx-core/src/main/java/jadx/core/Consts.java @@ -9,6 +9,7 @@ public class Consts { public static final boolean DEBUG_EXC_HANDLERS = false; public static final boolean DEBUG_FINALLY = false; public static final boolean DEBUG_ATTRIBUTES = false; + public static final boolean DEBUG_RESTRUCTURE = false; public static final boolean DEBUG_EVENTS = true; public static final String CLASS_OBJECT = "java.lang.Object"; diff --git a/jadx-core/src/main/java/jadx/core/ProcessClass.java b/jadx-core/src/main/java/jadx/core/ProcessClass.java index 762f19a762b..0394b1db3b4 100644 --- a/jadx-core/src/main/java/jadx/core/ProcessClass.java +++ b/jadx-core/src/main/java/jadx/core/ProcessClass.java @@ -9,6 +9,7 @@ import jadx.api.ICodeInfo; import jadx.api.JadxArgs; +import jadx.api.impl.SimpleCodeInfo; import jadx.core.codegen.CodeGen; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.nodes.ClassNode; @@ -27,6 +28,8 @@ public class ProcessClass { private static final Logger LOG = LoggerFactory.getLogger(ProcessClass.class); + private static final ICodeInfo NOT_GENERATED = new SimpleCodeInfo(""); + private final List passes; public ProcessClass(JadxArgs args) { @@ -101,7 +104,8 @@ public ICodeInfo generateCode(ClassNode cls) { try { if (cls.contains(AFlag.DONT_GENERATE)) { process(cls, false); - return ICodeInfo.EMPTY; + LOG.warn("Requested code for class with DONT_GENERATE flag: {}", cls); + return NOT_GENERATED; } for (ClassNode depCls : cls.getDependencies()) { process(depCls, false); diff --git a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java index ff06caa24b2..a9d94344a43 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java @@ -106,6 +106,10 @@ public String getFullName() { return declClass.getFullName() + '.' + name; } + public String getAliasFullName() { + return declClass.getAliasFullName() + '.' + alias; + } + public String getFullId() { return declClass.getFullName() + '.' + shortId; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index e4294eaef8c..a0aff4b5ff2 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -13,6 +13,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import jadx.api.DecompilationMode; import jadx.api.ICodeCache; @@ -56,6 +58,8 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeNode, IPackageUpdate, Comparable { + private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class); + private final RootNode root; private final IClassData clsData; @@ -381,6 +385,9 @@ private synchronized ICodeInfo decompile(boolean searchInCache) { } ICodeInfo codeInfo; try { + if (Consts.DEBUG) { + LOG.debug("Decompiling class: {}", this); + } codeInfo = root.getProcessClasses().generateCode(this); } catch (Throwable e) { addError("Code generation failed", e); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java index ec7c6143b3d..a4b5ed5508b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java @@ -8,6 +8,7 @@ import jadx.api.ICodeWriter; import jadx.api.impl.SimpleCodeWriter; +import jadx.core.Consts; import jadx.core.codegen.InsnGen; import jadx.core.codegen.MethodGen; import jadx.core.dex.attributes.AFlag; @@ -46,7 +47,8 @@ public void processBlock(MethodNode mth, IBlock container) { if (blocksInRegions.add(block)) { return; } - if (LOG.isDebugEnabled() + if (Consts.DEBUG_RESTRUCTURE + && LOG.isDebugEnabled() && !block.contains(AFlag.RETURN) && !block.contains(AFlag.REMOVE) && !block.contains(AFlag.SYNTHETIC) diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java index 890eabe777f..cc7617be9c7 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java @@ -9,6 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jadx.core.Consts; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.LoopInfo; @@ -74,7 +75,9 @@ static IfInfo restructureIf(MethodNode mth, BlockNode block, IfInfo info) { boolean badThen = isBadBranchBlock(info, thenBlock); boolean badElse = isBadBranchBlock(info, elseBlock); if (badThen && badElse) { - LOG.debug("Stop processing blocks after 'if': {}, method: {}", info.getMergedBlocks(), mth); + if (Consts.DEBUG_RESTRUCTURE) { + LOG.debug("Stop processing blocks after 'if': {}, method: {}", info.getMergedBlocks(), mth); + } return null; } if (badElse) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java index 065d400e74f..7a62c2bb999 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java @@ -182,7 +182,7 @@ private void setImmutableType(MethodNode mth, SSAVar ssaVar) { } catch (JadxOverflowException e) { throw e; } catch (Exception e) { - LOG.error("Failed to set immutable type for var: {}", ssaVar, e); + mth.addWarnComment("Failed to set immutable type for var: " + ssaVar, e); } } @@ -192,7 +192,7 @@ private boolean setBestType(MethodNode mth, SSAVar ssaVar) { } catch (JadxOverflowException e) { throw e; } catch (Exception e) { - LOG.error("Failed to calculate best type for var: {}", ssaVar, e); + mth.addWarnComment("Failed to calculate best type for var: " + ssaVar, e); return false; } } @@ -201,7 +201,7 @@ private boolean calculateFromBounds(MethodNode mth, SSAVar ssaVar) { TypeInfo typeInfo = ssaVar.getTypeInfo(); Set bounds = typeInfo.getBounds(); Optional bestTypeOpt = selectBestTypeFromBounds(bounds); - if (!bestTypeOpt.isPresent()) { + if (bestTypeOpt.isEmpty()) { if (Consts.DEBUG_TYPE_INFERENCE) { LOG.warn("Failed to select best type from bounds, count={} : ", bounds.size()); for (ITypeBound bound : bounds) { @@ -456,6 +456,7 @@ private boolean tryDeduceTypes(MethodNode mth) { return fixed; } + @SuppressWarnings("RedundantIfStatement") private boolean deduceType(MethodNode mth, SSAVar var) { if (var.isTypeImmutable()) { return false; 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 114da9b3421..e20bf2a9b6e 100644 --- a/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java +++ b/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java @@ -309,7 +309,7 @@ public String toString() { return "TaskWorker{status=" + status + ", jobsCount=" + jobsCount + ", jobsComplete=" + jobsComplete - + ", time=" + time + '}'; + + ", time=" + time + "ms}"; } } } diff --git a/jadx-gui/src/main/java/jadx/gui/search/providers/ClassSearchProvider.java b/jadx-gui/src/main/java/jadx/gui/search/providers/ClassSearchProvider.java index 269e284843a..ad1fef7776c 100644 --- a/jadx-gui/src/main/java/jadx/gui/search/providers/ClassSearchProvider.java +++ b/jadx-gui/src/main/java/jadx/gui/search/providers/ClassSearchProvider.java @@ -1,6 +1,7 @@ package jadx.gui.search.providers; import java.util.List; +import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; @@ -16,7 +17,16 @@ public final class ClassSearchProvider extends BaseSearchProvider { private int clsNum = 0; public ClassSearchProvider(MainWindow mw, SearchSettings searchSettings, List classes) { - super(mw, searchSettings, classes); + super(mw, searchSettings, filterClasses(classes)); + } + + /** + * Collect top class with code + */ + private static List filterClasses(List classes) { + return classes.stream() + .filter(cls -> !cls.isInner() && !cls.isNoCode()) + .collect(Collectors.toList()); } @Override diff --git a/jadx-gui/src/main/java/jadx/gui/search/providers/MethodSearchProvider.java b/jadx-gui/src/main/java/jadx/gui/search/providers/MethodSearchProvider.java index ce64c98116a..ef19546199d 100644 --- a/jadx-gui/src/main/java/jadx/gui/search/providers/MethodSearchProvider.java +++ b/jadx-gui/src/main/java/jadx/gui/search/providers/MethodSearchProvider.java @@ -5,8 +5,8 @@ import org.jetbrains.annotations.Nullable; import jadx.api.JavaClass; -import jadx.api.JavaMethod; import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.nodes.MethodNode; import jadx.gui.jobs.Cancelable; import jadx.gui.search.SearchSettings; import jadx.gui.treemodel.JNode; @@ -28,11 +28,11 @@ public MethodSearchProvider(MainWindow mw, SearchSettings searchSettings, List methods = cls.getMethods(); + List methods = cls.getClassNode().getMethods(); if (mthNum < methods.size()) { - JavaMethod mth = methods.get(mthNum++); - if (checkMth(mth)) { - return convert(mth); + MethodNode mth = methods.get(mthNum++); + if (checkMth(mth.getMethodInfo())) { + return convert(mth.getJavaNode()); } } else { clsNum++; @@ -44,10 +44,11 @@ public MethodSearchProvider(MainWindow mw, SearchSettings searchSettings, List