From 4a6115ed641201f0cdc7b1c287d608bd43accba2 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sun, 11 May 2014 23:09:28 +0400 Subject: [PATCH] core: refactor attribute storage --- build.gradle | 5 +- .../src/main/java/jadx/api/Decompiler.java | 47 ++-- .../src/main/java/jadx/api/JavaClass.java | 15 +- .../java/jadx/core/codegen/AnnotationGen.java | 8 +- .../main/java/jadx/core/codegen/ClassGen.java | 26 +-- .../java/jadx/core/codegen/CodeWriter.java | 2 +- .../main/java/jadx/core/codegen/InsnGen.java | 25 ++- .../java/jadx/core/codegen/MethodGen.java | 30 ++- .../java/jadx/core/codegen/RegionGen.java | 25 +-- .../{AttributeFlag.java => AFlag.java} | 2 +- .../java/jadx/core/dex/attributes/AType.java | 45 ++++ .../jadx/core/dex/attributes/AttrList.java | 30 +++ .../jadx/core/dex/attributes/AttrNode.java | 93 +++++++- .../core/dex/attributes/AttributeStorage.java | 122 +++++++++++ .../core/dex/attributes/AttributeType.java | 67 ------ .../core/dex/attributes/AttributesList.java | 201 ------------------ .../core/dex/attributes/EmptyAttrStorage.java | 55 +++++ .../jadx/core/dex/attributes/IAttribute.java | 2 +- .../core/dex/attributes/IAttributeNode.java | 33 ++- .../annotations/AnnotationsList.java | 6 +- .../annotations/MethodParameters.java | 6 +- .../{ => nodes}/DeclareVariablesAttr.java | 8 +- .../attributes/{ => nodes}/EnumClassAttr.java | 8 +- .../{ => nodes}/FieldReplaceAttr.java | 8 +- .../{ => nodes}/ForceReturnAttr.java | 8 +- .../attributes/{ => nodes}/JadxErrorAttr.java | 8 +- .../JumpInfo.java} | 23 +- .../attributes/{ => nodes}/LineAttrNode.java | 4 +- .../{LoopAttr.java => nodes/LoopInfo.java} | 16 +- .../{ => nodes}/MethodInlineAttr.java | 8 +- .../attributes/{ => nodes}/PhiListAttr.java | 8 +- .../{ => nodes}/SourceFileAttr.java | 9 +- .../jadx/core/dex/instructions/PhiInsn.java | 2 +- .../dex/instructions/args/RegisterArg.java | 13 +- .../java/jadx/core/dex/nodes/BlockNode.java | 47 ++-- .../java/jadx/core/dex/nodes/ClassNode.java | 19 +- .../java/jadx/core/dex/nodes/FieldNode.java | 2 +- .../java/jadx/core/dex/nodes/InsnNode.java | 2 +- .../java/jadx/core/dex/nodes/MethodNode.java | 33 +-- .../dex/nodes/parser/AnnotationsParser.java | 8 +- .../dex/nodes/parser/DebugInfoParser.java | 4 +- .../core/dex/nodes/parser/FieldValueAttr.java | 6 +- .../dex/nodes/parser/SignatureParser.java | 2 +- .../dex/nodes/parser/StaticValuesParser.java | 2 +- .../jadx/core/dex/trycatch/CatchAttr.java | 6 +- .../core/dex/trycatch/ExcHandlerAttr.java | 6 +- .../core/dex/trycatch/SplitterBlockAttr.java | 6 +- .../jadx/core/dex/trycatch/TryCatchBlock.java | 15 +- .../core/dex/visitors/BlockMakerVisitor.java | 89 ++++---- .../dex/visitors/BlockProcessingHelper.java | 16 +- .../jadx/core/dex/visitors/ClassModifier.java | 22 +- .../jadx/core/dex/visitors/CodeShrinker.java | 4 +- .../core/dex/visitors/DotGraphVisitor.java | 16 +- .../jadx/core/dex/visitors/EnumVisitor.java | 12 +- .../dex/visitors/FallbackModeVisitor.java | 4 +- .../dex/visitors/MethodInlineVisitor.java | 12 +- .../jadx/core/dex/visitors/ModVisitor.java | 10 +- .../core/dex/visitors/PrepareForCodeGen.java | 6 +- .../dex/visitors/regions/CheckRegions.java | 12 +- .../dex/visitors/regions/IfRegionVisitor.java | 10 +- .../visitors/regions/ProcessReturnInsns.java | 8 +- .../regions/ProcessTryCatchRegions.java | 8 +- .../visitors/regions/ProcessVariables.java | 12 +- .../dex/visitors/regions/RegionMaker.java | 55 +++-- .../core/dex/visitors/regions/TernaryMod.java | 10 +- .../dex/visitors/ssa/EliminatePhiNodes.java | 6 +- .../core/dex/visitors/ssa/SSATransform.java | 16 +- .../visitors/typeinference/TypeInference.java | 4 +- .../main/java/jadx/core/utils/BlockUtils.java | 6 +- .../java/jadx/core/utils/ErrorsCounter.java | 8 +- .../jadx/core/utils/InstructionRemover.java | 4 +- .../java/jadx/core/utils/RegionUtils.java | 10 +- .../exceptions/JadxRuntimeException.java | 4 + .../java/jadx/core/utils/files/InputFile.java | 41 ++-- .../src/test/groovy/jadx/tests/TestAPI.groovy | 86 ++++++++ .../jadx/tests/TestAttributeStorage.groovy | 82 +++++++ .../jadx/tests/TestSignatureParser.groovy | 1 + .../dex/nodes/parser/TestSignatureParser.java | 110 ---------- .../tests/functional/StringUtilsTest.java | 35 --- .../internal/debuginfo/TestLineNumbers.java | 2 +- .../internal/trycatch/TestTryCatch3.java | 43 ++++ .../src/main/java/jadx/gui/JadxWrapper.java | 9 +- .../src/main/java/jadx/gui/ui/CodePanel.java | 16 +- 83 files changed, 1047 insertions(+), 868 deletions(-) rename jadx-core/src/main/java/jadx/core/dex/attributes/{AttributeFlag.java => AFlag.java} (92%) create mode 100644 jadx-core/src/main/java/jadx/core/dex/attributes/AType.java create mode 100644 jadx-core/src/main/java/jadx/core/dex/attributes/AttrList.java create mode 100644 jadx-core/src/main/java/jadx/core/dex/attributes/AttributeStorage.java delete mode 100644 jadx-core/src/main/java/jadx/core/dex/attributes/AttributeType.java delete mode 100644 jadx-core/src/main/java/jadx/core/dex/attributes/AttributesList.java create mode 100644 jadx-core/src/main/java/jadx/core/dex/attributes/EmptyAttrStorage.java rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/DeclareVariablesAttr.java (73%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/EnumClassAttr.java (88%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/FieldReplaceAttr.java (72%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/ForceReturnAttr.java (68%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/JadxErrorAttr.java (76%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{JumpAttribute.java => nodes/JumpInfo.java} (72%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/LineAttrNode.java (83%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{LoopAttr.java => nodes/LoopInfo.java} (79%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/MethodInlineAttr.java (62%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/PhiListAttr.java (73%) rename jadx-core/src/main/java/jadx/core/dex/attributes/{ => nodes}/SourceFileAttr.java (61%) create mode 100644 jadx-core/src/test/groovy/jadx/tests/TestAPI.groovy create mode 100644 jadx-core/src/test/groovy/jadx/tests/TestAttributeStorage.groovy delete mode 100644 jadx-core/src/test/java/jadx/core/dex/nodes/parser/TestSignatureParser.java delete mode 100644 jadx-core/src/test/java/jadx/tests/functional/StringUtilsTest.java create mode 100644 jadx-core/src/test/java/jadx/tests/internal/trycatch/TestTryCatch3.java diff --git a/build.gradle b/build.gradle index 66ff65be7..a44473c87 100644 --- a/build.gradle +++ b/build.gradle @@ -32,10 +32,11 @@ subprojects { dependencies { compile 'org.slf4j:slf4j-api:1.7.7' + testCompile 'ch.qos.logback:logback-classic:1.1.2' testCompile 'junit:junit:4.11' testCompile 'org.mockito:mockito-core:1.9.5' - testCompile 'org.spockframework:spock-core:0.7-groovy-2.0' - testCompile 'ch.qos.logback:logback-classic:1.1.2' + testCompile 'org.spockframework:spock-core:0.7-groovy-2.0' + testCompile 'cglib:cglib-nodep:3.1' } repositories { diff --git a/jadx-core/src/main/java/jadx/api/Decompiler.java b/jadx-core/src/main/java/jadx/api/Decompiler.java index 3709040fc..aa225820e 100644 --- a/jadx-core/src/main/java/jadx/api/Decompiler.java +++ b/jadx-core/src/main/java/jadx/api/Decompiler.java @@ -9,6 +9,7 @@ import jadx.core.dex.visitors.IDexTreeVisitor; import jadx.core.dex.visitors.SaveCode; import jadx.core.utils.ErrorsCounter; import jadx.core.utils.exceptions.DecodeException; +import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.InputFile; @@ -22,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -72,23 +72,34 @@ public final class Decompiler { } void init() { + reset(); if (outDir == null) { outDir = new File("jadx-output"); } this.passes = Jadx.getPassesList(args, outDir); } - public void loadFile(File file) throws IOException, DecodeException { + void reset() { + ClassInfo.clearCache(); + ErrorsCounter.reset(); + classes = null; + } + + public void loadFile(File file) throws JadxException { loadFiles(Collections.singletonList(file)); } - public void loadFiles(List files) throws IOException, DecodeException { + public void loadFiles(List files) throws JadxException { if (files.isEmpty()) { - throw new JadxRuntimeException("Empty file list"); + throw new JadxException("Empty file list"); } inputFiles.clear(); for (File file : files) { - inputFiles.add(new InputFile(file)); + try { + inputFiles.add(new InputFile(file)); + } catch (IOException e) { + throw new JadxException("Error load file: " + file, e); + } } parse(); } @@ -99,11 +110,11 @@ public final class Decompiler { ex.shutdown(); ex.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { - LOG.error("Save interrupted", e); + throw new JadxRuntimeException("Save interrupted", e); } } - public ThreadPoolExecutor getSaveExecutor() { + public ExecutorService getSaveExecutor() { if (root == null) { throw new JadxRuntimeException("No loaded files"); } @@ -111,7 +122,7 @@ public final class Decompiler { LOG.debug("processing threads count: {}", threadsCount); LOG.info("processing ..."); - ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadsCount); + ExecutorService executor = Executors.newFixedThreadPool(threadsCount); for (final JavaClass cls : getClasses()) { executor.execute(new Runnable() { @Override @@ -125,6 +136,9 @@ public final class Decompiler { } public List getClasses() { + if (root == null) { + return Collections.emptyList(); + } if (classes == null) { List classNodeList = root.getClasses(false); List clsList = new ArrayList(classNodeList.size()); @@ -137,8 +151,12 @@ public final class Decompiler { } public List getPackages() { + List classList = getClasses(); + if (classList.isEmpty()) { + return Collections.emptyList(); + } Map> map = new HashMap>(); - for (JavaClass javaClass : getClasses()) { + for (JavaClass javaClass : classList) { String pkg = javaClass.getPackage(); List clsList = map.get(pkg); if (clsList == null) { @@ -174,12 +192,6 @@ public final class Decompiler { root.load(inputFiles); } - private void reset() { - ClassInfo.clearCache(); - ErrorsCounter.reset(); - classes = null; - } - void processClass(ClassNode cls) { ProcessClass.process(cls, passes); } @@ -199,4 +211,9 @@ public final class Decompiler { } return null; } + + @Override + public String toString() { + return "jadx decompiler"; + } } diff --git a/jadx-core/src/main/java/jadx/api/JavaClass.java b/jadx-core/src/main/java/jadx/api/JavaClass.java index 7d02b92d3..60a83be33 100644 --- a/jadx-core/src/main/java/jadx/api/JavaClass.java +++ b/jadx-core/src/main/java/jadx/api/JavaClass.java @@ -1,8 +1,8 @@ package jadx.api; import jadx.core.codegen.CodeWriter; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.LineAttrNode; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; @@ -35,7 +35,10 @@ public final class JavaClass { decompile(); code = cls.getCode(); } - return code != null ? code.toString() : "error processing class"; + if (code == null) { + return ""; + } + return code.toString(); } public void decompile() { @@ -57,7 +60,7 @@ public final class JavaClass { if (inClsCount != 0) { List list = new ArrayList(inClsCount); for (ClassNode inner : cls.getInnerClasses()) { - if (!inner.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (!inner.contains(AFlag.DONT_GENERATE)) { JavaClass javaClass = new JavaClass(null, inner); javaClass.load(); list.add(javaClass); @@ -70,7 +73,7 @@ public final class JavaClass { if (fieldsCount != 0) { List flds = new ArrayList(fieldsCount); for (FieldNode f : cls.getFields()) { - if (!f.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (!f.contains(AFlag.DONT_GENERATE)) { flds.add(new JavaField(f)); } } @@ -81,7 +84,7 @@ public final class JavaClass { if (methodsCount != 0) { List mths = new ArrayList(methodsCount); for (MethodNode m : cls.getMethods()) { - if (!m.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (!m.contains(AFlag.DONT_GENERATE)) { mths.add(new JavaMethod(this, m)); } } diff --git a/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java b/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java index 6ade80a07..4804b2906 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java @@ -1,7 +1,7 @@ package jadx.core.codegen; import jadx.core.Consts; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.attributes.annotations.Annotation; import jadx.core.dex.attributes.annotations.AnnotationsList; @@ -53,7 +53,7 @@ public class AnnotationGen { } private void add(IAttributeNode node, CodeWriter code) { - AnnotationsList aList = (AnnotationsList) node.getAttributes().get(AttributeType.ANNOTATION_LIST); + AnnotationsList aList = node.get(AType.ANNOTATION_LIST); if (aList == null || aList.size() == 0) { return; } @@ -96,7 +96,7 @@ public class AnnotationGen { @SuppressWarnings("unchecked") public void addThrows(MethodNode mth, CodeWriter code) { - Annotation an = mth.getAttributes().getAnnotation(Consts.DALVIK_THROWS); + Annotation an = mth.getAnnotation(Consts.DALVIK_THROWS); if (an != null) { Object exs = an.getDefaultValue(); code.add(" throws "); @@ -111,7 +111,7 @@ public class AnnotationGen { } public Object getAnnotationDefaultValue(String name) { - Annotation an = cls.getAttributes().getAnnotation(Consts.DALVIK_ANNOTATION_DEFAULT); + Annotation an = cls.getAnnotation(Consts.DALVIK_ANNOTATION_DEFAULT); if (an != null) { Annotation defAnnotation = (Annotation) an.getDefaultValue(); return defAnnotation.getValues().get(name); diff --git a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java index b86d7067e..4680c73b9 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java @@ -1,12 +1,12 @@ package jadx.core.codegen; import jadx.core.Consts; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AttrNode; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.EnumClassAttr; -import jadx.core.dex.attributes.EnumClassAttr.EnumField; -import jadx.core.dex.attributes.SourceFileAttr; +import jadx.core.dex.attributes.nodes.EnumClassAttr; +import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField; +import jadx.core.dex.attributes.nodes.SourceFileAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.ClassInfo; import jadx.core.dex.instructions.args.ArgType; @@ -90,10 +90,10 @@ public class ClassGen { } public void addClassCode(CodeWriter code) throws CodegenException { - if (cls.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (cls.contains(AFlag.DONT_GENERATE)) { return; } - if (cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) { + if (cls.contains(AFlag.INCONSISTENT_CODE)) { code.startLine("// jadx: inconsistent code"); } addClassDeclaration(code); @@ -206,7 +206,7 @@ public class ClassGen { private void addMethods(CodeWriter code) { for (MethodNode mth : cls.getMethods()) { - if (!mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (!mth.contains(AFlag.DONT_GENERATE)) { try { if (code.getLine() != clsDeclLine) { code.newLine(); @@ -233,7 +233,7 @@ public class ClassGen { } code.add(';'); } else { - boolean badCode = mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE); + boolean badCode = mth.contains(AFlag.INCONSISTENT_CODE); if (badCode) { code.startLine("/* JADX WARNING: inconsistent code. */"); code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */"); @@ -254,7 +254,7 @@ public class ClassGen { private void addFields(CodeWriter code) throws CodegenException { addEnumFields(code); for (FieldNode f : cls.getFields()) { - if (f.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (f.contains(AFlag.DONT_GENERATE)) { continue; } annotationGen.addForField(code, f); @@ -262,7 +262,7 @@ public class ClassGen { code.add(TypeGen.translate(this, f.getType())); code.add(' '); code.add(f.getName()); - FieldValueAttr fv = (FieldValueAttr) f.getAttributes().get(AttributeType.FIELD_VALUE); + FieldValueAttr fv = f.get(AType.FIELD_VALUE); if (fv != null) { code.add(" = "); if (fv.getValue() == null) { @@ -277,7 +277,7 @@ public class ClassGen { } private void addEnumFields(CodeWriter code) throws CodegenException { - EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS); + EnumClassAttr enumFields = cls.get(AType.ENUM_CLASS); if (enumFields != null) { InsnGen igen = null; for (Iterator it = enumFields.getFields().iterator(); it.hasNext(); ) { @@ -441,7 +441,7 @@ public class ClassGen { } private void insertSourceFileInfo(CodeWriter code, AttrNode node) { - SourceFileAttr sourceFileAttr = (SourceFileAttr) node.getAttributes().get(AttributeType.SOURCE_FILE); + SourceFileAttr sourceFileAttr = node.get(AType.SOURCE_FILE); if (sourceFileAttr != null) { code.startLine("// compiled from: ").add(sourceFileAttr.getFileName()); } diff --git a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java index 009da3490..7c6b89496 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java +++ b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java @@ -1,7 +1,7 @@ package jadx.core.codegen; import jadx.api.CodePosition; -import jadx.core.dex.attributes.LineAttrNode; +import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.utils.Utils; import java.io.File; diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index e707abc08..1df32c37d 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -1,9 +1,9 @@ package jadx.core.codegen; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.FieldReplaceAttr; -import jadx.core.dex.attributes.MethodInlineAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.FieldReplaceAttr; +import jadx.core.dex.attributes.nodes.MethodInlineAttr; import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.MethodInfo; @@ -110,7 +110,7 @@ public class InsnGen { public void assignVar(CodeWriter code, InsnNode insn) throws CodegenException { RegisterArg arg = insn.getResult(); - if (insn.getAttributes().contains(AttributeFlag.DECLARE_VAR)) { + if (insn.contains(AFlag.DECLARE_VAR)) { declareVar(code, arg); } else { addArg(code, arg, false); @@ -130,7 +130,7 @@ public class InsnGen { private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException { FieldNode fieldNode = mth.getParentClass().searchField(field); if (fieldNode != null) { - FieldReplaceAttr replace = (FieldReplaceAttr) fieldNode.getAttributes().get(AttributeType.FIELD_REPLACE); + FieldReplaceAttr replace = fieldNode.get(AType.FIELD_REPLACE); if (replace != null) { FieldInfo info = replace.getFieldInfo(); if (replace.isOuterClass()) { @@ -553,13 +553,13 @@ public class InsnGen { } else { parent = cls.getSuperClass(); } - cls.getAttributes().add(AttributeFlag.DONT_GENERATE); + cls.add(AFlag.DONT_GENERATE); MethodNode defCtr = cls.getDefaultConstructor(); if (defCtr != null) { if (RegionUtils.notEmpty(defCtr.getRegion())) { - defCtr.getAttributes().add(AttributeFlag.ANONYMOUS_CONSTRUCTOR); + defCtr.add(AFlag.ANONYMOUS_CONSTRUCTOR); } else { - defCtr.getAttributes().add(AttributeFlag.DONT_GENERATE); + defCtr.add(AFlag.DONT_GENERATE); } } code.add("new ").add(parent == null ? "Object" : useClass(parent)).add("() "); @@ -624,7 +624,7 @@ public class InsnGen { } private void generateArguments(CodeWriter code, InsnNode insn, int k, MethodNode callMth) throws CodegenException { - if (callMth != null && callMth.getAttributes().contains(AttributeFlag.SKIP_FIRST_ARG)) { + if (callMth != null && callMth.contains(AFlag.SKIP_FIRST_ARG)) { k++; } int argsCount = insn.getArgsCount(); @@ -662,7 +662,7 @@ public class InsnGen { } private boolean inlineMethod(MethodNode callMthNode, InvokeNode insn, CodeWriter code) throws CodegenException { - MethodInlineAttr mia = (MethodInlineAttr) callMthNode.getAttributes().get(AttributeType.METHOD_INLINE); + MethodInlineAttr mia = callMthNode.get(AType.METHOD_INLINE); if (mia == null) { return false; } @@ -729,8 +729,7 @@ public class InsnGen { private void makeArith(ArithNode insn, CodeWriter code, EnumSet state) throws CodegenException { // wrap insn in brackets for save correct operation order - boolean wrap = state.contains(Flags.BODY_ONLY) - && !insn.getAttributes().contains(AttributeFlag.DONT_WRAP); + boolean wrap = state.contains(Flags.BODY_ONLY) && !insn.contains(AFlag.DONT_WRAP); if (wrap) { code.add('('); } diff --git a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java index 76fccdc1c..4cae3eb5c 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java @@ -1,12 +1,10 @@ package jadx.core.codegen; import jadx.core.Consts; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.AttributesList; -import jadx.core.dex.attributes.IAttribute; -import jadx.core.dex.attributes.JadxErrorAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.annotations.MethodParameters; +import jadx.core.dex.attributes.nodes.JadxErrorAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.NamedArg; @@ -14,6 +12,7 @@ import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.regions.Region; +import jadx.core.dex.trycatch.CatchAttr; import jadx.core.dex.visitors.DepthTraversal; import jadx.core.dex.visitors.FallbackModeVisitor; import jadx.core.utils.ErrorsCounter; @@ -68,7 +67,7 @@ public class MethodGen { code.attachDefinition(mth); return true; } - if (mth.getAttributes().contains(AttributeFlag.ANONYMOUS_CONSTRUCTOR)) { + if (mth.contains(AFlag.ANONYMOUS_CONSTRUCTOR)) { // don't add method name and arguments code.startLine(); code.attachDefinition(mth); @@ -102,7 +101,7 @@ public class MethodGen { List args = mth.getArguments(false); if (mth.getMethodInfo().isConstructor() - && mth.getParentClass().getAttributes().contains(AttributeType.ENUM_CLASS)) { + && mth.getParentClass().contains(AType.ENUM_CLASS)) { if (args.size() == 2) { args.clear(); } else if (args.size() > 2) { @@ -124,7 +123,7 @@ public class MethodGen { private void addMethodArguments(CodeWriter argsCode, List args) { MethodParameters paramsAnnotation = - (MethodParameters) mth.getAttributes().get(AttributeType.ANNOTATION_MTH_PARAMETERS); + mth.get(AType.ANNOTATION_MTH_PARAMETERS); int i = 0; for (Iterator it = args.iterator(); it.hasNext(); ) { @@ -226,12 +225,12 @@ public class MethodGen { } public void addInstructions(CodeWriter code) throws CodegenException { - if (mth.getAttributes().contains(AttributeType.JADX_ERROR)) { + if (mth.contains(AType.JADX_ERROR)) { code.startLine("throw new UnsupportedOperationException(\"Method not decompiled: "); code.add(mth.toString()); code.add("\");"); - JadxErrorAttr err = (JadxErrorAttr) mth.getAttributes().get(AttributeType.JADX_ERROR); + JadxErrorAttr err = mth.get(AType.JADX_ERROR); code.startLine("/* JADX: method processing error */"); Throwable cause = err.getCause(); if (cause != null) { @@ -241,7 +240,7 @@ public class MethodGen { code.add("*/"); } makeMethodDump(code); - } else if (mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) { + } else if (mth.contains(AFlag.INCONSISTENT_CODE)) { code.startLine("/*"); addFallbackMethodCode(code); code.startLine("*/"); @@ -295,10 +294,9 @@ public class MethodGen { public static void addFallbackInsns(CodeWriter code, MethodNode mth, List insns, boolean addLabels) { InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true); for (InsnNode insn : insns) { - AttributesList attrs = insn.getAttributes(); if (addLabels) { - if (attrs.contains(AttributeType.JUMP) - || attrs.contains(AttributeType.EXC_HANDLER)) { + if (insn.contains(AType.JUMP) + || insn.contains(AType.EXC_HANDLER)) { code.decIndent(); code.startLine(getLabelName(insn.getOffset()) + ":"); code.incIndent(); @@ -306,8 +304,8 @@ public class MethodGen { } try { if (insnGen.makeInsn(insn, code)) { - List catchAttrs = attrs.getAll(AttributeType.CATCH_BLOCK); - for (IAttribute catchAttr : catchAttrs) { + CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK); + if (catchAttr != null) { code.add("\t " + catchAttr); } } diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index aaa2167a3..e4ce7905f 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -1,10 +1,9 @@ package jadx.core.codegen; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.DeclareVariablesAttr; -import jadx.core.dex.attributes.ForceReturnAttr; -import jadx.core.dex.attributes.IAttribute; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.DeclareVariablesAttr; +import jadx.core.dex.attributes.nodes.ForceReturnAttr; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.SwitchNode; @@ -63,8 +62,7 @@ public class RegionGen extends InsnGen { } private void declareVars(CodeWriter code, IContainer cont) { - DeclareVariablesAttr declVars = - (DeclareVariablesAttr) cont.getAttributes().get(AttributeType.DECLARE_VARIABLES); + DeclareVariablesAttr declVars = cont.get(AType.DECLARE_VARIABLES); if (declVars != null) { for (RegisterArg v : declVars.getVars()) { code.startLine(); @@ -75,7 +73,7 @@ public class RegionGen extends InsnGen { } private void makeSimpleRegion(CodeWriter code, Region region) throws CodegenException { - CatchAttr tc = (CatchAttr) region.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr tc = region.get(AType.CATCH_BLOCK); if (tc != null) { makeTryCatch(region, tc.getTryBlock(), code); } else { @@ -96,9 +94,8 @@ public class RegionGen extends InsnGen { for (InsnNode insn : block.getInstructions()) { makeInsn(insn, code); } - IAttribute attr; - if ((attr = block.getAttributes().get(AttributeType.FORCE_RETURN)) != null) { - ForceReturnAttr retAttr = (ForceReturnAttr) attr; + ForceReturnAttr retAttr = block.get(AType.FORCE_RETURN); + if (retAttr != null) { makeInsn(retAttr.getReturnInsn(), code); } } @@ -138,7 +135,7 @@ public class RegionGen extends InsnGen { List subBlocks = re.getSubBlocks(); if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) { IfRegion ifRegion = (IfRegion) subBlocks.get(0); - if (ifRegion.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) { + if (ifRegion.contains(AFlag.ELSE_IF_CHAIN)) { makeIf(ifRegion, code, false); return true; } @@ -153,7 +150,7 @@ public class RegionGen extends InsnGen { List headerInsns = header.getInstructions(); if (headerInsns.size() > 1) { // write not inlined instructions from header - mth.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + mth.add(AFlag.INCONSISTENT_CODE); int last = headerInsns.size() - 1; for (int i = 0; i < last; i++) { InsnNode insn = headerInsns.get(i); @@ -244,7 +241,7 @@ public class RegionGen extends InsnGen { private void makeTryCatch(IContainer region, TryCatchBlock tryCatchBlock, CodeWriter code) throws CodegenException { code.startLine("try {"); - region.getAttributes().remove(AttributeType.CATCH_BLOCK); + region.remove(AType.CATCH_BLOCK); makeRegionIndent(code, region); ExceptionHandler allHandler = null; for (ExceptionHandler handler : tryCatchBlock.getHandlers()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeFlag.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java similarity index 92% rename from jadx-core/src/main/java/jadx/core/dex/attributes/AttributeFlag.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java index 7d7d63f07..07393fcc1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeFlag.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java @@ -1,6 +1,6 @@ package jadx.core.dex.attributes; -public enum AttributeFlag { +public enum AFlag { TRY_ENTER, TRY_LEAVE, diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AType.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AType.java new file mode 100644 index 000000000..f982a8a06 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/AType.java @@ -0,0 +1,45 @@ +package jadx.core.dex.attributes; + +import jadx.core.dex.attributes.annotations.AnnotationsList; +import jadx.core.dex.attributes.annotations.MethodParameters; +import jadx.core.dex.attributes.nodes.DeclareVariablesAttr; +import jadx.core.dex.attributes.nodes.EnumClassAttr; +import jadx.core.dex.attributes.nodes.FieldReplaceAttr; +import jadx.core.dex.attributes.nodes.ForceReturnAttr; +import jadx.core.dex.attributes.nodes.JadxErrorAttr; +import jadx.core.dex.attributes.nodes.JumpInfo; +import jadx.core.dex.attributes.nodes.LoopInfo; +import jadx.core.dex.attributes.nodes.MethodInlineAttr; +import jadx.core.dex.attributes.nodes.PhiListAttr; +import jadx.core.dex.attributes.nodes.SourceFileAttr; +import jadx.core.dex.nodes.parser.FieldValueAttr; +import jadx.core.dex.trycatch.CatchAttr; +import jadx.core.dex.trycatch.ExcHandlerAttr; +import jadx.core.dex.trycatch.SplitterBlockAttr; + +/** + * Attribute types enumeration, + * uses generic type for omit cast after in 'AttributeStorage.get' method + * + * @param attribute class implementation + */ +public class AType { + + public static final AType> JUMP = new AType>(); + public static final AType> LOOP = new AType>(); + + public static final AType EXC_HANDLER = new AType(); + public static final AType CATCH_BLOCK = new AType(); + public static final AType SPLITTER_BLOCK = new AType(); + public static final AType FORCE_RETURN = new AType(); + public static final AType FIELD_VALUE = new AType(); + public static final AType FIELD_REPLACE = new AType(); + public static final AType JADX_ERROR = new AType(); + public static final AType METHOD_INLINE = new AType(); + public static final AType ENUM_CLASS = new AType(); + public static final AType ANNOTATION_LIST = new AType(); + public static final AType ANNOTATION_MTH_PARAMETERS = new AType(); + public static final AType PHI_LIST = new AType(); + public static final AType SOURCE_FILE = new AType(); + public static final AType DECLARE_VARIABLES = new AType(); +} diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttrList.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AttrList.java new file mode 100644 index 000000000..eeabbfea8 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/AttrList.java @@ -0,0 +1,30 @@ +package jadx.core.dex.attributes; + +import jadx.core.utils.Utils; + +import java.util.LinkedList; +import java.util.List; + +public class AttrList implements IAttribute { + + private final AType> type; + private final List list = new LinkedList(); + + public AttrList(AType> type) { + this.type = type; + } + + public List getList() { + return list; + } + + @Override + public AType> getType() { + return type; + } + + @Override + public String toString() { + return Utils.listToString(list); + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java index 2f1942ae2..28563feae 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java @@ -1,15 +1,96 @@ package jadx.core.dex.attributes; +import jadx.core.dex.attributes.annotations.Annotation; + +import java.util.List; + public abstract class AttrNode implements IAttributeNode { - private AttributesList attributesList; + private static final AttributeStorage EMPTY_ATTR_STORAGE = new EmptyAttrStorage(); + + private AttributeStorage storage = EMPTY_ATTR_STORAGE; @Override - public AttributesList getAttributes() { - if (attributesList == null) { - attributesList = new AttributesList(); - } - return attributesList; + public void add(AFlag flag) { + getStorage().add(flag); } + @Override + public void addAttr(IAttribute attr) { + getStorage().add(attr); + } + + @Override + public void addAttr(AType> type, T obj) { + getStorage().add(type, obj); + } + + @Override + public void copyAttributesFrom(AttrNode attrNode) { + getStorage().addAll(attrNode.storage); + } + + AttributeStorage getStorage() { + AttributeStorage store = storage; + if (store == EMPTY_ATTR_STORAGE) { + store = new AttributeStorage(); + storage = store; + } + return store; + } + + @Override + public boolean contains(AFlag flag) { + return storage.contains(flag); + } + + @Override + public boolean contains(AType type) { + return storage.contains(type); + } + + @Override + public T get(AType type) { + return storage.get(type); + } + + @Override + public Annotation getAnnotation(String cls) { + return storage.getAnnotation(cls); + } + + @Override + public List getAll(AType> type) { + return storage.getAll(type); + } + + @Override + public void remove(AFlag flag) { + storage.remove(flag); + } + + @Override + public void remove(AType type) { + storage.remove(type); + } + + @Override + public void removeAttr(IAttribute attr) { + storage.remove(attr); + } + + @Override + public void clearAttributes() { + storage.clear(); + } + + @Override + public List getAttributesStringsList() { + return storage.getAttributeStrings(); + } + + @Override + public String getAttributesString() { + return storage.toString(); + } } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeStorage.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeStorage.java new file mode 100644 index 000000000..0dcc4941d --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeStorage.java @@ -0,0 +1,122 @@ +package jadx.core.dex.attributes; + +import jadx.core.dex.attributes.annotations.Annotation; +import jadx.core.dex.attributes.annotations.AnnotationsList; +import jadx.core.utils.Utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Storage for different attribute types: + * 1. flags - boolean attribute (set or not) + * 2. attribute - class instance associated with attribute type. + */ +public class AttributeStorage { + + private final Set flags; + private final Map, IAttribute> attributes; + + public AttributeStorage() { + flags = EnumSet.noneOf(AFlag.class); + attributes = new HashMap, IAttribute>(2); + } + + public void add(AFlag flag) { + flags.add(flag); + } + + public void add(IAttribute attr) { + attributes.put(attr.getType(), attr); + } + + public void add(AType> type, T obj) { + AttrList list = get(type); + if (list == null) { + list = new AttrList(type); + add(list); + } + list.getList().add(obj); + } + + public void addAll(AttributeStorage otherList) { + flags.addAll(otherList.flags); + attributes.putAll(otherList.attributes); + } + + public boolean contains(AFlag flag) { + return flags.contains(flag); + } + + public boolean contains(AType type) { + return attributes.containsKey(type); + } + + @SuppressWarnings("unchecked") + public T get(AType type) { + return (T) attributes.get(type); + } + + public Annotation getAnnotation(String cls) { + AnnotationsList aList = get(AType.ANNOTATION_LIST); + return aList == null ? null : aList.get(cls); + } + + public List getAll(AType> type) { + AttrList attrList = get(type); + if (attrList == null) { + return Collections.emptyList(); + } + return attrList.getList(); + } + + public void remove(AFlag flag) { + flags.remove(flag); + } + + public void remove(AType type) { + attributes.remove(type); + } + + public void remove(IAttribute attr) { + AType type = attr.getType(); + IAttribute a = attributes.get(type); + if (a == attr) { + attributes.remove(type); + } + } + + public void clear() { + flags.clear(); + attributes.clear(); + } + + public List getAttributeStrings() { + int size = flags.size() + attributes.size() + attributes.size(); + if (size == 0) { + return Collections.emptyList(); + } + List list = new ArrayList(size); + for (AFlag a : flags) { + list.add(a.toString()); + } + for (IAttribute a : attributes.values()) { + list.add(a.toString()); + } + return list; + } + + @Override + public String toString() { + List list = getAttributeStrings(); + if (list.isEmpty()) { + return ""; + } + return "A:{" + Utils.listToString(list) + "}"; + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeType.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeType.java deleted file mode 100644 index 15c4640a0..000000000 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributeType.java +++ /dev/null @@ -1,67 +0,0 @@ -package jadx.core.dex.attributes; - -public enum AttributeType { - - /* Multi attributes */ - - JUMP(false), - - LOOP(false), - CATCH_BLOCK(false), - - /* Uniq attributes */ - - EXC_HANDLER(true), - SPLITTER_BLOCK(true), - FORCE_RETURN(true), - - FIELD_VALUE(true), - - JADX_ERROR(true), - METHOD_INLINE(true), - FIELD_REPLACE(true), - - ENUM_CLASS(true), - - ANNOTATION_LIST(true), - ANNOTATION_MTH_PARAMETERS(true), - - PHI_LIST(true), - - SOURCE_FILE(true), - - // for regions - DECLARE_VARIABLES(true); - - private static final int NOT_UNIQ_COUNT; - private final boolean uniq; - - private AttributeType(boolean isUniq) { - this.uniq = isUniq; - } - - static { - // place all not unique attributes at first - int last = -1; - AttributeType[] vals = AttributeType.values(); - for (int i = 0; i < vals.length; i++) { - AttributeType type = vals[i]; - if (type.notUniq()) { - last = i; - } - } - NOT_UNIQ_COUNT = last + 1; - } - - public static int getNotUniqCount() { - return NOT_UNIQ_COUNT; - } - - public boolean isUniq() { - return uniq; - } - - public boolean notUniq() { - return !uniq; - } -} diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributesList.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AttributesList.java deleted file mode 100644 index 17c2441de..000000000 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/AttributesList.java +++ /dev/null @@ -1,201 +0,0 @@ -package jadx.core.dex.attributes; - -import jadx.core.dex.attributes.annotations.Annotation; -import jadx.core.dex.attributes.annotations.AnnotationsList; -import jadx.core.utils.Utils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Storage for different attribute types: - * 1. flags - boolean attribute (set or not) - * 2. attribute - class instance associated for attribute type, - * only one attached to node for unique attributes, multiple for others - */ -public final class AttributesList { - - private final Set flags; - private final Map uniqAttr; - private final List attributes; - private final int[] attrCount; - - public AttributesList() { - flags = EnumSet.noneOf(AttributeFlag.class); - uniqAttr = new EnumMap(AttributeType.class); - attributes = new LinkedList(); - attrCount = new int[AttributeType.getNotUniqCount()]; - } - - // Flags - - public void add(AttributeFlag flag) { - flags.add(flag); - } - - public boolean contains(AttributeFlag flag) { - return flags.contains(flag); - } - - public void remove(AttributeFlag flag) { - flags.remove(flag); - } - - // Attributes - - public void add(IAttribute attr) { - if (attr.getType().isUniq()) { - uniqAttr.put(attr.getType(), attr); - } else { - addMultiAttribute(attr); - } - } - - private void addMultiAttribute(IAttribute attr) { - attributes.add(attr); - attrCount[attr.getType().ordinal()]++; - } - - private int getMultiCountInternal(AttributeType type) { - return attrCount[type.ordinal()]; - } - - public void addAll(AttributesList otherList) { - flags.addAll(otherList.flags); - uniqAttr.putAll(otherList.uniqAttr); - for (IAttribute attr : otherList.attributes) { - addMultiAttribute(attr); - } - } - - public boolean contains(AttributeType type) { - if (type.isUniq()) { - return uniqAttr.containsKey(type); - } else { - return getMultiCountInternal(type) != 0; - } - } - - public IAttribute get(AttributeType type) { - if (type.isUniq()) { - return uniqAttr.get(type); - } else { - if (getMultiCountInternal(type) != 0) { - for (IAttribute attr : attributes) { - if (attr.getType() == type) { - return attr; - } - } - } - return null; - } - } - - public int getCount(AttributeType type) { - if (type.isUniq()) { - return uniqAttr.containsKey(type) ? 1 : 0; - } else { - return getMultiCountInternal(type); - } - } - - public Annotation getAnnotation(String cls) { - AnnotationsList aList = (AnnotationsList) get(AttributeType.ANNOTATION_LIST); - return aList == null ? null : aList.get(cls); - } - - public List getAll(AttributeType type) { - assert type.notUniq(); - - int count = getMultiCountInternal(type); - if (count == 0) { - return Collections.emptyList(); - } - List attrs = new ArrayList(count); - for (IAttribute attr : attributes) { - if (attr.getType() == type) { - attrs.add(attr); - } - } - return attrs; - } - - public void remove(AttributeType type) { - if (type.isUniq()) { - uniqAttr.remove(type); - } else { - for (Iterator it = attributes.iterator(); it.hasNext(); ) { - IAttribute attr = it.next(); - if (attr.getType() == type) { - it.remove(); - } - } - attrCount[type.ordinal()] = 0; - } - } - - public void remove(IAttribute attr) { - AttributeType type = attr.getType(); - if (type.isUniq()) { - IAttribute a = uniqAttr.get(type); - if (a == attr) { - uniqAttr.remove(type); - } - } else { - if (getMultiCountInternal(type) == 0) { - return; - } - - for (Iterator it = attributes.iterator(); it.hasNext(); ) { - IAttribute a = it.next(); - if (a == attr) { - it.remove(); - attrCount[type.ordinal()]--; - } - } - } - } - - public void clear() { - flags.clear(); - uniqAttr.clear(); - attributes.clear(); - Arrays.fill(attrCount, 0); - } - - public List getAttributeStrings() { - int size = flags.size() + uniqAttr.size() + attributes.size(); - if (size == 0) { - return Collections.emptyList(); - } - List list = new ArrayList(size); - for (AttributeFlag a : flags) { - list.add(a.toString()); - } - for (IAttribute a : uniqAttr.values()) { - list.add(a.toString()); - } - for (IAttribute a : attributes) { - list.add(a.toString()); - } - return list; - } - - @Override - public String toString() { - List list = getAttributeStrings(); - if (list.isEmpty()) { - return ""; - } - return "A:{" + Utils.listToString(list) + "}"; - } - -} diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/EmptyAttrStorage.java b/jadx-core/src/main/java/jadx/core/dex/attributes/EmptyAttrStorage.java new file mode 100644 index 000000000..ac0179977 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/EmptyAttrStorage.java @@ -0,0 +1,55 @@ +package jadx.core.dex.attributes; + +import jadx.core.dex.attributes.annotations.Annotation; + +import java.util.Collections; +import java.util.List; + +public class EmptyAttrStorage extends AttributeStorage { + + @Override + public boolean contains(AFlag flag) { + return false; + } + + @Override + public boolean contains(AType type) { + return false; + } + + @Override + public T get(AType type) { + return null; + } + + @Override + public Annotation getAnnotation(String cls) { + return null; + } + + @Override + public List getAll(AType> type) { + return Collections.emptyList(); + } + + @Override + public void clear() { + } + + @Override + public void remove(AFlag flag) { + } + + @Override + public void remove(AType type) { + } + + @Override + public void remove(IAttribute attr) { + } + + @Override + public List getAttributeStrings() { + return Collections.emptyList(); + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/IAttribute.java b/jadx-core/src/main/java/jadx/core/dex/attributes/IAttribute.java index a968d723e..18bb476b6 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/IAttribute.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/IAttribute.java @@ -2,6 +2,6 @@ package jadx.core.dex.attributes; public interface IAttribute { - AttributeType getType(); + AType getType(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java index 885e19f76..c963938a6 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java @@ -1,7 +1,38 @@ package jadx.core.dex.attributes; +import jadx.core.dex.attributes.annotations.Annotation; + +import java.util.List; + public interface IAttributeNode { - AttributesList getAttributes(); + void add(AFlag flag); + void addAttr(IAttribute attr); + + void addAttr(AType> type, T obj); + + void copyAttributesFrom(AttrNode attrNode); + + boolean contains(AFlag flag); + + boolean contains(AType type); + + T get(AType type); + + Annotation getAnnotation(String cls); + + List getAll(AType> type); + + void remove(AFlag flag); + + void remove(AType type); + + void removeAttr(IAttribute attr); + + void clearAttributes(); + + List getAttributesStringsList(); + + String getAttributesString(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/AnnotationsList.java b/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/AnnotationsList.java index 02a77ed78..13eb2dd9b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/AnnotationsList.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/AnnotationsList.java @@ -1,6 +1,6 @@ package jadx.core.dex.attributes.annotations; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; import jadx.core.utils.Utils; @@ -33,8 +33,8 @@ public class AnnotationsList implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.ANNOTATION_LIST; + public AType getType() { + return AType.ANNOTATION_LIST; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/MethodParameters.java b/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/MethodParameters.java index 4624f8fb8..28778f9b5 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/MethodParameters.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/annotations/MethodParameters.java @@ -1,6 +1,6 @@ package jadx.core.dex.attributes.annotations; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; import jadx.core.utils.Utils; @@ -20,8 +20,8 @@ public class MethodParameters implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.ANNOTATION_MTH_PARAMETERS; + public AType getType() { + return AType.ANNOTATION_MTH_PARAMETERS; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/DeclareVariablesAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/DeclareVariablesAttr.java similarity index 73% rename from jadx-core/src/main/java/jadx/core/dex/attributes/DeclareVariablesAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/DeclareVariablesAttr.java index 3cecbdef2..a06a704a7 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/DeclareVariablesAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/DeclareVariablesAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.utils.Utils; @@ -22,8 +24,8 @@ public class DeclareVariablesAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.DECLARE_VARIABLES; + public AType getType() { + return AType.DECLARE_VARIABLES; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/EnumClassAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumClassAttr.java similarity index 88% rename from jadx-core/src/main/java/jadx/core/dex/attributes/EnumClassAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumClassAttr.java index 464363843..a53d7c2bc 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/EnumClassAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumClassAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.MethodNode; @@ -67,8 +69,8 @@ public class EnumClassAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.ENUM_CLASS; + public AType getType() { + return AType.ENUM_CLASS; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/FieldReplaceAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/FieldReplaceAttr.java similarity index 72% rename from jadx-core/src/main/java/jadx/core/dex/attributes/FieldReplaceAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/FieldReplaceAttr.java index 8f650e11e..ff30c6f11 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/FieldReplaceAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/FieldReplaceAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.info.FieldInfo; public class FieldReplaceAttr implements IAttribute { @@ -21,8 +23,8 @@ public class FieldReplaceAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.FIELD_REPLACE; + public AType getType() { + return AType.FIELD_REPLACE; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/ForceReturnAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/ForceReturnAttr.java similarity index 68% rename from jadx-core/src/main/java/jadx/core/dex/attributes/ForceReturnAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/ForceReturnAttr.java index b0579368f..46b938ae6 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/ForceReturnAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/ForceReturnAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.nodes.InsnNode; import jadx.core.utils.Utils; @@ -16,8 +18,8 @@ public class ForceReturnAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.FORCE_RETURN; + public AType getType() { + return AType.FORCE_RETURN; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/JadxErrorAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxErrorAttr.java similarity index 76% rename from jadx-core/src/main/java/jadx/core/dex/attributes/JadxErrorAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxErrorAttr.java index 309e79b4b..71745240b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/JadxErrorAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxErrorAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.utils.Utils; public class JadxErrorAttr implements IAttribute { @@ -15,8 +17,8 @@ public class JadxErrorAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.JADX_ERROR; + public AType getType() { + return AType.JADX_ERROR; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/JumpAttribute.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JumpInfo.java similarity index 72% rename from jadx-core/src/main/java/jadx/core/dex/attributes/JumpAttribute.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JumpInfo.java index 207dacf72..cb11ff39e 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/JumpAttribute.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JumpInfo.java @@ -1,22 +1,17 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; import jadx.core.utils.InsnUtils; -public class JumpAttribute implements IAttribute { +public class JumpInfo { private final int src; private final int dest; - public JumpAttribute(int src, int dest) { + public JumpInfo(int src, int dest) { this.src = src; this.dest = dest; } - @Override - public AttributeType getType() { - return AttributeType.JUMP; - } - public int getSrc() { return src; } @@ -25,11 +20,6 @@ public class JumpAttribute implements IAttribute { return dest; } - @Override - public String toString() { - return "JUMP: " + InsnUtils.formatOffset(src) + " -> " + InsnUtils.formatOffset(dest); - } - @Override public int hashCode() { return 31 * dest + src; @@ -46,7 +36,12 @@ public class JumpAttribute implements IAttribute { if (getClass() != obj.getClass()) { return false; } - JumpAttribute other = (JumpAttribute) obj; + JumpInfo other = (JumpInfo) obj; return dest == other.dest && src == other.src; } + + @Override + public String toString() { + return "JUMP: " + InsnUtils.formatOffset(src) + " -> " + InsnUtils.formatOffset(dest); + } } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/LineAttrNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java similarity index 83% rename from jadx-core/src/main/java/jadx/core/dex/attributes/LineAttrNode.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java index bb41e7d26..a88db0002 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/LineAttrNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java @@ -1,4 +1,6 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; + +import jadx.core.dex.attributes.AttrNode; public abstract class LineAttrNode extends AttrNode { diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/LoopAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LoopInfo.java similarity index 79% rename from jadx-core/src/main/java/jadx/core/dex/attributes/LoopAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LoopInfo.java index f87c15c9d..c868855e7 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/LoopAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LoopInfo.java @@ -1,5 +1,6 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.Edge; import jadx.core.utils.BlockUtils; @@ -10,13 +11,13 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; -public class LoopAttr implements IAttribute { +public class LoopInfo { private final BlockNode start; private final BlockNode end; private final Set loopBlocks; - public LoopAttr(BlockNode start, BlockNode end) { + public LoopInfo(BlockNode start, BlockNode end) { this.start = start; this.end = end; this.loopBlocks = Collections.unmodifiableSet(BlockUtils.getAllPathsBlocks(start, end)); @@ -30,11 +31,6 @@ public class LoopAttr implements IAttribute { return end; } - @Override - public AttributeType getType() { - return AttributeType.LOOP; - } - public Set getLoopBlocks() { return loopBlocks; } @@ -49,7 +45,7 @@ public class LoopAttr implements IAttribute { for (BlockNode block : blocks) { // exit: successor node not from this loop, (don't change to getCleanSuccessors) for (BlockNode s : block.getSuccessors()) { - if (!blocks.contains(s) && !s.getAttributes().contains(AttributeType.EXC_HANDLER)) { + if (!blocks.contains(s) && !s.contains(AType.EXC_HANDLER)) { nodes.add(block); } } @@ -65,7 +61,7 @@ public class LoopAttr implements IAttribute { Set blocks = getLoopBlocks(); for (BlockNode block : blocks) { for (BlockNode s : block.getSuccessors()) { - if (!blocks.contains(s) && !s.getAttributes().contains(AttributeType.EXC_HANDLER)) { + if (!blocks.contains(s) && !s.contains(AType.EXC_HANDLER)) { edges.add(new Edge(block, s)); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/MethodInlineAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java similarity index 62% rename from jadx-core/src/main/java/jadx/core/dex/attributes/MethodInlineAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java index 32939b91d..60b8f729f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/MethodInlineAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.nodes.InsnNode; public class MethodInlineAttr implements IAttribute { @@ -15,8 +17,8 @@ public class MethodInlineAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.METHOD_INLINE; + public AType getType() { + return AType.METHOD_INLINE; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/PhiListAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java similarity index 73% rename from jadx-core/src/main/java/jadx/core/dex/attributes/PhiListAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java index b00d8a2ac..4487ddd04 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/PhiListAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java @@ -1,5 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.instructions.PhiInsn; import java.util.LinkedList; @@ -10,8 +12,8 @@ public class PhiListAttr implements IAttribute { private final List list = new LinkedList(); @Override - public AttributeType getType() { - return AttributeType.PHI_LIST; + public AType getType() { + return AType.PHI_LIST; } public List getList() { diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/SourceFileAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/SourceFileAttr.java similarity index 61% rename from jadx-core/src/main/java/jadx/core/dex/attributes/SourceFileAttr.java rename to jadx-core/src/main/java/jadx/core/dex/attributes/nodes/SourceFileAttr.java index 0eace7489..4cc8c8537 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/SourceFileAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/SourceFileAttr.java @@ -1,4 +1,7 @@ -package jadx.core.dex.attributes; +package jadx.core.dex.attributes.nodes; + +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.IAttribute; public class SourceFileAttr implements IAttribute { @@ -13,8 +16,8 @@ public class SourceFileAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.SOURCE_FILE; + public AType getType() { + return AType.SOURCE_FILE; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java b/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java index 832a9f4e3..10b57dae0 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java @@ -12,7 +12,7 @@ public class PhiInsn extends InsnNode { super(InsnType.PHI, predecessors); setResult(InsnArg.reg(regNum, ArgType.UNKNOWN)); for (int i = 0; i < predecessors; i++) { - addReg(regNum, ArgType.UNKNOWN); + addReg(regNum, ArgType.UNKNOWN); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java index 939a966f6..4d52a0dd8 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java @@ -1,6 +1,6 @@ package jadx.core.dex.instructions.args; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.instructions.ConstClassNode; import jadx.core.dex.instructions.ConstStringNode; @@ -16,9 +16,6 @@ import jadx.core.utils.exceptions.JadxRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - - public class RegisterArg extends InsnArg implements Named { private static final Logger LOG = LoggerFactory.getLogger(RegisterArg.class); @@ -95,7 +92,7 @@ public class RegisterArg extends InsnArg implements Named { FieldInfo f = (FieldInfo) ((IndexInsnNode) parInsn).getIndex(); FieldNode fieldNode = dex.resolveField(f); if (fieldNode != null) { - FieldValueAttr attr = (FieldValueAttr) fieldNode.getAttributes().get(AttributeType.FIELD_VALUE); + FieldValueAttr attr = fieldNode.get(AType.FIELD_VALUE); if (attr != null) { return attr.getValue(); } @@ -186,13 +183,13 @@ public class RegisterArg extends InsnArg implements Named { @Override public String toString() { - StringBuilder sb=new StringBuilder(); + StringBuilder sb = new StringBuilder(); sb.append("(r"); sb.append(regNum); - if(sVar!=null){ + if (sVar != null) { sb.append("_").append(sVar.getVersion()); } - if(name!=null){ + if (name != null) { sb.append(" '").append(name).append("'"); } sb.append(" "); diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java index c6cd9b67a..4c321ab0b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java @@ -1,9 +1,9 @@ package jadx.core.dex.nodes; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AttrNode; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.LoopAttr; +import jadx.core.dex.attributes.nodes.LoopInfo; import jadx.core.utils.InsnUtils; import java.util.ArrayList; @@ -79,26 +79,27 @@ public class BlockNode extends AttrNode implements IBlock { */ private static List cleanSuccessors(BlockNode block) { List sucList = block.getSuccessors(); - List nodes = new ArrayList(sucList.size()); - if (block.getAttributes().contains(AttributeFlag.LOOP_END)) { - LoopAttr loop = (LoopAttr) block.getAttributes().get(AttributeType.LOOP); - for (BlockNode b : sucList) { - if (!b.getAttributes().contains(AttributeType.EXC_HANDLER)) { - // don't follow back edge - if (loop.getStart() == b) { - continue; - } - nodes.add(b); - } - } - } else { - for (BlockNode b : sucList) { - if (!b.getAttributes().contains(AttributeType.EXC_HANDLER)) { - nodes.add(b); - } + if (sucList.isEmpty()) { + return sucList; + } + List toRemove = new LinkedList(); + for (BlockNode b : sucList) { + if (b.contains(AType.EXC_HANDLER)) { + toRemove.add(b); } } - return nodes.size() == sucList.size() ? sucList : nodes; + if (block.contains(AFlag.LOOP_END)) { + List loops = block.getAll(AType.LOOP); + for (LoopInfo loop : loops) { + toRemove.add(loop.getStart()); + } + } + if (toRemove.isEmpty()) { + return sucList; + } + List result = new ArrayList(sucList); + result.removeAll(toRemove); + return result; } @Override @@ -159,11 +160,11 @@ public class BlockNode extends AttrNode implements IBlock { } public boolean isSynthetic() { - return getAttributes().contains(AttributeFlag.SYNTHETIC); + return contains(AFlag.SYNTHETIC); } public boolean isReturnBlock() { - return getAttributes().contains(AttributeFlag.RETURN); + return contains(AFlag.RETURN); } @Override 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 042061117..8e75eff1a 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 @@ -2,11 +2,11 @@ package jadx.core.dex.nodes; import jadx.core.Consts; import jadx.core.codegen.CodeWriter; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.JadxErrorAttr; -import jadx.core.dex.attributes.LineAttrNode; -import jadx.core.dex.attributes.SourceFileAttr; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.annotations.Annotation; +import jadx.core.dex.attributes.nodes.JadxErrorAttr; +import jadx.core.dex.attributes.nodes.LineAttrNode; +import jadx.core.dex.attributes.nodes.SourceFileAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo.AFType; import jadx.core.dex.info.ClassInfo; @@ -106,14 +106,14 @@ public class ClassNode extends LineAttrNode implements ILoadable { String fileName = dex.getString(sfIdx); if (!this.getFullName().contains(fileName.replace(".java", "")) && !fileName.equals("SourceFile")) { - this.getAttributes().add(new SourceFileAttr(fileName)); + this.addAttr(new SourceFileAttr(fileName)); LOG.debug("Class '{}' compiled from '{}'", this, fileName); } } // restore original access flags from dalvik annotation if present int accFlagsValue; - Annotation a = getAttributes().getAnnotation(Consts.DALVIK_INNER_CLASS); + Annotation a = getAnnotation(Consts.DALVIK_INNER_CLASS); if (a != null) { accFlagsValue = (Integer) a.getValues().get("accessFlags"); } else { @@ -140,8 +140,7 @@ public class ClassNode extends LineAttrNode implements ILoadable { private void loadStaticValues(ClassDef cls, List staticFields) throws DecodeException { for (FieldNode f : staticFields) { if (f.getAccessFlags().isFinal()) { - FieldValueAttr nullValue = new FieldValueAttr(null); - f.getAttributes().add(nullValue); + f.addAttr(new FieldValueAttr(null)); } } @@ -153,7 +152,7 @@ public class ClassNode extends LineAttrNode implements ILoadable { for (FieldNode f : staticFields) { AccessInfo accFlags = f.getAccessFlags(); if (accFlags.isStatic() && accFlags.isFinal()) { - FieldValueAttr fv = (FieldValueAttr) f.getAttributes().get(AttributeType.FIELD_VALUE); + FieldValueAttr fv = f.get(AType.FIELD_VALUE); if (fv != null && fv.getValue() != null) { if (accFlags.isPublic()) { dex.getConstFields().put(fv.getValue(), f); @@ -212,7 +211,7 @@ public class ClassNode extends LineAttrNode implements ILoadable { mth.load(); } catch (DecodeException e) { LOG.error("Method load error", e); - mth.getAttributes().add(new JadxErrorAttr(e)); + mth.addAttr(new JadxErrorAttr(e)); } } for (ClassNode innerCls : getInnerClasses()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java index 5d46c973e..9be5b6e71 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java @@ -1,6 +1,6 @@ package jadx.core.dex.nodes; -import jadx.core.dex.attributes.LineAttrNode; +import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo.AFType; import jadx.core.dex.info.FieldInfo; diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index ae5cb1973..edbbcfc58 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -1,6 +1,6 @@ package jadx.core.dex.nodes; -import jadx.core.dex.attributes.LineAttrNode; +import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index 6956ea2e9..5b16dea63 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -1,9 +1,10 @@ package jadx.core.dex.nodes; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.JumpAttribute; -import jadx.core.dex.attributes.LineAttrNode; -import jadx.core.dex.attributes.LoopAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.JumpInfo; +import jadx.core.dex.attributes.nodes.LineAttrNode; +import jadx.core.dex.attributes.nodes.LoopInfo; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo.AFType; import jadx.core.dex.info.ClassInfo; @@ -65,7 +66,7 @@ public class MethodNode extends LineAttrNode implements ILoadable { private Region region; private List exceptionHandlers = Collections.emptyList(); - private List loops = Collections.emptyList(); + private List loops = Collections.emptyList(); public MethodNode(ClassNode classNode, Method mthData) { this.mthInfo = MethodInfo.fromDex(classNode.dex(), mthData.getMethodIndex()); @@ -224,7 +225,7 @@ public class MethodNode extends LineAttrNode implements ILoadable { } public RegisterArg removeFirstArgument() { - this.getAttributes().add(AttributeFlag.SKIP_FIRST_ARG); + this.add(AFlag.SKIP_FIRST_ARG); return argsList.remove(0); } @@ -288,24 +289,24 @@ public class MethodNode extends LineAttrNode implements ILoadable { int addr = eh.getHandleOffset(); // assert addrs.add(addr) : "Instruction already contains EXC_HANDLER attribute"; ExcHandlerAttr ehAttr = new ExcHandlerAttr(ct, eh); - insnByOffset[addr].getAttributes().add(ehAttr); + insnByOffset[addr].addAttr(ehAttr); } } // attach TRY_ENTER, TRY_LEAVE attributes to instructions for (Try aTry : tries) { int catchNum = aTry.getCatchHandlerIndex(); - TryCatchBlock block = catches.get(catchNum); + TryCatchBlock catchBlock = catches.get(catchNum); int offset = aTry.getStartAddress(); int end = offset + aTry.getInstructionCount() - 1; - insnByOffset[offset].getAttributes().add(AttributeFlag.TRY_ENTER); + insnByOffset[offset].add(AFlag.TRY_ENTER); while (offset <= end && offset >= 0) { - block.addInsn(insnByOffset[offset]); + catchBlock.addInsn(insnByOffset[offset]); offset = InsnDecoder.getNextInsnOffset(insnByOffset, offset); } if (insnByOffset[end] != null) { - insnByOffset[end].getAttributes().add(AttributeFlag.TRY_LEAVE); + insnByOffset[end].add(AFlag.TRY_LEAVE); } } } @@ -346,7 +347,7 @@ public class MethodNode extends LineAttrNode implements ILoadable { } private static void addJump(InsnNode[] insnByOffset, int offset, int target) { - insnByOffset[target].getAttributes().add(new JumpAttribute(offset, target)); + insnByOffset[target].addAttr(AType.JUMP, new JumpInfo(offset, target)); } public String getName() { @@ -411,15 +412,15 @@ public class MethodNode extends LineAttrNode implements ILoadable { this.exitBlocks.add(exitBlock); } - public void registerLoop(LoopAttr loop) { + public void registerLoop(LoopInfo loop) { if (loops.isEmpty()) { - loops = new ArrayList(5); + loops = new ArrayList(5); } loops.add(loop); } - public LoopAttr getLoopForBlock(BlockNode block) { - for (LoopAttr loop : loops) { + public LoopInfo getLoopForBlock(BlockNode block) { + for (LoopInfo loop : loops) { if (loop.getLoopBlocks().contains(block)) { return loop; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/AnnotationsParser.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/AnnotationsParser.java index 2b10d0d82..a6df6d8ea 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/AnnotationsParser.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/AnnotationsParser.java @@ -44,17 +44,17 @@ public class AnnotationsParser { int annotatedParametersCount = section.readInt(); if (classAnnotationsOffset != 0) { - cls.getAttributes().add(readAnnotationSet(classAnnotationsOffset)); + cls.addAttr(readAnnotationSet(classAnnotationsOffset)); } for (int i = 0; i < fieldsCount; i++) { FieldNode f = cls.searchFieldById(section.readInt()); - f.getAttributes().add(readAnnotationSet(section.readInt())); + f.addAttr(readAnnotationSet(section.readInt())); } for (int i = 0; i < annotatedMethodsCount; i++) { MethodNode m = cls.searchMethodById(section.readInt()); - m.getAttributes().add(readAnnotationSet(section.readInt())); + m.addAttr(readAnnotationSet(section.readInt())); } for (int i = 0; i < annotatedParametersCount; i++) { @@ -66,7 +66,7 @@ public class AnnotationsParser { for (int j = 0; j < size; j++) { params.getParamList().add(readAnnotationSet(ss.readInt())); } - mth.getAttributes().add(params); + mth.addAttr(params); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/DebugInfoParser.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/DebugInfoParser.java index 330686004..077fde253 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/DebugInfoParser.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/DebugInfoParser.java @@ -1,6 +1,6 @@ package jadx.core.dex.nodes.parser; -import jadx.core.dex.attributes.SourceFileAttr; +import jadx.core.dex.attributes.nodes.SourceFileAttr; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.DexNode; @@ -135,7 +135,7 @@ public class DebugInfoParser { int idx = section.readUleb128() - 1; if (idx != DexNode.NO_INDEX) { String sourceFile = dex.getString(idx); - mth.getAttributes().add(new SourceFileAttr(sourceFile)); + mth.addAttr(new SourceFileAttr(sourceFile)); } break; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/FieldValueAttr.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/FieldValueAttr.java index 9523c4a78..d61d9f626 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/FieldValueAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/FieldValueAttr.java @@ -1,6 +1,6 @@ package jadx.core.dex.nodes.parser; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; public class FieldValueAttr implements IAttribute { @@ -12,8 +12,8 @@ public class FieldValueAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.FIELD_VALUE; + public AType getType() { + return AType.FIELD_VALUE; } public Object getValue() { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java index 4df105ce9..72c5420f4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java @@ -35,7 +35,7 @@ public class SignatureParser { @SuppressWarnings("unchecked") public static SignatureParser fromNode(IAttributeNode node) { - Annotation a = node.getAttributes().getAnnotation(Consts.DALVIK_SIGNATURE); + Annotation a = node.getAnnotation(Consts.DALVIK_SIGNATURE); if (a == null) { return null; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/StaticValuesParser.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/StaticValuesParser.java index e68271631..5e5b19083 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/StaticValuesParser.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/StaticValuesParser.java @@ -19,7 +19,7 @@ public class StaticValuesParser extends EncValueParser { int count = Leb128.readUnsignedLeb128(in); for (int i = 0; i < count; i++) { Object value = parseValue(); - fields.get(i).getAttributes().add(new FieldValueAttr(value)); + fields.get(i).addAttr(new FieldValueAttr(value)); } return count; } diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/CatchAttr.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/CatchAttr.java index 145e72410..8b38d120f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/CatchAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/CatchAttr.java @@ -1,6 +1,6 @@ package jadx.core.dex.trycatch; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; public class CatchAttr implements IAttribute { @@ -12,8 +12,8 @@ public class CatchAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.CATCH_BLOCK; + public AType getType() { + return AType.CATCH_BLOCK; } public TryCatchBlock getTryBlock() { diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java index 0990b5f35..fdca842d9 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java @@ -1,6 +1,6 @@ package jadx.core.dex.trycatch; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; public class ExcHandlerAttr implements IAttribute { @@ -14,8 +14,8 @@ public class ExcHandlerAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.EXC_HANDLER; + public AType getType() { + return AType.EXC_HANDLER; } public TryCatchBlock getTryBlock() { diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java index 734617b82..ec051b6ca 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java @@ -1,6 +1,6 @@ package jadx.core.dex.trycatch; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.nodes.BlockNode; @@ -17,8 +17,8 @@ public class SplitterBlockAttr implements IAttribute { } @Override - public AttributeType getType() { - return AttributeType.SPLITTER_BLOCK; + public AType getType() { + return AType.SPLITTER_BLOCK; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/TryCatchBlock.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/TryCatchBlock.java index e18fc8a9a..00bdb5ec8 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/TryCatchBlock.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/TryCatchBlock.java @@ -1,7 +1,6 @@ package jadx.core.dex.trycatch; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.IAttribute; +import jadx.core.dex.attributes.AType; import jadx.core.dex.info.ClassInfo; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBlock; @@ -63,7 +62,7 @@ public class TryCatchBlock { if (finalBlock != null) { // search catch attr for (BlockNode block : mth.getBasicBlocks()) { - CatchAttr cb = (CatchAttr) block.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr cb = block.get(AType.CATCH_BLOCK); if (cb == attr) { for (ExceptionHandler eh : mth.getExceptionHandlers()) { if (eh.getBlocks().contains(block)) { @@ -76,23 +75,23 @@ public class TryCatchBlock { } else { // self destruction for (InsnNode insn : insns) { - insn.getAttributes().remove(attr); + insn.removeAttr(attr); } insns.clear(); for (BlockNode block : mth.getBasicBlocks()) { - block.getAttributes().remove(attr); + block.removeAttr(attr); } } } public void addInsn(InsnNode insn) { insns.add(insn); - insn.getAttributes().add(attr); + insn.addAttr(attr); } public void removeInsn(InsnNode insn) { insns.remove(insn); - insn.getAttributes().remove(attr.getType()); + insn.remove(AType.CATCH_BLOCK); } public Iterable getInsns() { @@ -125,7 +124,7 @@ public class TryCatchBlock { } // remove from blocks with this catch for (BlockNode b : mth.getBasicBlocks()) { - IAttribute ca = b.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr ca = b.get(AType.CATCH_BLOCK); if (attr == ca) { b.getInstructions().removeAll(finalBlockInsns); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java index 934fa6ecf..19481e3df 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java @@ -1,11 +1,9 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.AttributesList; -import jadx.core.dex.attributes.IAttribute; -import jadx.core.dex.attributes.JumpAttribute; -import jadx.core.dex.attributes.LoopAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.JumpInfo; +import jadx.core.dex.attributes.nodes.LoopInfo; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; @@ -91,7 +89,7 @@ public class BlockMakerVisitor extends AbstractVisitor { } } // for try/catch make empty block for connect handlers - if (insn.getAttributes().contains(AttributeFlag.TRY_ENTER)) { + if (insn.contains(AFlag.TRY_ENTER)) { BlockNode block; if (insn.getOffset() != 0 && !startNew) { block = startNewBlock(mth, insn.getOffset()); @@ -102,8 +100,8 @@ public class BlockMakerVisitor extends AbstractVisitor { // add this insn in new block block = startNewBlock(mth, -1); - curBlock.getAttributes().add(AttributeFlag.SYNTHETIC); - block.getAttributes().add(new SplitterBlockAttr(curBlock)); + curBlock.add(AFlag.SYNTHETIC); + block.addAttr(new SplitterBlockAttr(curBlock)); connect(curBlock, block); curBlock = block; } else { @@ -119,20 +117,19 @@ public class BlockMakerVisitor extends AbstractVisitor { private static void setupConnections(MethodNode mth, Map blocksMap) { for (BlockNode block : mth.getBasicBlocks()) { for (InsnNode insn : block.getInstructions()) { - List jumps = insn.getAttributes().getAll(AttributeType.JUMP); - for (IAttribute attr : jumps) { - JumpAttribute jump = (JumpAttribute) attr; + List jumps = insn.getAll(AType.JUMP); + for (JumpInfo jump : jumps) { BlockNode srcBlock = getBlock(jump.getSrc(), blocksMap); BlockNode thisblock = getBlock(jump.getDest(), blocksMap); connect(srcBlock, thisblock); } // connect exception handlers - CatchAttr catches = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr catches = insn.get(AType.CATCH_BLOCK); // get synthetic block for handlers - IAttribute spl = block.getAttributes().get(AttributeType.SPLITTER_BLOCK); + SplitterBlockAttr spl = block.get(AType.SPLITTER_BLOCK); if (catches != null && spl != null) { - BlockNode connBlock = ((SplitterBlockAttr) spl).getBlock(); + BlockNode connBlock = spl.getBlock(); for (ExceptionHandler h : catches.getTryBlock().getHandlers()) { BlockNode destBlock = getBlock(h.getHandleOffset(), blocksMap); // skip self loop in handler @@ -146,16 +143,14 @@ public class BlockMakerVisitor extends AbstractVisitor { } private static boolean isSplitByJump(InsnNode prevInsn, InsnNode currentInsn) { - List pJumps = prevInsn.getAttributes().getAll(AttributeType.JUMP); - for (IAttribute j : pJumps) { - JumpAttribute jump = (JumpAttribute) j; + List pJumps = prevInsn.getAll(AType.JUMP); + for (JumpInfo jump : pJumps) { if (jump.getSrc() == prevInsn.getOffset()) { return true; } } - List cJumps = currentInsn.getAttributes().getAll(AttributeType.JUMP); - for (IAttribute j : cJumps) { - JumpAttribute jump = (JumpAttribute) j; + List cJumps = currentInsn.getAll(AType.JUMP); + for (JumpInfo jump : cJumps) { if (jump.getDest() == currentInsn.getOffset()) { return true; } @@ -335,7 +330,7 @@ public class BlockMakerVisitor extends AbstractVisitor { mth.getExitBlocks().clear(); for (BlockNode block : mth.getBasicBlocks()) { if (BlockUtils.lastInsnType(block, InsnType.RETURN)) { - block.getAttributes().add(AttributeFlag.RETURN); + block.add(AFlag.RETURN); mth.getExitBlocks().add(block); } } @@ -347,12 +342,12 @@ public class BlockMakerVisitor extends AbstractVisitor { // Every successor that dominates its predecessor is a header of a loop, // block -> succ is a back edge. if (block.getDoms().get(succ.getId())) { - succ.getAttributes().add(AttributeFlag.LOOP_START); - block.getAttributes().add(AttributeFlag.LOOP_END); + succ.add(AFlag.LOOP_START); + block.add(AFlag.LOOP_END); - LoopAttr loop = new LoopAttr(succ, block); - succ.getAttributes().add(loop); - block.getAttributes().add(loop); + LoopInfo loop = new LoopInfo(succ, block); + succ.addAttr(AType.LOOP, loop); + block.addAttr(AType.LOOP, loop); } } } @@ -360,10 +355,11 @@ public class BlockMakerVisitor extends AbstractVisitor { private static void registerLoops(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { - AttributesList attributes = block.getAttributes(); - IAttribute loop = attributes.get(AttributeType.LOOP); - if (loop != null && attributes.contains(AttributeFlag.LOOP_START)) { - mth.registerLoop((LoopAttr) loop); + List loops = block.getAll(AType.LOOP); + if (block.contains(AFlag.LOOP_START)) { + for (LoopInfo loop : loops) { + mth.registerLoop(loop); + } } } } @@ -375,11 +371,10 @@ public class BlockMakerVisitor extends AbstractVisitor { } // check loops - List loops = block.getAttributes().getAll(AttributeType.LOOP); + List loops = block.getAll(AType.LOOP); if (loops.size() > 1) { boolean oneHeader = true; - for (IAttribute a : loops) { - LoopAttr loop = (LoopAttr) a; + for (LoopInfo loop : loops) { if (loop.getStart() != block) { oneHeader = false; break; @@ -388,10 +383,9 @@ public class BlockMakerVisitor extends AbstractVisitor { if (oneHeader) { // several back edges connected to one loop header => make additional block BlockNode newLoopHeader = startNewBlock(mth, block.getStartOffset()); - newLoopHeader.getAttributes().add(AttributeFlag.SYNTHETIC); + newLoopHeader.add(AFlag.SYNTHETIC); connect(newLoopHeader, block); - for (IAttribute a : loops) { - LoopAttr la = (LoopAttr) a; + for (LoopInfo la : loops) { BlockNode node = la.getEnd(); removeConnection(node, block); connect(node, newLoopHeader); @@ -401,13 +395,13 @@ public class BlockMakerVisitor extends AbstractVisitor { } // insert additional blocks if loop has several exits if (loops.size() == 1) { - LoopAttr loop = (LoopAttr) loops.get(0); + LoopInfo loop = loops.get(0); List edges = loop.getExitEdges(); if (edges.size() > 1) { boolean change = false; for (Edge edge : edges) { BlockNode target = edge.getTarget(); - if (!target.getAttributes().contains(AttributeFlag.SYNTHETIC)) { + if (!target.contains(AFlag.SYNTHETIC)) { insertBlockBetween(mth, edge.getSource(), target); change = true; } @@ -429,7 +423,7 @@ public class BlockMakerVisitor extends AbstractVisitor { private static BlockNode insertBlockBetween(MethodNode mth, BlockNode source, BlockNode target) { BlockNode newBlock = startNewBlock(mth, target.getStartOffset()); - newBlock.getAttributes().add(AttributeFlag.SYNTHETIC); + newBlock.add(AFlag.SYNTHETIC); removeConnection(source, target); connect(source, newBlock); connect(newBlock, target); @@ -477,8 +471,8 @@ public class BlockMakerVisitor extends AbstractVisitor { BlockNode exitBlock = mth.getExitBlocks().get(0); if (exitBlock.getPredecessors().size() > 1 && exitBlock.getInstructions().size() == 1 - && !exitBlock.getInstructions().get(0).getAttributes().contains(AttributeType.CATCH_BLOCK) - && !exitBlock.getAttributes().contains(AttributeFlag.SYNTHETIC)) { + && !exitBlock.getInstructions().get(0).contains(AType.CATCH_BLOCK) + && !exitBlock.contains(AFlag.SYNTHETIC)) { InsnNode returnInsn = exitBlock.getInstructions().get(0); List preds = new ArrayList(exitBlock.getPredecessors()); if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) { @@ -486,7 +480,7 @@ public class BlockMakerVisitor extends AbstractVisitor { } for (BlockNode pred : preds) { BlockNode newRetBlock = startNewBlock(mth, exitBlock.getStartOffset()); - newRetBlock.getAttributes().add(AttributeFlag.SYNTHETIC); + newRetBlock.add(AFlag.SYNTHETIC); newRetBlock.getInstructions().add(duplicateReturnInsn(returnInsn)); removeConnection(pred, exitBlock); connect(pred, newRetBlock); @@ -527,17 +521,16 @@ public class BlockMakerVisitor extends AbstractVisitor { RegisterArg arg = (RegisterArg) returnInsn.getArg(0); insn.addArg(InsnArg.reg(arg.getRegNum(), arg.getType())); } - insn.getAttributes().addAll(returnInsn.getAttributes()); + insn.copyAttributesFrom(returnInsn); insn.setOffset(returnInsn.getOffset()); return insn; } private static void clearBlocksState(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { - AttributesList attrs = block.getAttributes(); - attrs.remove(AttributeType.LOOP); - attrs.remove(AttributeFlag.LOOP_START); - attrs.remove(AttributeFlag.LOOP_END); + block.remove(AType.LOOP); + block.remove(AFlag.LOOP_START); + block.remove(AFlag.LOOP_END); block.setDoms(null); block.setIDom(null); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java b/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java index 10e5f3338..ec6c771c3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; @@ -45,7 +45,7 @@ public class BlockProcessingHelper { private static void markExceptionHandlers(BlockNode block) { if (!block.getInstructions().isEmpty()) { InsnNode me = block.getInstructions().get(0); - ExcHandlerAttr handlerAttr = (ExcHandlerAttr) me.getAttributes().get(AttributeType.EXC_HANDLER); + ExcHandlerAttr handlerAttr = me.get(AType.EXC_HANDLER); if (handlerAttr != null && me.getType() == InsnType.MOVE_EXCEPTION) { ExceptionHandler excHandler = handlerAttr.getHandler(); assert me.getOffset() == excHandler.getHandleOffset(); @@ -64,13 +64,13 @@ public class BlockProcessingHelper { excArg.setType(type); excHandler.setArg(excArg); - block.getAttributes().add(handlerAttr); + block.addAttr(handlerAttr); } } } private static void processExceptionHandlers(MethodNode mth, BlockNode block) { - ExcHandlerAttr handlerAttr = (ExcHandlerAttr) block.getAttributes().get(AttributeType.EXC_HANDLER); + ExcHandlerAttr handlerAttr = block.get(AType.EXC_HANDLER); if (handlerAttr != null) { ExceptionHandler excHandler = handlerAttr.getHandler(); excHandler.addBlock(block); @@ -93,7 +93,7 @@ public class BlockProcessingHelper { // if 'throw' in exception handler block have 'catch' - merge these catch blocks for (InsnNode insn : excBlock.getInstructions()) { if (insn.getType() == InsnType.THROW) { - CatchAttr catchAttr = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK); if (catchAttr != null) { TryCatchBlock handlerBlock = handlerAttr.getTryBlock(); TryCatchBlock catchBlock = catchAttr.getTryBlock(); @@ -112,7 +112,7 @@ public class BlockProcessingHelper { // if all instructions in block have same 'catch' attribute mark it as 'TryCatch' block CatchAttr commonCatchAttr = null; for (InsnNode insn : block.getInstructions()) { - CatchAttr catchAttr = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK); if (catchAttr == null) { continue; } @@ -124,7 +124,7 @@ public class BlockProcessingHelper { } } if (commonCatchAttr != null) { - block.getAttributes().add(commonCatchAttr); + block.addAttr(commonCatchAttr); // connect handler to block for (ExceptionHandler handler : commonCatchAttr.getTryBlock().getHandlers()) { connectHandler(mth, handler); @@ -135,7 +135,7 @@ public class BlockProcessingHelper { private static void connectHandler(MethodNode mth, ExceptionHandler handler) { int addr = handler.getHandleOffset(); for (BlockNode block : mth.getBasicBlocks()) { - ExcHandlerAttr bh = (ExcHandlerAttr) block.getAttributes().get(AttributeType.EXC_HANDLER); + ExcHandlerAttr bh = block.get(AType.EXC_HANDLER); if (bh != null && bh.getHandler().getHandleOffset() == addr) { handler.setHandleBlock(block); break; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java index c09217e44..55f24e6b5 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java @@ -1,9 +1,8 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.AttributesList; -import jadx.core.dex.attributes.FieldReplaceAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.FieldReplaceAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.FieldInfo; @@ -33,7 +32,7 @@ public class ClassModifier extends AbstractVisitor { if (cls.getAccessFlags().isSynthetic() && cls.getFields().isEmpty() && cls.getMethods().isEmpty()) { - cls.getAttributes().add(AttributeFlag.DONT_GENERATE); + cls.add(AFlag.DONT_GENERATE); return false; } removeSyntheticFields(cls); @@ -62,10 +61,9 @@ public class ClassModifier extends AbstractVisitor { } } if (found != 0) { - AttributesList attributes = field.getAttributes(); FieldInfo replace = new FieldInfo(parentClass, "this", parentClass.getType()); - attributes.add(new FieldReplaceAttr(replace, true)); - attributes.add(AttributeFlag.DONT_GENERATE); + field.addAttr(new FieldReplaceAttr(replace, true)); + field.add(AFlag.DONT_GENERATE); } } } @@ -121,7 +119,7 @@ public class ClassModifier extends AbstractVisitor { // remove bridge methods if (af.isBridge() && af.isSynthetic() && !isMethodUniq(cls, mth)) { // TODO add more checks before method deletion - mth.getAttributes().add(AttributeFlag.DONT_GENERATE); + mth.add(AFlag.DONT_GENERATE); } // remove synthetic constructor for inner non-static classes if (af.isSynthetic() && af.isConstructor() && mth.getBasicBlocks().size() == 2) { @@ -130,7 +128,7 @@ public class ClassModifier extends AbstractVisitor { ConstructorInsn constr = (ConstructorInsn) insns.get(0); if (constr.isThis() && mth.getArguments(false).size() >= 1) { mth.removeFirstArgument(); - mth.getAttributes().add(AttributeFlag.DONT_GENERATE); + mth.add(AFlag.DONT_GENERATE); } } } @@ -162,7 +160,7 @@ public class ClassModifier extends AbstractVisitor { && mth.getArguments(false).isEmpty()) { List bb = mth.getBasicBlocks(); if (bb == null || bb.isEmpty() || allBlocksEmpty(bb)) { - mth.getAttributes().add(AttributeFlag.DONT_GENERATE); + mth.add(AFlag.DONT_GENERATE); } } } @@ -203,7 +201,7 @@ public class ClassModifier extends AbstractVisitor { if (field.getDeclClass().getFullName().equals(thisClass)) { FieldNode fn = cls.searchField(field); if (fn != null && fn.getAccessFlags().isFinal()) { - fn.getAttributes().remove(AttributeType.FIELD_VALUE); + fn.remove(AType.FIELD_VALUE); } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java index 80b1684d0..96323ea57 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnWrapArg; @@ -30,7 +30,7 @@ public class CodeShrinker extends AbstractVisitor { } public static void shrinkMethod(MethodNode mth) { - if (mth.isNoCode() || mth.getAttributes().contains(AttributeFlag.DONT_SHRINK)) { + if (mth.isNoCode() || mth.contains(AFlag.DONT_SHRINK)) { return; } for (BlockNode block : mth.getBasicBlocks()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java index 885678a58..8ae179c72 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java @@ -24,7 +24,7 @@ import java.util.Set; public class DotGraphVisitor extends AbstractVisitor { private static final String NL = "\\l"; - private static final boolean PRINT_DOMINATORS = true; + private static final boolean PRINT_DOMINATORS = false; private final File dir; private final boolean useRegions; @@ -170,19 +170,9 @@ public class DotGraphVisitor extends AbstractVisitor { if (PRINT_DOMINATORS) { for (BlockNode c : block.getDominatesOn()) { conn.startLine(block.getId() + " -> " + c.getId() + "[color=green];"); -// } -// for (BlockNode dom : BlockUtils.bitSetToBlocks(mth, block.getDoms())) { -// if (dom == block.getIDom()) { -// conn.startLine(dom.getId() + " -> " + block.getId() + "[style=dashed, color=green];"); -//// addEdge(block, dom, "[style=dashed, color=green]"); -// } else { -//// addEdge(block, dom, "[color=green]"); -// } -// } for (BlockNode dom : BlockUtils.bitSetToBlocks(mth, block.getDomFrontier())) { conn.startLine("f_" + block.getId() + " -> f_" + dom.getId() + "[color=blue];"); -// addEdge(block, dom, "[color=blue]"); } } } @@ -195,7 +185,7 @@ public class DotGraphVisitor extends AbstractVisitor { private String attributesString(IAttributeNode block) { StringBuilder attrs = new StringBuilder(); - for (String attr : block.getAttributes().getAttributeStrings()) { + for (String attr : block.getAttributesStringsList()) { attrs.append(escape(attr)).append(NL); } return attrs.toString(); @@ -215,7 +205,7 @@ public class DotGraphVisitor extends AbstractVisitor { if (rawInsn) { StringBuilder str = new StringBuilder(); for (InsnNode insn : block.getInstructions()) { - str.append(escape(insn + " " + insn.getAttributes())); + str.append(escape(insn + " " + insn.getAttributesString())); str.append(NL); } return str.toString(); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java index bda56f144..f61b8451a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java @@ -1,9 +1,9 @@ package jadx.core.dex.visitors; import jadx.core.codegen.TypeGen; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.EnumClassAttr; -import jadx.core.dex.attributes.EnumClassAttr.EnumField; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.nodes.EnumClassAttr; +import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField; import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.MethodInfo; @@ -77,12 +77,12 @@ public class EnumVisitor extends AbstractVisitor { } EnumClassAttr attr = new EnumClassAttr(enumFields.size()); - cls.getAttributes().add(attr); + cls.addAttr(attr); if (staticMethod == null) { LOG.warn("Enum class init method not found: {}", cls); // for this broken enum puts found fields and mark as inconsistent - cls.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + cls.add(AFlag.INCONSISTENT_CODE); for (FieldNode field : enumFields) { attr.getFields().add(new EnumField(field.getName(), 0)); } @@ -166,7 +166,7 @@ public class EnumVisitor extends AbstractVisitor { } } field.setCls(innerCls); - innerCls.getAttributes().add(AttributeFlag.DONT_GENERATE); + innerCls.add(AFlag.DONT_GENERATE); } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/FallbackModeVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/FallbackModeVisitor.java index d6599e3c6..fbd8dcde4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/FallbackModeVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/FallbackModeVisitor.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.trycatch.CatchAttr; @@ -15,7 +15,7 @@ public class FallbackModeVisitor extends AbstractVisitor { } for (InsnNode insn : mth.getInstructions()) { // remove 'exception catch' for instruction which don't throw any exceptions - CatchAttr catchAttr = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK); if (catchAttr != null) { switch (insn.getType()) { case RETURN: diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlineVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlineVisitor.java index f91dc851f..e396adadd 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlineVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlineVisitor.java @@ -1,8 +1,7 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributesList; -import jadx.core.dex.attributes.MethodInlineAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.nodes.MethodInlineAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.nodes.BlockNode; @@ -23,7 +22,7 @@ public class MethodInlineVisitor extends AbstractVisitor { && mth.getBasicBlocks().size() == 2) { BlockNode block = mth.getBasicBlocks().get(1); if (block.getInstructions().isEmpty() - || block.getAttributes().contains(AttributeFlag.RETURN)) { + || block.contains(AFlag.RETURN)) { inlineMth(mth); } } @@ -48,8 +47,7 @@ public class MethodInlineVisitor extends AbstractVisitor { } private static void addInlineAttr(MethodNode mth, InsnNode insn) { - AttributesList attributes = mth.getAttributes(); - attributes.add(new MethodInlineAttr(insn)); - attributes.add(AttributeFlag.DONT_GENERATE); + mth.addAttr(new MethodInlineAttr(insn)); + mth.add(AFlag.DONT_GENERATE); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java index d26c7158d..546ad6166 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java @@ -1,7 +1,7 @@ package jadx.core.dex.visitors; import jadx.core.deobf.NameMapper; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.instructions.ConstClassNode; import jadx.core.dex.instructions.ConstStringNode; @@ -47,7 +47,7 @@ public class ModVisitor extends AbstractVisitor { checkArgsNames(mth); for (BlockNode block : mth.getBasicBlocks()) { - processExceptionHander(mth, block); + processExceptionHandler(mth, block); } } @@ -194,8 +194,8 @@ public class ModVisitor extends AbstractVisitor { } } - private static void processExceptionHander(MethodNode mth, BlockNode block) { - ExcHandlerAttr handlerAttr = (ExcHandlerAttr) block.getAttributes().get(AttributeType.EXC_HANDLER); + private static void processExceptionHandler(MethodNode mth, BlockNode block) { + ExcHandlerAttr handlerAttr = block.get(AType.EXC_HANDLER); if (handlerAttr == null) { return; } @@ -249,7 +249,7 @@ public class ModVisitor extends AbstractVisitor { */ private static void replaceInsn(BlockNode block, int i, InsnNode insn) { InsnNode prevInsn = block.getInstructions().get(i); - insn.getAttributes().addAll(prevInsn.getAttributes()); + insn.copyAttributesFrom(prevInsn); block.getInstructions().set(i, insn); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java b/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java index cdc758d3b..19ab15e79 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.ArithNode; import jadx.core.dex.instructions.ArithOp; import jadx.core.dex.instructions.InsnType; @@ -67,7 +67,7 @@ public class PrepareForCodeGen extends AbstractVisitor { && insn.getArg(0).isInsnWrap()) { InsnNode wrapInsn = ((InsnWrapArg) insn.getArg(0)).getWrapInsn(); wrapInsn.setResult(insn.getResult()); - wrapInsn.getAttributes().addAll(insn.getAttributes()); + wrapInsn.copyAttributesFrom(insn); list.set(i, wrapInsn); } } @@ -92,7 +92,7 @@ public class PrepareForCodeGen extends AbstractVisitor { InsnArg arg = arith.getArg(i); if (arg.isInsnWrap()) { InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn(); - wrapInsn.getAttributes().add(AttributeFlag.DONT_WRAP); + wrapInsn.add(AFlag.DONT_WRAP); checkInsn(wrapInsn); } } 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 8519438e4..6d0fa4f2b 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 @@ -1,7 +1,7 @@ package jadx.core.dex.visitors.regions; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.IRegion; @@ -24,7 +24,7 @@ public class CheckRegions extends AbstractVisitor { public void visit(MethodNode mth) throws JadxException { if (mth.isNoCode() || mth.getBasicBlocks().isEmpty() - || mth.getAttributes().contains(AttributeType.JADX_ERROR)) { + || mth.contains(AType.JADX_ERROR)) { return; } @@ -44,8 +44,8 @@ public class CheckRegions extends AbstractVisitor { for (BlockNode block : mth.getBasicBlocks()) { if (!blocksInRegions.contains(block) && !block.getInstructions().isEmpty() - && !block.getAttributes().contains(AttributeFlag.SKIP)) { - mth.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + && !block.contains(AFlag.SKIP)) { + mth.add(AFlag.INCONSISTENT_CODE); LOG.debug(" Missing block: {} in {}", block, mth); } } @@ -60,7 +60,7 @@ public class CheckRegions extends AbstractVisitor { BlockNode loopHeader = loop.getHeader(); if (loopHeader != null && loopHeader.getInstructions().size() != 1) { ErrorsCounter.methodError(mth, "Incorrect condition in loop: " + loopHeader); - mth.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + mth.add(AFlag.INCONSISTENT_CODE); } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java index 8b4a2e00b..7746026a0 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors.regions; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.IContainer; @@ -94,11 +94,11 @@ public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor, IContainer elsRegion = ifRegion.getElseRegion(); if (elsRegion != null) { if (elsRegion instanceof IfRegion) { - elsRegion.getAttributes().add(AttributeFlag.ELSE_IF_CHAIN); + elsRegion.add(AFlag.ELSE_IF_CHAIN); } else if (elsRegion instanceof Region) { List subBlocks = ((Region) elsRegion).getSubBlocks(); if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) { - subBlocks.get(0).getAttributes().add(AttributeFlag.ELSE_IF_CHAIN); + subBlocks.get(0).add(AFlag.ELSE_IF_CHAIN); } } } @@ -115,13 +115,13 @@ public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor, if (region == null) { return false; } - if (region.getAttributes().contains(AttributeFlag.RETURN)) { + if (region.contains(AFlag.RETURN)) { return true; } if (region instanceof IRegion) { List subBlocks = ((IRegion) region).getSubBlocks(); if (subBlocks.size() == 1 - && subBlocks.get(0).getAttributes().contains(AttributeFlag.RETURN)) { + && subBlocks.get(0).contains(AFlag.RETURN)) { return true; } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessReturnInsns.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessReturnInsns.java index db65e0678..42c059e8d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessReturnInsns.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessReturnInsns.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors.regions; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.IContainer; @@ -26,13 +26,13 @@ public class ProcessReturnInsns extends TracedRegionVisitor { return; } BlockNode block = (BlockNode) container; - if (block.getAttributes().contains(AttributeFlag.RETURN)) { + if (block.contains(AFlag.RETURN)) { List insns = block.getInstructions(); if (insns.size() == 1 && blockNotInLoop(mth, block) && noTrailInstructions(block)) { insns.remove(insns.size() - 1); - block.getAttributes().remove(AttributeFlag.RETURN); + block.remove(AFlag.RETURN); } } } @@ -68,7 +68,7 @@ public class ProcessReturnInsns extends TracedRegionVisitor { IContainer subBlock = itSubBlock.previous(); if (subBlock == curContainer) { break; - } else if (!subBlock.getAttributes().contains(AttributeFlag.RETURN) + } else if (!subBlock.contains(AFlag.RETURN) && RegionUtils.notEmpty(subBlock)) { return false; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java index a038c788d..37d226c97 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors.regions; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; @@ -47,7 +47,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { Set tryBlocks = new HashSet(); // collect all try/catch blocks for (BlockNode block : mth.getBasicBlocks()) { - CatchAttr c = (CatchAttr) block.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr c = block.get(AType.CATCH_BLOCK); if (c != null) { tryBlocks.add(c.getTryBlock()); } @@ -58,7 +58,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { BitSet bs = null; // build bitset with dominators of blocks covered with this try/catch block for (BlockNode block : mth.getBasicBlocks()) { - CatchAttr c = (CatchAttr) block.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr c = block.get(AType.CATCH_BLOCK); if (c != null && c.getTryBlock() == tb) { if (bs == null) { bs = (BitSet) block.getDoms().clone(); @@ -144,7 +144,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { region.getSubBlocks().set(i, newRegion); region.getSubBlocks().removeAll(newRegion.getSubBlocks()); - newRegion.getAttributes().add(tb.getCatchAttr()); + newRegion.addAttr(tb.getCatchAttr()); // fix parents for (IContainer cont : newRegion.getSubBlocks()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java index 287ea3f62..477f1e7f3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java @@ -1,8 +1,8 @@ package jadx.core.dex.visitors.regions; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.DeclareVariablesAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.DeclareVariablesAttr; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.IBlock; @@ -151,7 +151,7 @@ public class ProcessVariables extends AbstractVisitor { for (IRegion assignRegion : u.getAssigns()) { if (u.getArgRegion() == assignRegion && canDeclareInRegion(u, assignRegion)) { - u.getArg().getParentInsn().getAttributes().add(AttributeFlag.DECLARE_VAR); + u.getArg().getParentInsn().add(AFlag.DECLARE_VAR); it.remove(); break; } @@ -204,10 +204,10 @@ public class ProcessVariables extends AbstractVisitor { } private static void declareVar(IContainer region, RegisterArg arg) { - DeclareVariablesAttr dv = (DeclareVariablesAttr) region.getAttributes().get(AttributeType.DECLARE_VARIABLES); + DeclareVariablesAttr dv = region.get(AType.DECLARE_VARIABLES); if (dv == null) { dv = new DeclareVariablesAttr(); - region.getAttributes().add(dv); + region.addAttr(dv); } dv.addVar(arg); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java index 621f9cdda..c20f84053 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java @@ -1,11 +1,9 @@ package jadx.core.dex.visitors.regions; import jadx.core.Consts; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.AttributesList; -import jadx.core.dex.attributes.IAttribute; -import jadx.core.dex.attributes.LoopAttr; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.LoopInfo; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.SwitchNode; @@ -23,6 +21,7 @@ import jadx.core.dex.regions.LoopRegion; import jadx.core.dex.regions.Region; import jadx.core.dex.regions.SwitchRegion; import jadx.core.dex.regions.SynchronizedRegion; +import jadx.core.dex.trycatch.ExcHandlerAttr; import jadx.core.dex.trycatch.ExceptionHandler; import jadx.core.utils.BlockUtils; import jadx.core.utils.ErrorsCounter; @@ -84,17 +83,14 @@ public class RegionMaker { BlockNode next = null; boolean processed = false; - AttributesList attrs = block.getAttributes(); - int loopCount = attrs.getCount(AttributeType.LOOP); - if (loopCount != 0 && attrs.contains(AttributeFlag.LOOP_START)) { + List loops = block.getAll(AType.LOOP); + int loopCount = loops.size(); + if (loopCount != 0 && block.contains(AFlag.LOOP_START)) { if (loopCount == 1) { - LoopAttr loop = (LoopAttr) attrs.get(AttributeType.LOOP); - next = processLoop(r, loop, stack); + next = processLoop(r, loops.get(0), stack); processed = true; } else { - List loops = attrs.getAll(AttributeType.LOOP); - for (IAttribute a : loops) { - LoopAttr loop = (LoopAttr) a; + for (LoopInfo loop : loops) { if (loop.getStart() == block) { next = processLoop(r, loop, stack); processed = true; @@ -140,7 +136,7 @@ public class RegionMaker { } } - private BlockNode processLoop(IRegion curRegion, LoopAttr loop, RegionStack stack) { + private BlockNode processLoop(IRegion curRegion, LoopInfo loop, RegionStack stack) { BlockNode loopStart = loop.getStart(); Set exitBlocksSet = loop.getExitNodes(); @@ -170,7 +166,7 @@ public class RegionMaker { BlockNode bThen = null; for (BlockNode exit : exitBlocks) { - if (exit.getAttributes().contains(AttributeType.EXC_HANDLER) + if (exit.contains(AType.EXC_HANDLER) || exit.getInstructions().size() != 1) { continue; } @@ -255,19 +251,18 @@ public class RegionMaker { BlockNode bElse = ifnode.getElseBlock(); out = (bThen == loopStart ? bElse : bThen); - loopStart.getAttributes().remove(AttributeType.LOOP); + loopStart.remove(AType.LOOP); stack.addExit(loop.getEnd()); loopRegion.setBody(makeRegion(loopStart, stack)); - loopStart.getAttributes().add(loop); + loopStart.addAttr(AType.LOOP, loop); } else { if (bThen != loopBody) { loopRegion.setCondition(IfCondition.invert(loopRegion.getCondition())); } out = selectOther(loopBody, condBlock.getSuccessors()); - AttributesList outAttrs = out.getAttributes(); - if (outAttrs.contains(AttributeFlag.LOOP_START) - && outAttrs.get(AttributeType.LOOP) != loop + if (out.contains(AFlag.LOOP_START) + && !out.getAll(AType.LOOP).contains(loop) && stack.peekRegion() instanceof LoopRegion) { LoopRegion outerLoop = (LoopRegion) stack.peekRegion(); boolean notYetProcessed = outerLoop.getBody() == null; @@ -283,12 +278,12 @@ public class RegionMaker { return out; } - private BlockNode makeEndlessLoop(IRegion curRegion, RegionStack stack, LoopAttr loop, BlockNode loopStart) { + private BlockNode makeEndlessLoop(IRegion curRegion, RegionStack stack, LoopInfo loop, BlockNode loopStart) { LoopRegion loopRegion; loopRegion = new LoopRegion(curRegion, null, false); curRegion.getSubBlocks().add(loopRegion); - loopStart.getAttributes().remove(AttributeType.LOOP); + loopStart.remove(AType.LOOP); stack.push(loopRegion); Region body = makeRegion(loopStart, stack); if (!RegionUtils.isRegionContainsBlock(body, loop.getEnd())) { @@ -296,7 +291,7 @@ public class RegionMaker { } loopRegion.setBody(body); stack.pop(); - loopStart.getAttributes().add(loop); + loopStart.addAttr(AType.LOOP, loop); BlockNode next = BlockUtils.getNextBlock(loop.getEnd()); return RegionUtils.isRegionContainsBlock(body, next) ? null : next; @@ -308,7 +303,7 @@ public class RegionMaker { while (exit != null) { if (prev != null && isPathExists(loopExit, exit)) { // found cross - if (!exit.getAttributes().contains(AttributeFlag.RETURN)) { + if (!exit.contains(AFlag.RETURN)) { prev.getInstructions().add(new InsnNode(InsnType.BREAK, 0)); stack.addExit(exit); } @@ -399,7 +394,7 @@ public class RegionMaker { } private BlockNode processIf(IRegion currentRegion, BlockNode block, IfNode ifnode, RegionStack stack) { - if (block.getAttributes().contains(AttributeFlag.SKIP)) { + if (block.contains(AFlag.SKIP)) { // block already included in other 'if' region return ifnode.getThenBlock(); } @@ -526,7 +521,7 @@ public class RegionMaker { if (merged != null) { merged.add(nestedIfBlock); } - nestedIfBlock.getAttributes().add(AttributeFlag.SKIP); + nestedIfBlock.add(AFlag.SKIP); BlockNode blockToNestedIfBlock = BlockUtils.getNextBlockToPath(ifBlock, nestedIfBlock); skipSimplePath(BlockUtils.selectOther(blockToNestedIfBlock, ifBlock.getCleanSuccessors())); @@ -555,7 +550,7 @@ public class RegionMaker { } private static BlockNode getIfNode(BlockNode block) { - if (block != null && !block.getAttributes().contains(AttributeType.LOOP)) { + if (block != null && !block.contains(AType.LOOP)) { List insns = block.getInstructions(); if (insns.size() == 1 && insns.get(0).getType() == InsnType.IF) { return block; @@ -699,15 +694,15 @@ public class RegionMaker { // TODO add blocks common for several handlers to some region handler.setHandlerRegion(makeRegion(start, stack)); - IAttribute excHandlerAttr = start.getAttributes().get(AttributeType.EXC_HANDLER); - handler.getHandlerRegion().getAttributes().add(excHandlerAttr); + ExcHandlerAttr excHandlerAttr = start.get(AType.EXC_HANDLER); + handler.getHandlerRegion().addAttr(excHandlerAttr); } private void skipSimplePath(BlockNode block) { while (block != null && block.getCleanSuccessors().size() < 2 && block.getPredecessors().size() == 1) { - block.getAttributes().add(AttributeFlag.SKIP); + block.add(AFlag.SKIP); block = BlockUtils.getNextBlock(block); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java index b22a5ad60..287fbc342 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors.regions; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; @@ -22,7 +22,7 @@ public class TernaryMod { } static void makeTernaryInsn(MethodNode mth, IfRegion ifRegion) { - if (ifRegion.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) { + if (ifRegion.contains(AFlag.ELSE_IF_CHAIN)) { return; } IContainer thenRegion = ifRegion.getThenRegion(); @@ -65,8 +65,8 @@ public class TernaryMod { && t.getType() == InsnType.RETURN && e.getType() == InsnType.RETURN) { InsnList.remove(tb, t); InsnList.remove(eb, e); - tb.getAttributes().remove(AttributeFlag.RETURN); - eb.getAttributes().remove(AttributeFlag.RETURN); + tb.remove(AFlag.RETURN); + eb.remove(AFlag.RETURN); TernaryInsn ternInsn = new TernaryInsn(ifRegion.getCondition(), null, t.getArg(0), e.getArg(0)); InsnNode retInsn = new InsnNode(InsnType.RETURN, 1); @@ -74,7 +74,7 @@ public class TernaryMod { header.getInstructions().clear(); header.getInstructions().add(retInsn); - header.getAttributes().add(AttributeFlag.RETURN); + header.add(AFlag.RETURN); ifRegion.setTernRegion(new TernaryRegion(ifRegion, header)); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/EliminatePhiNodes.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/EliminatePhiNodes.java index 7305bb8df..6737b745e 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/EliminatePhiNodes.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/EliminatePhiNodes.java @@ -1,7 +1,7 @@ package jadx.core.dex.visitors.ssa; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.PhiListAttr; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.PhiListAttr; import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.nodes.BlockNode; @@ -71,7 +71,7 @@ public class EliminatePhiNodes extends AbstractVisitor { private static void removePhiInstructions(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { - PhiListAttr phiList = (PhiListAttr) block.getAttributes().get(AttributeType.PHI_LIST); + PhiListAttr phiList = block.get(AType.PHI_LIST); if (phiList == null) { continue; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/SSATransform.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/SSATransform.java index 7deb2a10a..e846c713e 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/SSATransform.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ssa/SSATransform.java @@ -1,7 +1,7 @@ package jadx.core.dex.visitors.ssa; -import jadx.core.dex.attributes.AttributeType; -import jadx.core.dex.attributes.PhiListAttr; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.PhiListAttr; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.args.InsnArg; @@ -72,10 +72,10 @@ public class SSATransform extends AbstractVisitor { } private void addPhi(BlockNode block, int regNum) { - PhiListAttr phiList = (PhiListAttr) block.getAttributes().get(AttributeType.PHI_LIST); + PhiListAttr phiList = block.get(AType.PHI_LIST); if (phiList == null) { phiList = new PhiListAttr(); - block.getAttributes().add(phiList); + block.addAttr(phiList); } PhiInsn phiInsn = new PhiInsn(regNum, block.getPredecessors().size()); phiList.getList().add(phiInsn); @@ -118,7 +118,7 @@ public class SSATransform extends AbstractVisitor { } } for (BlockNode s : block.getSuccessors()) { - PhiListAttr phiList = (PhiListAttr) s.getAttributes().get(AttributeType.PHI_LIST); + PhiListAttr phiList = s.get(AType.PHI_LIST); if (phiList != null) { int j = s.getPredecessors().indexOf(block); if (j == -1) { @@ -154,7 +154,7 @@ public class SSATransform extends AbstractVisitor { } } for (BlockNode block : mth.getBasicBlocks()) { - PhiListAttr phiList = (PhiListAttr) block.getAttributes().get(AttributeType.PHI_LIST); + PhiListAttr phiList = block.get(AType.PHI_LIST); if (phiList == null) { continue; } @@ -194,7 +194,7 @@ public class SSATransform extends AbstractVisitor { return; } for (BlockNode block : mth.getBasicBlocks()) { - PhiListAttr phiList = (PhiListAttr) block.getAttributes().get(AttributeType.PHI_LIST); + PhiListAttr phiList = block.get(AType.PHI_LIST); if (phiList == null) { continue; } @@ -208,7 +208,7 @@ public class SSATransform extends AbstractVisitor { } } if (list.isEmpty()) { - block.getAttributes().remove(AttributeType.PHI_LIST); + block.remove(AType.PHI_LIST); } } insnToRemove.clear(); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java index e7343ee5c..d36271812 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java @@ -1,6 +1,6 @@ package jadx.core.dex.visitors.typeinference; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; @@ -61,7 +61,7 @@ public class TypeInference extends AbstractVisitor { if (useType.isTypeKnown()) { type = ArgType.merge(type, useType); } - if (arg.getParentInsn().getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) { + if (arg.getParentInsn().contains(AFlag.INCONSISTENT_CODE)) { throw new JadxRuntimeException("not removed arg"); } } diff --git a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java index 0f25a1c6d..8e5f5fd90 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -1,6 +1,6 @@ package jadx.core.utils; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AType; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.InsnNode; @@ -60,7 +60,7 @@ public class BlockUtils { private static List cleanBlockList(List list) { List ret = new ArrayList(list.size()); for (BlockNode block : list) { - if (!block.getAttributes().contains(AttributeType.EXC_HANDLER)) { + if (!block.contains(AType.EXC_HANDLER)) { ret.add(block); } } @@ -83,7 +83,7 @@ public class BlockUtils { public static void cleanBitSet(MethodNode mth, BitSet bs) { for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { BlockNode block = mth.getBasicBlocks().get(i); - if (block.getAttributes().contains(AttributeType.EXC_HANDLER)) { + if (block.contains(AType.EXC_HANDLER)) { bs.clear(i); } } diff --git a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java index 671bb4d97..3a5ef2ee5 100644 --- a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java +++ b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java @@ -1,8 +1,8 @@ package jadx.core.utils; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.IAttributeNode; -import jadx.core.dex.attributes.JadxErrorAttr; +import jadx.core.dex.attributes.nodes.JadxErrorAttr; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.MethodNode; @@ -39,9 +39,9 @@ public class ErrorsCounter { } else { LOG.error(msg, e); } - node.getAttributes().add(new JadxErrorAttr(e)); + node.addAttr(new JadxErrorAttr(e)); } else { - node.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + node.add(AFlag.INCONSISTENT_CODE); LOG.error(msg); } } diff --git a/jadx-core/src/main/java/jadx/core/utils/InstructionRemover.java b/jadx-core/src/main/java/jadx/core/utils/InstructionRemover.java index ccb846d48..7f9bf0c1f 100644 --- a/jadx-core/src/main/java/jadx/core/utils/InstructionRemover.java +++ b/jadx-core/src/main/java/jadx/core/utils/InstructionRemover.java @@ -1,7 +1,7 @@ package jadx.core.utils; import jadx.core.Consts; -import jadx.core.dex.attributes.AttributeFlag; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.SSAVar; @@ -73,7 +73,7 @@ public class InstructionRemover { } } } - insn.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + insn.add(AFlag.INCONSISTENT_CODE); } // Don't use 'insns.removeAll(toRemove)' because it will remove instructions by content diff --git a/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java b/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java index dd5add0a1..3728fc9a8 100644 --- a/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java @@ -1,7 +1,7 @@ package jadx.core.utils; -import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.AttributeType; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; @@ -22,7 +22,7 @@ public class RegionUtils { if (container instanceof BlockNode) { BlockNode block = (BlockNode) container; return block.getSuccessors().size() != 0 - && !block.getAttributes().contains(AttributeFlag.RETURN); + && !block.contains(AFlag.RETURN); } else if (container instanceof IRegion) { IRegion region = (IRegion) container; List blocks = region.getSubBlocks(); @@ -91,7 +91,7 @@ public class RegionUtils { // process sub blocks for (IContainer b : r.getSubBlocks()) { // process try block - CatchAttr cb = (CatchAttr) b.getAttributes().get(AttributeType.CATCH_BLOCK); + CatchAttr cb = b.get(AType.CATCH_BLOCK); if (cb != null && (b instanceof IRegion)) { TryCatchBlock tb = cb.getTryBlock(); for (ExceptionHandler eh : tb.getHandlers()) { @@ -128,7 +128,7 @@ public class RegionUtils { IRegion parent = region.getParent(); while (container != parent) { if (parent == null) { - if (region.getAttributes().contains(AttributeType.EXC_HANDLER)) { + if (region.contains(AType.EXC_HANDLER)) { return isRegionContainsExcHandlerRegion(container, region); } return false; diff --git a/jadx-core/src/main/java/jadx/core/utils/exceptions/JadxRuntimeException.java b/jadx-core/src/main/java/jadx/core/utils/exceptions/JadxRuntimeException.java index a36f17864..ced9878ae 100644 --- a/jadx-core/src/main/java/jadx/core/utils/exceptions/JadxRuntimeException.java +++ b/jadx-core/src/main/java/jadx/core/utils/exceptions/JadxRuntimeException.java @@ -7,4 +7,8 @@ public class JadxRuntimeException extends RuntimeException { public JadxRuntimeException(String message) { super(message); } + + public JadxRuntimeException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/jadx-core/src/main/java/jadx/core/utils/files/InputFile.java b/jadx-core/src/main/java/jadx/core/utils/files/InputFile.java index 74531abb7..8cb22ad19 100644 --- a/jadx-core/src/main/java/jadx/core/utils/files/InputFile.java +++ b/jadx-core/src/main/java/jadx/core/utils/files/InputFile.java @@ -23,43 +23,54 @@ public class InputFile { private final Dex dexBuf; public InputFile(File file) throws IOException, DecodeException { - this.file = file; if (!file.exists()) { throw new IOException("File not found: " + file.getAbsolutePath()); } - String fileName = file.getName(); + this.file = file; + this.dexBuf = loadDexBuffer(); + } + private Dex loadDexBuffer() throws IOException, DecodeException { + String fileName = file.getName(); if (fileName.endsWith(".dex")) { - this.dexBuf = new Dex(file); - } else if (fileName.endsWith(".apk")) { - this.dexBuf = new Dex(openDexFromApk(file)); - } else if (fileName.endsWith(".class") || fileName.endsWith(".jar")) { + return new Dex(file); + } + if (fileName.endsWith(".apk")) { + byte[] data = openDexFromZip(file); + if (data == null) { + throw new JadxRuntimeException("File 'classes.dex' not found in file: " + file); + } + return new Dex(data); + } + if (fileName.endsWith(".jar")) { + // check if jar contains 'classes.dex' + byte[] data = openDexFromZip(file); + if (data != null) { + return new Dex(data); + } try { LOG.info("converting to dex: {} ...", fileName); JavaToDex j2d = new JavaToDex(); byte[] ba = j2d.convert(file.getAbsolutePath()); if (ba.length == 0) { - throw new JadxException( - j2d.isError() ? j2d.getDxErrors() : "Empty dx output"); + throw new JadxException(j2d.isError() ? j2d.getDxErrors() : "Empty dx output"); } else if (j2d.isError()) { LOG.warn("dx message: " + j2d.getDxErrors()); } - this.dexBuf = new Dex(ba); + return new Dex(ba); } catch (Throwable e) { - throw new DecodeException( - "java class to dex conversion error:\n " + e.getMessage(), e); + throw new DecodeException("java class to dex conversion error:\n " + e.getMessage(), e); } - } else { - throw new DecodeException("Unsupported input file: " + file); } + throw new DecodeException("Unsupported input file format: " + file); } - private byte[] openDexFromApk(File file) throws IOException { + private byte[] openDexFromZip(File file) throws IOException { ZipFile zf = new ZipFile(file); ZipEntry dex = zf.getEntry("classes.dex"); if (dex == null) { zf.close(); - throw new JadxRuntimeException("File 'classes.dex' not found in apk file: " + file); + return null; } ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); InputStream in = null; diff --git a/jadx-core/src/test/groovy/jadx/tests/TestAPI.groovy b/jadx-core/src/test/groovy/jadx/tests/TestAPI.groovy new file mode 100644 index 000000000..8ba1203e7 --- /dev/null +++ b/jadx-core/src/test/groovy/jadx/tests/TestAPI.groovy @@ -0,0 +1,86 @@ +package jadx.tests + +import jadx.api.Decompiler +import jadx.api.IJadxArgs +import jadx.core.dex.nodes.MethodNode +import jadx.core.utils.ErrorsCounter +import jadx.core.utils.exceptions.JadxException +import jadx.core.utils.exceptions.JadxRuntimeException +import spock.lang.Specification + +class TestAPI extends Specification { + + def "no loaded files"() { + setup: + def d = new Decompiler() + when: + def classes = d.getClasses() + def packages = d.getPackages() + then: + notThrown(NullPointerException) + classes?.isEmpty() + packages?.isEmpty() + } + + def "save with no loaded files"() { + when: + new Decompiler().save() + then: + def e = thrown(JadxRuntimeException) + e.message == "No loaded files" + } + + def "load empty files list"() { + when: + new Decompiler().loadFiles(Collections.emptyList()) + then: + def e = thrown(JadxException) + e.message == "Empty file list" + } + + def "load null"() { + when: + new Decompiler().loadFile(null) + then: + thrown(NullPointerException) + } + + def "load missing file"() { + when: + new Decompiler().loadFile(new File("_.dex")) + then: + def e = thrown(JadxException) + e.message == "Error load file: _.dex" + e.cause.class == IOException + } + + def "pass decompiler args"() { + setup: + def args = Mock(IJadxArgs) + when: + new Decompiler(args) + then: + noExceptionThrown() + } + + def "get errors count for new decompiler"() { + expect: + new Decompiler().getErrorsCount() == 0 + } + + def "get errors count after one more init"() { + setup: + new Decompiler() + def mth = Mock(MethodNode) + when: + ErrorsCounter.methodError(mth, "") + def d = new Decompiler() + then: + d.getErrorsCount() == 0 + } + + def "decompiler toString()"() { + expect: + new Decompiler().toString() == "jadx decompiler" + } +} diff --git a/jadx-core/src/test/groovy/jadx/tests/TestAttributeStorage.groovy b/jadx-core/src/test/groovy/jadx/tests/TestAttributeStorage.groovy new file mode 100644 index 000000000..89204f9e7 --- /dev/null +++ b/jadx-core/src/test/groovy/jadx/tests/TestAttributeStorage.groovy @@ -0,0 +1,82 @@ +package jadx.tests + +import jadx.core.dex.attributes.AType +import jadx.core.dex.attributes.AttributeStorage +import jadx.core.dex.attributes.IAttribute +import spock.lang.Specification + +import static jadx.core.dex.attributes.AFlag.SYNTHETIC + +class TestAttributeStorage extends Specification { + + AttributeStorage storage + + def setup() { + storage = new AttributeStorage() + } + + def "add flag"() { + when: + storage.add(SYNTHETIC) + then: + storage.contains(SYNTHETIC) + } + + def "remove flag"() { + setup: + storage.add(SYNTHETIC) + when: + storage.remove(SYNTHETIC) + then: + !storage.contains(SYNTHETIC) + } + + def TEST = new AType() + class TestAttr implements IAttribute { + AType getType() { TEST } + } + + def "add attribute"() { + setup: + def attr = new TestAttr() + when: + storage.add(attr) + then: + storage.contains(TEST) + storage.get(TEST) == attr + } + + def "remove attribute"() { + setup: + def attr = new TestAttr() + storage.add(attr) + when: + storage.remove(attr) + then: + !storage.contains(TEST) + storage.get(TEST) == null + } + + def "remove attribute other"() { + setup: + def attr = new TestAttr() + storage.add(attr) + when: + storage.remove(new TestAttr()) + then: + storage.contains(TEST) + storage.get(TEST) == attr + } + + def "clear"() { + setup: + storage.add(SYNTHETIC) + storage.add(new TestAttr()) + when: + storage.clear() + then: + !storage.contains(SYNTHETIC) + !storage.contains(TEST) + } + +} diff --git a/jadx-core/src/test/groovy/jadx/tests/TestSignatureParser.groovy b/jadx-core/src/test/groovy/jadx/tests/TestSignatureParser.groovy index 9e67b492d..d841cbc29 100644 --- a/jadx-core/src/test/groovy/jadx/tests/TestSignatureParser.groovy +++ b/jadx-core/src/test/groovy/jadx/tests/TestSignatureParser.groovy @@ -1,4 +1,5 @@ package jadx.tests + import jadx.core.dex.instructions.args.ArgType import jadx.core.dex.nodes.parser.SignatureParser import spock.lang.Specification diff --git a/jadx-core/src/test/java/jadx/core/dex/nodes/parser/TestSignatureParser.java b/jadx-core/src/test/java/jadx/core/dex/nodes/parser/TestSignatureParser.java deleted file mode 100644 index 631007b60..000000000 --- a/jadx-core/src/test/java/jadx/core/dex/nodes/parser/TestSignatureParser.java +++ /dev/null @@ -1,110 +0,0 @@ -package jadx.core.dex.nodes.parser; - -import jadx.core.dex.instructions.args.ArgType; - -import java.util.List; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class TestSignatureParser { - - private SignatureParser p(String str) { - return new SignatureParser(str); - } - - @Test - public void testType() { - assertEquals(p("").consumeType(), null); - assertEquals(p("I").consumeType(), ArgType.INT); - assertEquals(p("[I").consumeType(), ArgType.array(ArgType.INT)); - assertEquals(p("Ljava/lang/Object;").consumeType(), ArgType.OBJECT); - assertEquals(p("[Ljava/lang/Object;").consumeType(), ArgType.array(ArgType.OBJECT)); - assertEquals(p("[[I").consumeType(), ArgType.array(ArgType.array(ArgType.INT))); - } - - @Test - public void testType2() { - assertEquals(p("TD;").consumeType(), ArgType.genericType("D")); - } - - @Test - public void testGenericType() { - assertEquals(p("La;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.genericType("V"), ArgType.object("b")})); - - assertEquals(p("La;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ - ArgType.generic("Lb;", new ArgType[]{ - ArgType.object("Lc;")})}) - ); - } - - @Test - public void testGenericInnerType() { - assertEquals(p("La.c;").consumeType(), - ArgType.genericInner(ArgType.generic("La;", new ArgType[]{ArgType.genericType("D")}), "c", null)); - - assertEquals(p("La.c;").consumeType(), - ArgType.genericInner(ArgType.generic("La;", new ArgType[]{ArgType.object("Lb;")}), - "c", new ArgType[]{ArgType.genericType("V")}) - ); - - assertEquals(p("La.LinkedHashIterator;>;").consumeType().getObject(), - "a$LinkedHashIterator"); - - } - - @Test - public void testWildCards() { - assertEquals(p("La<*>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard()})); - - assertEquals(p("La<+Lb;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(ArgType.object("b"), 1)})); - - assertEquals(p("La<-Lb;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(ArgType.object("b"), -1)})); - - assertEquals(p("La<+TV;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(ArgType.genericType("V"), 1)})); - - assertEquals(p("La<-TV;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(ArgType.genericType("V"), -1)})); - } - - @Test - public void testWildCards2() { - assertEquals(p("La<*>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard()})); - - assertEquals(p("La<**>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(), ArgType.wildcard()})); - - assertEquals(p("La<*Lb;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(), ArgType.object("b")})); - - assertEquals(p("La<*TV;>;").consumeType(), - ArgType.generic("La;", new ArgType[]{ArgType.wildcard(), ArgType.genericType("V")})); - } - - @Test - public void testGenericMap() { - assertEquals(p("").consumeGenericMap().toString(), - "{T=[]}"); - - assertEquals(p("").consumeGenericMap().toString(), - "{K=[], LongGenericType=[]}"); - - assertEquals(p("").consumeGenericMap().toString(), - "{ResultT=[java.lang.Exception]}"); - } - - @Test - public void testMethodsArgs() { - List argTypes = p("(Ljava/util/List<*>;)V").consumeMethodArgs(); - assertEquals(argTypes.size(), 1); - assertEquals(argTypes.get(0), ArgType.generic("Ljava/util/List;", new ArgType[]{ArgType.wildcard()})); - } -} diff --git a/jadx-core/src/test/java/jadx/tests/functional/StringUtilsTest.java b/jadx-core/src/test/java/jadx/tests/functional/StringUtilsTest.java deleted file mode 100644 index 71689b647..000000000 --- a/jadx-core/src/test/java/jadx/tests/functional/StringUtilsTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package jadx.tests.functional; - -import jadx.core.utils.StringUtils; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class StringUtilsTest { - - @Test - public void testUnescape() { - unescapeTest("\n", "\\n"); - unescapeTest("\t", "\\t"); - unescapeTest("\r", "\\r"); - unescapeTest("\b", "\\b"); - unescapeTest("\f", "\\f"); - unescapeTest("\\", "\\\\"); - unescapeTest("\"", "\\\""); - unescapeTest("'", "'"); - - unescapeTest("\u1234", "\\u1234"); - - unescapeCharTest('\'', "'\\\''"); - } - - private void unescapeTest(String input, String expected) { - assertEquals("\"" + expected + "\"", StringUtils.unescapeString(input)); - } - - private void unescapeCharTest(char input, String expected) { - assertEquals(expected, StringUtils.unescapeChar(input)); - } - -} diff --git a/jadx-core/src/test/java/jadx/tests/internal/debuginfo/TestLineNumbers.java b/jadx-core/src/test/java/jadx/tests/internal/debuginfo/TestLineNumbers.java index 8eb3e61b3..c9c46eccd 100644 --- a/jadx-core/src/test/java/jadx/tests/internal/debuginfo/TestLineNumbers.java +++ b/jadx-core/src/test/java/jadx/tests/internal/debuginfo/TestLineNumbers.java @@ -2,7 +2,7 @@ package jadx.tests.internal.debuginfo; import jadx.api.InternalJadxTest; import jadx.core.codegen.CodeWriter; -import jadx.core.dex.attributes.LineAttrNode; +import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.MethodNode; diff --git a/jadx-core/src/test/java/jadx/tests/internal/trycatch/TestTryCatch3.java b/jadx-core/src/test/java/jadx/tests/internal/trycatch/TestTryCatch3.java new file mode 100644 index 000000000..8e2025739 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/internal/trycatch/TestTryCatch3.java @@ -0,0 +1,43 @@ +package jadx.tests.internal.trycatch; + +import jadx.api.InternalJadxTest; +import jadx.core.dex.nodes.ClassNode; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; + +public class TestTryCatch3 extends InternalJadxTest { + + public static class TestCls { + private final static Object obj = new Object(); + private boolean mDiscovering; + + private boolean test(Object obj) { + this.mDiscovering = false; + try { + exc(obj); + } catch (Exception e) { + e.toString(); + } finally { + mDiscovering = true; + } + return mDiscovering; + } + + private void exc(Object obj) throws Exception { + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + System.out.println(code); + + assertThat(code, containsString("try {")); + assertThat(code, containsString("exc(obj);")); + assertThat(code, containsString("} catch (Exception e) {")); + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index 5901f9ab5..c5ac4631b 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -5,10 +5,10 @@ import jadx.api.IJadxArgs; import jadx.api.JavaClass; import jadx.api.JavaPackage; import jadx.core.utils.exceptions.DecodeException; +import jadx.core.utils.exceptions.JadxException; import javax.swing.ProgressMonitor; import java.io.File; -import java.io.IOException; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; @@ -29,20 +29,21 @@ public class JadxWrapper { this.openFile = file; try { this.decompiler.loadFile(file); - } catch (IOException e) { - LOG.error("Error open file: " + file, e); } catch (DecodeException e) { LOG.error("Error decode file: " + file, e); + } catch (JadxException e) { + LOG.error("Error open file: " + file, e); } } + public void saveAll(final File dir, final ProgressMonitor progressMonitor) { Runnable save = new Runnable() { @Override public void run() { try { decompiler.setOutputDir(dir); - ThreadPoolExecutor ex = decompiler.getSaveExecutor(); + ThreadPoolExecutor ex = (ThreadPoolExecutor) decompiler.getSaveExecutor(); ex.shutdown(); while (ex.isTerminating()) { long total = ex.getTaskCount(); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java index bed12fa1b..7a07f1871 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java @@ -37,12 +37,16 @@ class CodePanel extends JPanel { add(scrollPane); KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK); - Utils.addKeyBinding(codeArea, key, "SearchAction", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - searchBar.toggle(); - } - }); + Utils.addKeyBinding(codeArea, key, "SearchAction", new SearchAction()); + } + + private class SearchAction extends AbstractAction { + private static final long serialVersionUID = 8650568214755387093L; + + @Override + public void actionPerformed(ActionEvent e) { + searchBar.toggle(); + } } TabbedPane getCodePanel() {