fix: sort inner classes and methods by source lines
This commit is contained in:
@@ -10,6 +10,7 @@ import java.util.Objects;
|
||||
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;
|
||||
@@ -130,7 +131,8 @@ public class ClassGen {
|
||||
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('@');
|
||||
@@ -222,21 +224,32 @@ public class ClassGen {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,36 +262,24 @@ public class ClassGen {
|
||||
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() {
|
||||
@@ -290,7 +291,7 @@ public class ClassGen {
|
||||
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);
|
||||
|
||||
@@ -8,9 +8,12 @@ import java.util.Set;
|
||||
|
||||
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;
|
||||
@@ -20,6 +23,7 @@ import jadx.core.dex.instructions.args.RegisterArg;
|
||||
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;
|
||||
@@ -44,6 +48,14 @@ import jadx.core.utils.exceptions.JadxException;
|
||||
)
|
||||
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();
|
||||
@@ -246,4 +258,26 @@ public class PrepareForCodeGen extends AbstractVisitor {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TestLineNumbers2 extends IntegrationTest {
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user