Skip to content

Commit

Permalink
fix: sort inner classes and methods by source lines
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Nov 19, 2019
1 parent 4b314e9 commit e4e6f37
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 38 deletions.
75 changes: 38 additions & 37 deletions jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Set;

import com.android.dx.rop.code.AccessFlags;
import com.google.common.collect.Streams;

import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AFlag;
Expand Down Expand Up @@ -130,7 +131,8 @@ public void addClassDeclaration(CodeWriter clsCode) {
annotationGen.addForClass(clsCode);
insertRenameInfo(clsCode, cls);
CodeGenUtils.addSourceFileInfo(clsCode, cls);
clsCode.startLine(af.makeString());
clsCode.startLineWithNum(cls.getSourceLine());
clsCode.add(af.makeString());
if (af.isInterface()) {
if (af.isAnnotation()) {
clsCode.add('@');
Expand Down Expand Up @@ -222,21 +224,32 @@ public void addClassBody(CodeWriter clsCode) throws CodegenException {
clsDeclLine = clsCode.getLine();
clsCode.incIndent();
addFields(clsCode);
addInnerClasses(clsCode, cls);
addMethods(clsCode);
addInnerClsAndMethods(clsCode);
clsCode.decIndent();
clsCode.startLine('}');
}

private void addInnerClasses(CodeWriter code, ClassNode cls) throws CodegenException {
for (ClassNode innerCls : cls.getInnerClasses()) {
if (innerCls.contains(AFlag.DONT_GENERATE)) {
continue;
}
private void addInnerClsAndMethods(CodeWriter clsCode) {
Streams.concat(cls.getInnerClasses().stream(), cls.getMethods().stream())
.filter(node -> !node.contains(AFlag.DONT_GENERATE))
.sorted(Comparator.comparingInt(LineAttrNode::getSourceLine))
.forEach(node -> {
if (node instanceof ClassNode) {
addInnerClass(clsCode, (ClassNode) node);
} else {
addMethod(clsCode, (MethodNode) node);
}
});
}

private void addInnerClass(CodeWriter code, ClassNode innerCls) {
try {
ClassGen inClGen = new ClassGen(innerCls, getParentGen());
code.newLine();
inClGen.addClassCode(code);
imports.addAll(inClGen.getImports());
} catch (Exception e) {
ErrorsCounter.classError(innerCls, "Inner class code generation error", e);
}
}

Expand All @@ -249,38 +262,26 @@ private boolean isInnerClassesPresents() {
return false;
}

private void addMethods(CodeWriter code) {
List<MethodNode> methods = sortMethodsByLine(cls.getMethods());
for (MethodNode mth : methods) {
if (mth.contains(AFlag.DONT_GENERATE)) {
continue;
}
if (code.getLine() != clsDeclLine) {
code.newLine();
}
int savedIndent = code.getIndent();
try {
addMethod(code, mth);
} catch (Exception e) {
if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) {
throw new JadxRuntimeException("Method generation error", e);
}
code.newLine().add("/*");
code.newLine().addMultiLine(ErrorsCounter.methodError(mth, "Method generation error", e));
Utils.appendStackTrace(code, e);
code.newLine().add("*/");
code.setIndent(savedIndent);
mth.addError("Method generation error: " + e.getMessage(), e);
private void addMethod(CodeWriter code, MethodNode mth) {
if (code.getLine() != clsDeclLine) {
code.newLine();
}
int savedIndent = code.getIndent();
try {
addMethodCode(code, mth);
} catch (Exception e) {
if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) {
throw new JadxRuntimeException("Method generation error", e);
}
code.newLine().add("/*");
code.newLine().addMultiLine(ErrorsCounter.methodError(mth, "Method generation error", e));
Utils.appendStackTrace(code, e);
code.newLine().add("*/");
code.setIndent(savedIndent);
mth.addError("Method generation error: " + e.getMessage(), e);
}
}

private static List<MethodNode> sortMethodsByLine(List<MethodNode> methods) {
List<MethodNode> out = new ArrayList<>(methods);
out.sort(Comparator.comparingInt(LineAttrNode::getSourceLine));
return out;
}

private boolean isMethodsPresents() {
for (MethodNode mth : cls.getMethods()) {
if (!mth.contains(AFlag.DONT_GENERATE)) {
Expand All @@ -290,7 +291,7 @@ private boolean isMethodsPresents() {
return false;
}

public void addMethod(CodeWriter code, MethodNode mth) throws CodegenException {
public void addMethodCode(CodeWriter code, MethodNode mth) throws CodegenException {
CodeGenUtils.addComments(code, mth);
if (mth.getAccessFlags().isAbstract() || mth.getAccessFlags().isNative()) {
MethodGen mthGen = new MethodGen(this, mth);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@

import org.jetbrains.annotations.Nullable;

import com.google.common.collect.Streams;

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.LineAttrNode;
import jadx.core.dex.instructions.ArithNode;
import jadx.core.dex.instructions.ArithOp;
import jadx.core.dex.instructions.InsnType;
Expand All @@ -20,6 +23,7 @@
import jadx.core.dex.instructions.mods.ConstructorInsn;
import jadx.core.dex.instructions.mods.TernaryInsn;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.InsnContainer;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
Expand All @@ -44,6 +48,14 @@
)
public class PrepareForCodeGen extends AbstractVisitor {

@Override
public boolean visit(ClassNode cls) throws JadxException {
if (cls.root().getArgs().isDebugInfo()) {
setClassSourceLine(cls);
}
return true;
}

@Override
public void visit(MethodNode mth) throws JadxException {
List<BlockNode> blocks = mth.getBasicBlocks();
Expand Down Expand Up @@ -246,4 +258,26 @@ private ConstructorInsn searchConstructorCall(MethodNode mth) {
}
return null;
}

/**
* Use source line from top method
*/
private void setClassSourceLine(ClassNode cls) {
for (ClassNode innerClass : cls.getInnerClasses()) {
setClassSourceLine(innerClass);
}

int minLine = Streams.concat(
cls.getMethods().stream(),
cls.getInnerClasses().stream(),
cls.getFields().stream())
.filter(mth -> !mth.contains(AFlag.DONT_GENERATE))
.filter(mth -> mth.getSourceLine() != 0)
.mapToInt(LineAttrNode::getSourceLine)
.min()
.orElse(0);
if (minLine != 0) {
cls.setSourceLine(minLine - 1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void test() {

ClassNode cls = getClassNode(TestCls.class);
Map<Integer, Integer> lineMapping = cls.getCode().getLineMapping();
assertEquals("{8=18, 11=22, 12=23, 13=24, 14=28, 16=25, 17=26, 18=28, 21=31, 22=32}",
assertEquals("{5=17, 8=18, 11=22, 12=23, 13=24, 14=28, 16=25, 17=26, 18=28, 21=31, 22=32}",
lineMapping.toString());
}
}

0 comments on commit e4e6f37

Please sign in to comment.