提交 4a6115ed 编写于 作者: S Skylot

core: refactor attribute storage

上级 42eb3197
......@@ -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";
}
}
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));
}
}
......
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);
......
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());
}
......
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;
......
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('(');
}
......
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);
}
}
......
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()) {
......
package jadx.core.dex.attributes;
public enum AttributeFlag {
public enum AFlag {
TRY_ENTER,
TRY_LEAVE,
......
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>();
}
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);
}
}
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 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 AttributesList getAttributes() {
if (attributesList == null) {
attributesList = new AttributesList();
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 attributesList;
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();
}
}
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) + "}";
}
}
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;
}
}
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) + "}";
}
}
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();
}
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();
}
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
......
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
......
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
......
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
......
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
......
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
......
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
......
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);
}
}
package jadx.core.dex.attributes;
package jadx.core.dex.attributes.nodes;
import jadx.core.dex.attributes.AttrNode;
public abstract class LineAttrNode extends AttrNode {
......
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));
}
}
......
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
......
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() {
......
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);
}
}
......
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(" ");
......
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);
}
if (sucList.isEmpty()) {
return sucList;
}
List<BlockNode> toRemove = new LinkedList<BlockNode>();
for (BlockNode b : sucList) {
if (b.contains(AType.EXC_HANDLER)) {
toRemove.add(b);
}
} else {
for (BlockNode b : sucList) {
if (!b.getAttributes().contains(AttributeType.EXC_HANDLER)) {
nodes.add(b);
}
}
if (block.contains(AFlag.LOOP_END)) {
List<LoopInfo> loops = block.getAll(AType.LOOP);
for (LoopInfo loop : loops) {
toRemove.add(loop.getStart());
}
}
return nodes.size() == sucList.size() ? sucList : nodes;
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()) {
......
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;
......
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;
......
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);
}
}
......
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;
}
......
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;
}
......
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() {
......
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() {
......
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
......
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);
}
......
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);
......
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;
......
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);
}
}
}
......
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();
......
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);
}
}
}
......
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:
......
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);
}
}
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);
}
......
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);
}
}
......
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);
}
}
}
......
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;
}
}
......
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;
}
......
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()) {
......
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);
}
......
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);
}
}
......
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));
......
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;
}
......
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();
......
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");
}
}
......
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);
}
}
......
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);
}
}
......
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
......
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;
......
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"
}
}
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)
}
}
package jadx.tests
import jadx.core.dex.instructions.args.ArgType
import jadx.core.dex.nodes.parser.SignatureParser
import spock.lang.Specification
......
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()}));
}
}
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;
......
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() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册