core: refactor attribute storage
This commit is contained in:
+3
-2
@@ -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 {
|
||||
|
||||
@@ -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<File> files) throws IOException, DecodeException {
|
||||
public void loadFiles(List<File> 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<JavaClass> getClasses() {
|
||||
if (root == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (classes == null) {
|
||||
List<ClassNode> classNodeList = root.getClasses(false);
|
||||
List<JavaClass> clsList = new ArrayList<JavaClass>(classNodeList.size());
|
||||
@@ -137,8 +151,12 @@ public final class Decompiler {
|
||||
}
|
||||
|
||||
public List<JavaPackage> getPackages() {
|
||||
List<JavaClass> classList = getClasses();
|
||||
if (classList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Map<String, List<JavaClass>> map = new HashMap<String, List<JavaClass>>();
|
||||
for (JavaClass javaClass : getClasses()) {
|
||||
for (JavaClass javaClass : classList) {
|
||||
String pkg = javaClass.getPackage();
|
||||
List<JavaClass> 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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<JavaClass> list = new ArrayList<JavaClass>(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<JavaField> flds = new ArrayList<JavaField>(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<JavaMethod> mths = new ArrayList<JavaMethod>(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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<EnumField> 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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Flags> 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('(');
|
||||
}
|
||||
|
||||
@@ -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<RegisterArg> 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<RegisterArg> args) {
|
||||
MethodParameters paramsAnnotation =
|
||||
(MethodParameters) mth.getAttributes().get(AttributeType.ANNOTATION_MTH_PARAMETERS);
|
||||
mth.get(AType.ANNOTATION_MTH_PARAMETERS);
|
||||
|
||||
int i = 0;
|
||||
for (Iterator<RegisterArg> 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<InsnNode> 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<IAttribute> catchAttrs = attrs.getAll(AttributeType.CATCH_BLOCK);
|
||||
for (IAttribute catchAttr : catchAttrs) {
|
||||
CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK);
|
||||
if (catchAttr != null) {
|
||||
code.add("\t " + catchAttr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IContainer> 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<InsnNode> 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()) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package jadx.core.dex.attributes;
|
||||
|
||||
public enum AttributeFlag {
|
||||
public enum AFlag {
|
||||
TRY_ENTER,
|
||||
TRY_LEAVE,
|
||||
|
||||
@@ -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 <T> attribute class implementation
|
||||
*/
|
||||
public class AType<T extends IAttribute> {
|
||||
|
||||
public static final AType<AttrList<JumpInfo>> JUMP = new AType<AttrList<JumpInfo>>();
|
||||
public static final AType<AttrList<LoopInfo>> LOOP = new AType<AttrList<LoopInfo>>();
|
||||
|
||||
public static final AType<ExcHandlerAttr> EXC_HANDLER = new AType<ExcHandlerAttr>();
|
||||
public static final AType<CatchAttr> CATCH_BLOCK = new AType<CatchAttr>();
|
||||
public static final AType<SplitterBlockAttr> SPLITTER_BLOCK = new AType<SplitterBlockAttr>();
|
||||
public static final AType<ForceReturnAttr> FORCE_RETURN = new AType<ForceReturnAttr>();
|
||||
public static final AType<FieldValueAttr> FIELD_VALUE = new AType<FieldValueAttr>();
|
||||
public static final AType<FieldReplaceAttr> FIELD_REPLACE = new AType<FieldReplaceAttr>();
|
||||
public static final AType<JadxErrorAttr> JADX_ERROR = new AType<JadxErrorAttr>();
|
||||
public static final AType<MethodInlineAttr> METHOD_INLINE = new AType<MethodInlineAttr>();
|
||||
public static final AType<EnumClassAttr> ENUM_CLASS = new AType<EnumClassAttr>();
|
||||
public static final AType<AnnotationsList> ANNOTATION_LIST = new AType<AnnotationsList>();
|
||||
public static final AType<MethodParameters> ANNOTATION_MTH_PARAMETERS = new AType<MethodParameters>();
|
||||
public static final AType<PhiListAttr> PHI_LIST = new AType<PhiListAttr>();
|
||||
public static final AType<SourceFileAttr> SOURCE_FILE = new AType<SourceFileAttr>();
|
||||
public static final AType<DeclareVariablesAttr> DECLARE_VARIABLES = new AType<DeclareVariablesAttr>();
|
||||
}
|
||||
@@ -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<T> implements IAttribute {
|
||||
|
||||
private final AType<AttrList<T>> type;
|
||||
private final List<T> list = new LinkedList<T>();
|
||||
|
||||
public AttrList(AType<AttrList<T>> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public List<T> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AType<AttrList<T>> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Utils.listToString(list);
|
||||
}
|
||||
}
|
||||
@@ -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 <T> void addAttr(AType<AttrList<T>> 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 <T extends IAttribute> boolean contains(AType<T> type) {
|
||||
return storage.contains(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAttribute> T get(AType<T> type) {
|
||||
return storage.get(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation(String cls) {
|
||||
return storage.getAnnotation(cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getAll(AType<AttrList<T>> type) {
|
||||
return storage.getAll(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(AFlag flag) {
|
||||
storage.remove(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAttribute> void remove(AType<T> type) {
|
||||
storage.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttr(IAttribute attr) {
|
||||
storage.remove(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAttributes() {
|
||||
storage.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttributesStringsList() {
|
||||
return storage.getAttributeStrings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributesString() {
|
||||
return storage.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AFlag> flags;
|
||||
private final Map<AType<?>, IAttribute> attributes;
|
||||
|
||||
public AttributeStorage() {
|
||||
flags = EnumSet.noneOf(AFlag.class);
|
||||
attributes = new HashMap<AType<?>, IAttribute>(2);
|
||||
}
|
||||
|
||||
public void add(AFlag flag) {
|
||||
flags.add(flag);
|
||||
}
|
||||
|
||||
public void add(IAttribute attr) {
|
||||
attributes.put(attr.getType(), attr);
|
||||
}
|
||||
|
||||
public <T> void add(AType<AttrList<T>> type, T obj) {
|
||||
AttrList<T> list = get(type);
|
||||
if (list == null) {
|
||||
list = new AttrList<T>(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 <T extends IAttribute> boolean contains(AType<T> type) {
|
||||
return attributes.containsKey(type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IAttribute> T get(AType<T> 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 <T> List<T> getAll(AType<AttrList<T>> type) {
|
||||
AttrList<T> attrList = get(type);
|
||||
if (attrList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return attrList.getList();
|
||||
}
|
||||
|
||||
public void remove(AFlag flag) {
|
||||
flags.remove(flag);
|
||||
}
|
||||
|
||||
public <T extends IAttribute> void remove(AType<T> 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<String> getAttributeStrings() {
|
||||
int size = flags.size() + attributes.size() + attributes.size();
|
||||
if (size == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> list = new ArrayList<String>(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<String> list = getAttributeStrings();
|
||||
if (list.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return "A:{" + Utils.listToString(list) + "}";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<AttributeFlag> flags;
|
||||
private final Map<AttributeType, IAttribute> uniqAttr;
|
||||
private final List<IAttribute> attributes;
|
||||
private final int[] attrCount;
|
||||
|
||||
public AttributesList() {
|
||||
flags = EnumSet.noneOf(AttributeFlag.class);
|
||||
uniqAttr = new EnumMap<AttributeType, IAttribute>(AttributeType.class);
|
||||
attributes = new LinkedList<IAttribute>();
|
||||
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<IAttribute> getAll(AttributeType type) {
|
||||
assert type.notUniq();
|
||||
|
||||
int count = getMultiCountInternal(type);
|
||||
if (count == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<IAttribute> attrs = new ArrayList<IAttribute>(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<IAttribute> 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<IAttribute> 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<String> getAttributeStrings() {
|
||||
int size = flags.size() + uniqAttr.size() + attributes.size();
|
||||
if (size == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> list = new ArrayList<String>(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<String> list = getAttributeStrings();
|
||||
if (list.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return "A:{" + Utils.listToString(list) + "}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <T extends IAttribute> boolean contains(AType<T> type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAttribute> T get(AType<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation(String cls) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getAll(AType<AttrList<T>> type) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(AFlag flag) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAttribute> void remove(AType<T> type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(IAttribute attr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttributeStrings() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,6 @@ package jadx.core.dex.attributes;
|
||||
|
||||
public interface IAttribute {
|
||||
|
||||
AttributeType getType();
|
||||
AType<?> getType();
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
<T> void addAttr(AType<AttrList<T>> type, T obj);
|
||||
|
||||
void copyAttributesFrom(AttrNode attrNode);
|
||||
|
||||
boolean contains(AFlag flag);
|
||||
|
||||
<T extends IAttribute> boolean contains(AType<T> type);
|
||||
|
||||
<T extends IAttribute> T get(AType<T> type);
|
||||
|
||||
Annotation getAnnotation(String cls);
|
||||
|
||||
<T> List<T> getAll(AType<AttrList<T>> type);
|
||||
|
||||
void remove(AFlag flag);
|
||||
|
||||
<T extends IAttribute> void remove(AType<T> type);
|
||||
|
||||
void removeAttr(IAttribute attr);
|
||||
|
||||
void clearAttributes();
|
||||
|
||||
List<String> getAttributesStringsList();
|
||||
|
||||
String getAttributesString();
|
||||
}
|
||||
|
||||
@@ -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<AnnotationsList> getType() {
|
||||
return AType.ANNOTATION_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<MethodParameters> getType() {
|
||||
return AType.ANNOTATION_MTH_PARAMETERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-3
@@ -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<DeclareVariablesAttr> getType() {
|
||||
return AType.DECLARE_VARIABLES;
|
||||
}
|
||||
|
||||
@Override
|
||||
+5
-3
@@ -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<EnumClassAttr> getType() {
|
||||
return AType.ENUM_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
+5
-3
@@ -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<FieldReplaceAttr> getType() {
|
||||
return AType.FIELD_REPLACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
+5
-3
@@ -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<ForceReturnAttr> getType() {
|
||||
return AType.FORCE_RETURN;
|
||||
}
|
||||
|
||||
@Override
|
||||
+5
-3
@@ -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<JadxErrorAttr> getType() {
|
||||
return AType.JADX_ERROR;
|
||||
}
|
||||
|
||||
@Override
|
||||
+9
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -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 {
|
||||
|
||||
+6
-10
@@ -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<BlockNode> 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<BlockNode> 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<BlockNode> 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));
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -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<MethodInlineAttr> getType() {
|
||||
return AType.METHOD_INLINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
+5
-3
@@ -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<PhiInsn> list = new LinkedList<PhiInsn>();
|
||||
|
||||
@Override
|
||||
public AttributeType getType() {
|
||||
return AttributeType.PHI_LIST;
|
||||
public AType<PhiListAttr> getType() {
|
||||
return AType.PHI_LIST;
|
||||
}
|
||||
|
||||
public List<PhiInsn> getList() {
|
||||
+6
-3
@@ -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<SourceFileAttr> getType() {
|
||||
return AType.SOURCE_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(" ");
|
||||
|
||||
@@ -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<BlockNode> cleanSuccessors(BlockNode block) {
|
||||
List<BlockNode> sucList = block.getSuccessors();
|
||||
List<BlockNode> nodes = new ArrayList<BlockNode>(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<BlockNode> toRemove = new LinkedList<BlockNode>();
|
||||
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<LoopInfo> loops = block.getAll(AType.LOOP);
|
||||
for (LoopInfo loop : loops) {
|
||||
toRemove.add(loop.getStart());
|
||||
}
|
||||
}
|
||||
if (toRemove.isEmpty()) {
|
||||
return sucList;
|
||||
}
|
||||
List<BlockNode> result = new ArrayList<BlockNode>(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
|
||||
|
||||
@@ -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<FieldNode> 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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ExceptionHandler> exceptionHandlers = Collections.emptyList();
|
||||
private List<LoopAttr> loops = Collections.emptyList();
|
||||
private List<LoopInfo> 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<LoopAttr>(5);
|
||||
loops = new ArrayList<LoopInfo>(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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<FieldValueAttr> getType() {
|
||||
return AType.FIELD_VALUE;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<CatchAttr> getType() {
|
||||
return AType.CATCH_BLOCK;
|
||||
}
|
||||
|
||||
public TryCatchBlock getTryBlock() {
|
||||
|
||||
@@ -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<ExcHandlerAttr> getType() {
|
||||
return AType.EXC_HANDLER;
|
||||
}
|
||||
|
||||
public TryCatchBlock getTryBlock() {
|
||||
|
||||
@@ -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<SplitterBlockAttr> getType() {
|
||||
return AType.SPLITTER_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<InsnNode> 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);
|
||||
}
|
||||
|
||||
@@ -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<Integer, BlockNode> blocksMap) {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
List<IAttribute> jumps = insn.getAttributes().getAll(AttributeType.JUMP);
|
||||
for (IAttribute attr : jumps) {
|
||||
JumpAttribute jump = (JumpAttribute) attr;
|
||||
List<JumpInfo> 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<IAttribute> pJumps = prevInsn.getAttributes().getAll(AttributeType.JUMP);
|
||||
for (IAttribute j : pJumps) {
|
||||
JumpAttribute jump = (JumpAttribute) j;
|
||||
List<JumpInfo> pJumps = prevInsn.getAll(AType.JUMP);
|
||||
for (JumpInfo jump : pJumps) {
|
||||
if (jump.getSrc() == prevInsn.getOffset()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
List<IAttribute> cJumps = currentInsn.getAttributes().getAll(AttributeType.JUMP);
|
||||
for (IAttribute j : cJumps) {
|
||||
JumpAttribute jump = (JumpAttribute) j;
|
||||
List<JumpInfo> 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<LoopInfo> 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<IAttribute> loops = block.getAttributes().getAll(AttributeType.LOOP);
|
||||
List<LoopInfo> 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<Edge> 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<BlockNode> preds = new ArrayList<BlockNode>(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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<BlockNode> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IContainer> 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<IContainer> subBlocks = ((IRegion) region).getSubBlocks();
|
||||
if (subBlocks.size() == 1
|
||||
&& subBlocks.get(0).getAttributes().contains(AttributeFlag.RETURN)) {
|
||||
&& subBlocks.get(0).contains(AFlag.RETURN)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<InsnNode> 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;
|
||||
}
|
||||
|
||||
@@ -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<TryCatchBlock> tryBlocks = new HashSet<TryCatchBlock>();
|
||||
// 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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<LoopInfo> 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<IAttribute> 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<BlockNode> 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<InsnNode> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<BlockNode> cleanBlockList(List<BlockNode> list) {
|
||||
List<BlockNode> ret = new ArrayList<BlockNode>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<IContainer> 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;
|
||||
|
||||
@@ -7,4 +7,8 @@ public class JadxRuntimeException extends RuntimeException {
|
||||
public JadxRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JadxRuntimeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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<TestAttr>()
|
||||
class TestAttr implements IAttribute {
|
||||
AType<TestAttr> 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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<TV;Lb;>;").consumeType(),
|
||||
ArgType.generic("La;", new ArgType[]{ArgType.genericType("V"), ArgType.object("b")}));
|
||||
|
||||
assertEquals(p("La<Lb<Lc;>;>;").consumeType(),
|
||||
ArgType.generic("La;", new ArgType[]{
|
||||
ArgType.generic("Lb;", new ArgType[]{
|
||||
ArgType.object("Lc;")})})
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericInnerType() {
|
||||
assertEquals(p("La<TD;>.c;").consumeType(),
|
||||
ArgType.genericInner(ArgType.generic("La;", new ArgType[]{ArgType.genericType("D")}), "c", null));
|
||||
|
||||
assertEquals(p("La<Lb;>.c<TV;>;").consumeType(),
|
||||
ArgType.genericInner(ArgType.generic("La;", new ArgType[]{ArgType.object("Lb;")}),
|
||||
"c", new ArgType[]{ArgType.genericType("V")})
|
||||
);
|
||||
|
||||
assertEquals(p("La<TV;>.LinkedHashIterator<Lb$c<Ls;TV;>;>;").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("<T:Ljava/lang/Object;>").consumeGenericMap().toString(),
|
||||
"{T=[]}");
|
||||
|
||||
assertEquals(p("<K:Ljava/lang/Object;LongGenericType:Ljava/lang/Object;>").consumeGenericMap().toString(),
|
||||
"{K=[], LongGenericType=[]}");
|
||||
|
||||
assertEquals(p("<ResultT:Ljava/lang/Exception;:Ljava/lang/Object;>").consumeGenericMap().toString(),
|
||||
"{ResultT=[java.lang.Exception]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodsArgs() {
|
||||
List<ArgType> argTypes = p("(Ljava/util/List<*>;)V").consumeMethodArgs();
|
||||
assertEquals(argTypes.size(), 1);
|
||||
assertEquals(argTypes.get(0), ArgType.generic("Ljava/util/List;", new ArgType[]{ArgType.wildcard()}));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {"));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user