Commit 890c0a99 authored by Skylot's avatar Skylot

refactor: remove deprecated methods

parent b73cb406
......@@ -151,8 +151,7 @@ public class AnnotationGen {
code.add(InsnGen.makeStaticFieldAccess(field, classGen));
} else if (val instanceof List) {
code.add('{');
List list = (List) val;
Iterator it = list.iterator();
Iterator<?> it = ((List) val).iterator();
while (it.hasNext()) {
Object obj = it.next();
encodeValue(code, obj);
......
......@@ -43,6 +43,7 @@ public class ClassGen {
private final boolean fallback;
private final Set<ClassInfo> imports = new HashSet<ClassInfo>();
private int clsDeclLine = 0;
public ClassGen(ClassNode cls, ClassGen parentClsGen, boolean fallback) {
this.cls = cls;
......@@ -95,12 +96,11 @@ public class ClassGen {
if (cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) {
code.startLine("// jadx: inconsistent code");
}
makeClassDeclaration(code);
makeClassBody(code);
code.newLine();
addClassDeclaration(code);
addClassBody(code);
}
public void makeClassDeclaration(CodeWriter clsCode) {
public void addClassDeclaration(CodeWriter clsCode) {
AccessInfo af = cls.getAccessFlags();
if (af.isInterface()) {
af = af.remove(AccessFlags.ACC_ABSTRACT);
......@@ -123,7 +123,7 @@ public class ClassGen {
}
clsCode.add(cls.getShortName());
makeGenericMap(clsCode, cls.getGenericMap());
addGenericMap(clsCode, cls.getGenericMap());
clsCode.add(' ');
ClassInfo sup = cls.getSuperClass();
......@@ -150,11 +150,10 @@ public class ClassGen {
clsCode.add(' ');
}
}
clsCode.attachDefinition(cls);
}
public boolean makeGenericMap(CodeWriter code, Map<ArgType, List<ArgType>> gmap) {
public boolean addGenericMap(CodeWriter code, Map<ArgType, List<ArgType>> gmap) {
if (gmap == null || gmap.isEmpty()) {
return false;
}
......@@ -183,91 +182,78 @@ public class ClassGen {
return true;
}
public void makeClassBody(CodeWriter clsCode) throws CodegenException {
public void addClassBody(CodeWriter clsCode) throws CodegenException {
clsCode.add('{');
CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods());
CodeWriter fieldsCode = makeFields(clsCode, cls, cls.getFields());
clsCode.add(fieldsCode);
if (fieldsCode.notEmpty() && mthsCode.notEmpty()) {
clsCode.newLine();
}
// insert inner classes code
if (cls.getInnerClasses().size() != 0) {
clsCode.add(makeInnerClasses(cls, clsCode.getIndent()));
if (mthsCode.notEmpty()) {
clsCode.newLine();
}
}
clsCode.add(mthsCode);
clsDeclLine = clsCode.getLine();
clsCode.incIndent();
addFields(clsCode);
addInnerClasses(clsCode, cls);
addMethods(clsCode);
clsCode.decIndent();
clsCode.startLine('}');
}
private CodeWriter makeInnerClasses(ClassNode cls, int indent) throws CodegenException {
CodeWriter innerClsCode = new CodeWriter(indent + 1);
for (ClassNode inCls : cls.getInnerClasses()) {
if (!inCls.isAnonymous()) {
ClassGen inClGen = new ClassGen(inCls, parentGen == null ? this : parentGen, fallback);
inClGen.addClassCode(innerClsCode);
private void addInnerClasses(CodeWriter code, ClassNode cls) throws CodegenException {
for (ClassNode innerCls : cls.getInnerClasses()) {
if (!innerCls.isAnonymous()) {
ClassGen inClGen = new ClassGen(innerCls, getParentGen(), fallback);
code.newLine();
inClGen.addClassCode(code);
imports.addAll(inClGen.getImports());
}
}
return innerClsCode;
}
private CodeWriter makeMethods(CodeWriter clsCode, List<MethodNode> mthList) {
CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);
for (Iterator<MethodNode> it = mthList.iterator(); it.hasNext(); ) {
MethodNode mth = it.next();
if (mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
continue;
}
try {
if (mth.getAccessFlags().isAbstract() || mth.getAccessFlags().isNative()) {
MethodGen mthGen = new MethodGen(this, mth);
mthGen.addDefinition(code);
if (cls.getAccessFlags().isAnnotation()) {
Object def = annotationGen.getAnnotationDefaultValue(mth.getName());
if (def != null) {
code.add(" default ");
annotationGen.encodeValue(code, def);
}
}
code.add(';');
} else {
MethodGen mthGen = new MethodGen(this, mth);
boolean badCode = mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE);
if (badCode) {
code.startLine("/* JADX WARNING: inconsistent code. */");
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */");
LOG.error(ErrorsCounter.formatErrorMsg(mth, " Inconsistent code"));
}
if (mthGen.addDefinition(code)) {
code.add(' ');
private void addMethods(CodeWriter code) {
for (MethodNode mth : cls.getMethods()) {
if (!mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
try {
if (code.getLine() != clsDeclLine) {
code.newLine();
}
code.add('{');
code.incIndent();
insertSourceFileInfo(code, mth);
mthGen.addInstructions(code);
code.decIndent();
code.startLine('}');
addMethod(code, mth);
} catch (Exception e) {
String msg = ErrorsCounter.methodError(mth, "Method generation error", e);
code.startLine("/* " + msg + CodeWriter.NL + Utils.getStackTrace(e) + " */");
}
} catch (Throwable e) {
String msg = ErrorsCounter.methodError(mth, "Method generation error", e);
code.startLine("/* " + msg + CodeWriter.NL + Utils.getStackTrace(e) + " */");
}
if (it.hasNext()) {
code.newLine();
}
}
return code;
}
private CodeWriter makeFields(CodeWriter clsCode, ClassNode cls, List<FieldNode> fields) throws CodegenException {
CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);
addEnumFields(cls, code);
private void addMethod(CodeWriter code, MethodNode mth) throws CodegenException {
MethodGen mthGen = new MethodGen(this, mth);
if (mth.getAccessFlags().isAbstract() || mth.getAccessFlags().isNative()) {
mthGen.addDefinition(code);
if (cls.getAccessFlags().isAnnotation()) {
Object def = annotationGen.getAnnotationDefaultValue(mth.getName());
if (def != null) {
code.add(" default ");
annotationGen.encodeValue(code, def);
}
}
code.add(';');
} else {
boolean badCode = mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE);
if (badCode) {
code.startLine("/* JADX WARNING: inconsistent code. */");
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */");
LOG.error(ErrorsCounter.formatErrorMsg(mth, " Inconsistent code"));
}
if (mthGen.addDefinition(code)) {
code.add(' ');
}
code.add('{');
code.incIndent();
insertSourceFileInfo(code, mth);
mthGen.addInstructions(code);
code.decIndent();
code.startLine('}');
}
}
for (FieldNode f : fields) {
private void addFields(CodeWriter code) throws CodegenException {
addEnumFields(code);
for (FieldNode f : cls.getFields()) {
if (f.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
continue;
}
......@@ -288,10 +274,9 @@ public class ClassGen {
code.add(';');
code.attachDefinition(f);
}
return code;
}
private void addEnumFields(ClassNode cls, CodeWriter code) throws CodegenException {
private void addEnumFields(CodeWriter code) throws CodegenException {
EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS);
if (enumFields != null) {
InsnGen igen = null;
......@@ -305,7 +290,7 @@ public class ClassGen {
if (igen == null) {
// don't init mth gen if this is simple enum
MethodGen mthGen = new MethodGen(this, enumFields.getStaticMethod());
igen = new InsnGen(mthGen, enumFields.getStaticMethod(), false);
igen = new InsnGen(mthGen, false);
}
igen.addArg(code, arg);
if (aIt.hasNext()) {
......@@ -315,7 +300,7 @@ public class ClassGen {
code.add(')');
}
if (f.getCls() != null) {
new ClassGen(f.getCls(), this, fallback).makeClassBody(code);
new ClassGen(f.getCls(), this, fallback).addClassBody(code);
}
if (it.hasNext()) {
code.add(',');
......
......@@ -95,21 +95,15 @@ public class CodeWriter {
return this;
}
@Deprecated
public CodeWriter add(CodeWriter code) {
CodeWriter add(CodeWriter code) {
line--;
for (Map.Entry<CodePosition, Object> entry : code.annotations.entrySet()) {
CodePosition pos = entry.getKey();
attachAnnotation(entry.getValue(), new CodePosition(line + pos.getLine(), pos.getOffset()));
}
line += code.line;
String str = code.toString();
buf.append(str);
if (str.contains(NL)) {
offset = code.offset;
} else {
offset += code.offset;
}
offset = code.offset;
buf.append(code);
return this;
}
......@@ -143,6 +137,10 @@ public class CodeWriter {
}
}
public int getLine() {
return line;
}
public int getIndent() {
return indent;
}
......
......@@ -12,41 +12,52 @@ import jadx.core.dex.regions.Compare;
import jadx.core.dex.regions.IfCondition;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConditionGen {
public class ConditionGen extends InsnGen {
private static final Logger LOG = LoggerFactory.getLogger(ConditionGen.class);
static String make(InsnGen insnGen, IfCondition condition) throws CodegenException {
public ConditionGen(InsnGen insnGen) {
super(insnGen.mgen, insnGen.fallback);
}
void add(CodeWriter code, IfCondition condition) throws CodegenException {
switch (condition.getMode()) {
case COMPARE:
return makeCompare(insnGen, condition.getCompare());
addCompare(code, condition.getCompare());
break;
case NOT:
return "!(" + make(insnGen, condition.getArgs().get(0)) + ")";
addNot(code, condition);
break;
case AND:
case OR:
String mode = condition.getMode() == IfCondition.Mode.AND ? " && " : " || ";
StringBuilder sb = new StringBuilder();
for (IfCondition arg : condition.getArgs()) {
if (sb.length() != 0) {
sb.append(mode);
}
String s = make(insnGen, arg);
if (arg.isCompare()) {
sb.append(s);
} else {
sb.append('(').append(s).append(')');
}
}
return sb.toString();
addAndOr(code, condition);
break;
default:
return "??" + condition;
throw new JadxRuntimeException("Unknown condition mode: " + condition);
}
}
void wrap(CodeWriter code, IfCondition cond) throws CodegenException {
boolean wrap = isWrapNeeded(cond);
if (wrap) {
code.add('(');
}
add(code, cond);
if (wrap) {
code.add(')');
}
}
private static String makeCompare(InsnGen insnGen, Compare compare) throws CodegenException {
private void addCompare(CodeWriter code, Compare compare) throws CodegenException {
IfOp op = compare.getOp();
InsnArg firstArg = compare.getA();
InsnArg secondArg = compare.getB();
......@@ -59,20 +70,47 @@ public class ConditionGen {
}
if (op == IfOp.EQ) {
// == true
return insnGen.arg(firstArg, false).toString();
addArg(code, firstArg, false);
return;
} else if (op == IfOp.NE) {
// != true
if (isWrapNeeded(firstArg)) {
return "!(" + insnGen.arg(firstArg) + ")";
} else {
return "!" + insnGen.arg(firstArg);
code.add('!');
boolean wrap = isWrapNeeded(firstArg);
if (wrap) {
code.add('(');
}
addArg(code, firstArg, false);
if (wrap) {
code.add(')');
}
return;
}
LOG.warn(ErrorsCounter.formatErrorMsg(mth, "Unsupported boolean condition " + op.getSymbol()));
}
addArg(code, firstArg, isWrapNeeded(firstArg));
code.add(' ').add(op.getSymbol()).add(' ');
addArg(code, secondArg, isWrapNeeded(secondArg));
}
private void addNot(CodeWriter code, IfCondition condition) throws CodegenException {
code.add('!');
wrap(code, condition.getArgs().get(0));
}
private void addAndOr(CodeWriter code, IfCondition condition) throws CodegenException {
String mode = condition.getMode() == IfCondition.Mode.AND ? " && " : " || ";
Iterator<IfCondition> it = condition.getArgs().iterator();
while (it.hasNext()) {
wrap(code, it.next());
if (it.hasNext()) {
code.add(mode);
}
LOG.warn(ErrorsCounter.formatErrorMsg(insnGen.mth, "Unsupported boolean condition " + op.getSymbol()));
}
return insnGen.arg(firstArg, isWrapNeeded(firstArg))
+ " " + op.getSymbol() + " "
+ insnGen.arg(secondArg, isWrapNeeded(secondArg));
}
private boolean isWrapNeeded(IfCondition condition) {
return !condition.isCompare();
}
private static boolean isWrapNeeded(InsnArg arg) {
......
......@@ -58,6 +58,10 @@ public class MethodGen {
return classGen;
}
public MethodNode getMethodNode() {
return mth;
}
public boolean addDefinition(CodeWriter code) {
if (mth.getMethodInfo().isClassInit()) {
code.startLine("static");
......@@ -84,7 +88,7 @@ public class MethodGen {
}
code.startLine(ai.makeString());
if (classGen.makeGenericMap(code, mth.getGenericMap())) {
if (classGen.addGenericMap(code, mth.getGenericMap())) {
code.add(' ');
}
if (mth.getAccessFlags().isConstructor()) {
......@@ -245,7 +249,7 @@ public class MethodGen {
} else {
Region startRegion = mth.getRegion();
if (startRegion != null) {
(new RegionGen(this, mth)).makeRegion(code, startRegion);
(new RegionGen(this)).makeRegion(code, startRegion);
} else {
addFallbackMethodCode(code);
}
......@@ -289,7 +293,7 @@ public class MethodGen {
}
public static void addFallbackInsns(CodeWriter code, MethodNode mth, List<InsnNode> insns, boolean addLabels) {
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), mth, true);
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true);
for (InsnNode insn : insns) {
AttributesList attrs = insn.getAttributes();
if (addLabels) {
......
......@@ -15,7 +15,6 @@ import jadx.core.dex.nodes.IBlock;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.IfCondition;
import jadx.core.dex.regions.IfRegion;
import jadx.core.dex.regions.LoopRegion;
......@@ -36,8 +35,8 @@ import org.slf4j.LoggerFactory;
public class RegionGen extends InsnGen {
private static final Logger LOG = LoggerFactory.getLogger(RegionGen.class);
public RegionGen(MethodGen mgen, MethodNode mth) {
super(mgen, mth, false);
public RegionGen(MethodGen mgen) {
super(mgen, false);
}
public void makeRegion(CodeWriter code, IContainer cont) throws CodegenException {
......@@ -66,7 +65,9 @@ public class RegionGen extends InsnGen {
(DeclareVariablesAttr) cont.getAttributes().get(AttributeType.DECLARE_VARIABLES);
if (declVars != null) {
for (RegisterArg v : declVars.getVars()) {
code.startLine(declareVar(v)).add(';');
code.startLine();
declareVar(code, v);
code.add(';');
}
}
}
......@@ -111,7 +112,9 @@ public class RegionGen extends InsnGen {
if (newLine) {
code.startLine();
}
code.add("if (").add(ConditionGen.make(this, region.getCondition())).add(") {");
code.add("if (");
new ConditionGen(this).add(code, region.getCondition());
code.add(") {");
makeRegionIndent(code, region.getThenRegion());
code.startLine('}');
......@@ -169,13 +172,17 @@ public class RegionGen extends InsnGen {
return code;
}
String condStr = ConditionGen.make(this, condition);
ConditionGen conditionGen = new ConditionGen(this);
if (region.isConditionAtEnd()) {
code.startLine("do {");
makeRegionIndent(code, region.getBody());
code.startLine("} while (").add(condStr).add(");");
code.startLine("} while (");
conditionGen.add(code, condition);
code.add(");");
} else {
code.startLine("while (").add(condStr).add(") {");
code.startLine("while (");
conditionGen.add(code, condition);
code.add(") {");
makeRegionIndent(code, region.getBody());
code.startLine('}');
}
......
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.info.AccessInfo;
......@@ -39,6 +40,8 @@ public class ClassModifier extends AbstractVisitor {
removeSyntheticFields(cls);
removeSyntheticMethods(cls);
removeEmptyMethods(cls);
checkFieldsInit(cls);
return false;
}
......@@ -174,4 +177,36 @@ public class ClassModifier extends AbstractVisitor {
}
return true;
}
private static void checkFieldsInit(ClassNode cls) {
MethodNode clinit = cls.searchMethodByName("<clinit>()V");
if (clinit == null
|| !clinit.getAccessFlags().isStatic()
|| clinit.isNoCode()) {
return;
}
for (BlockNode block : clinit.getBasicBlocks()) {
for (InsnNode insn : block.getInstructions()) {
if (insn.getType() == InsnType.SPUT) {
processStaticFieldAssign(cls, (IndexInsnNode) insn);
}
}
}
}
/**
* Remove field initialization if it assign in "<clinit>" method
*/
private static void processStaticFieldAssign(ClassNode cls, IndexInsnNode insn) {
FieldInfo field = (FieldInfo) insn.getIndex();
String thisClass = cls.getFullName();
if (field.getDeclClass().getFullName().equals(thisClass)) {
FieldNode fn = cls.searchField(field);
if (fn != null && fn.getAccessFlags().isFinal()) {
fn.getAttributes().remove(AttributeType.FIELD_VALUE);
}
}
}
}
......@@ -6,7 +6,6 @@ import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.either;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
......@@ -18,10 +17,7 @@ public class TestRedundantBrackets extends InternalJadxTest {
}
public int method2(Object obj) {
if (obj instanceof String) {
return ((String) obj).length();
}
return 0;
return obj instanceof String ? ((String) obj).length() : 0;
}
public int method3(int a, int b) {
......@@ -50,11 +46,12 @@ public class TestRedundantBrackets extends InternalJadxTest {
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, not(containsString("(-1)")));
assertThat(code, not(containsString("return;")));
assertThat(code, either(containsString("if (obj instanceof String) {"))
.or(containsString("return (obj instanceof String) ? ")));
assertThat(code, containsString("return obj instanceof String ? ((String) obj).length() : 0;"));
assertThat(code, containsString("if (a + b < 10)"));
assertThat(code, containsString("if ((a & b) != 0)"));
assertThat(code, containsString("if (num == 4 || num == 6 || num == 8 || num == 10)"));
......
......@@ -57,7 +57,7 @@ public class TestReturnWrapping extends InternalJadxTest {
assertThat(code, containsString("return 255;"));
assertThat(code, containsString("return arg0 + 1;"));
//assertThat(code, containsString("return Integer.toHexString(i);"));
assertThat(code, containsString("return (i > 128) ? arg0.toString() + ret.toString() : Integer.valueOf(i);"));
assertThat(code, containsString("return i > 128 ? arg0.toString() + ret.toString() : Integer.valueOf(i);"));
assertThat(code, containsString("return arg0 + 2;"));
assertThat(code, containsString("arg0 -= 951;"));
}
......
package jadx.tests.internal;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestStaticFieldsInit extends InternalJadxTest {
public static class TestCls {
public static final String s1 = "1";
public static final String s2 = "12".substring(1);
public static final String s3 = null;
public static final String s4;
public static final String s5 = "5";
public static String s6 = "6";
static {
if (s5.equals("?")) {
s4 = "?";
} else {
s4 = "4";
}
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, not(containsString("public static final String s2 = null;")));
// TODO:
// assertThat(code, containsString("public static final String s3 = null;"));
}
}
......@@ -43,6 +43,6 @@ public class TestGenerics2 extends InternalJadxTest {
assertThat(code, containsString("public ItemReference(V item, Object id, ReferenceQueue<? super V> queue) {"));
assertThat(code, containsString("public V get(Object id) {"));
assertThat(code, containsString("WeakReference<V> ref = "));
assertThat(code, containsString("return (ref != null) ? ref.get() : null;"));
assertThat(code, containsString("return ref != null ? ref.get() : null;"));
}
}
......@@ -21,6 +21,8 @@ import org.slf4j.LoggerFactory;
public class JadxTextArea extends RSyntaxTextArea {
private static final Logger LOG = LoggerFactory.getLogger(JadxTextArea.class);
private static final long serialVersionUID = 6312736869579635796L;
private static final Color BACKGROUND = new Color(0xf7f7f7);
private static final Color JUMP_FOREGROUND = new Color(0x785523);
private static final Color JUMP_BACKGROUND = new Color(0xE6E6FF);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment