未验证 提交 48252c3c 编写于 作者: S Skylot

feat: add option for code comments levels (#998)

上级 37adce2e
...@@ -105,7 +105,8 @@ options: ...@@ -105,7 +105,8 @@ options:
--cfg - save methods control flow graph to dot file --cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions) --raw-cfg - save methods control flow graph (use raw instructions)
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc) -f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
--log-level - set log level, values: QUIET, PROGRESS, ERROR, WARN, INFO, DEBUG, default: PROGRESS --comments-level - set code comments level, values: none, user_only, error, warn, info, debug, default: info
--log-level - set log level, values: quiet, progress, error, warn, info, debug, default: progress
-v, --verbose - verbose output (set --log-level to DEBUG) -v, --verbose - verbose output (set --log-level to DEBUG)
-q, --quiet - turn off output (set --log-level to QUIET) -q, --quiet - turn off output (set --log-level to QUIET)
--version - print jadx version --version - print jadx version
......
...@@ -6,6 +6,7 @@ import java.util.ArrayList; ...@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
...@@ -130,7 +131,7 @@ public class JCommanderWrapper<T> { ...@@ -130,7 +131,7 @@ public class JCommanderWrapper<T> {
if (Enum.class.isAssignableFrom(fieldType)) { if (Enum.class.isAssignableFrom(fieldType)) {
Enum<?> val = (Enum<?>) f.get(args); Enum<?> val = (Enum<?>) f.get(args);
if (val != null) { if (val != null) {
return val.name(); return val.name().toLowerCase(Locale.ROOT);
} }
} }
} catch (Exception e) { } catch (Exception e) {
......
...@@ -11,6 +11,7 @@ import java.util.stream.Stream; ...@@ -11,6 +11,7 @@ import java.util.stream.Stream;
import com.beust.jcommander.IStringConverter; import com.beust.jcommander.IStringConverter;
import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameter;
import jadx.api.CommentsLevel;
import jadx.api.JadxArgs; import jadx.api.JadxArgs;
import jadx.api.JadxArgs.RenameEnum; import jadx.api.JadxArgs.RenameEnum;
import jadx.api.JadxDecompiler; import jadx.api.JadxDecompiler;
...@@ -102,7 +103,7 @@ public class JadxCLIArgs { ...@@ -102,7 +103,7 @@ public class JadxCLIArgs {
@Parameter( @Parameter(
names = { "--rename-flags" }, names = { "--rename-flags" },
description = "fix options (comma-separated list of): " description = "fix options (comma-separated list of):"
+ "\n 'case' - fix case sensitivity issues (according to --fs-case-sensitive option)," + "\n 'case' - fix case sensitivity issues (according to --fs-case-sensitive option),"
+ "\n 'valid' - rename java identifiers to make them valid," + "\n 'valid' - rename java identifiers to make them valid,"
+ "\n 'printable' - remove non-printable chars from identifiers," + "\n 'printable' - remove non-printable chars from identifiers,"
...@@ -124,9 +125,16 @@ public class JadxCLIArgs { ...@@ -124,9 +125,16 @@ public class JadxCLIArgs {
@Parameter(names = { "-f", "--fallback" }, description = "make simple dump (using goto instead of 'if', 'for', etc)") @Parameter(names = { "-f", "--fallback" }, description = "make simple dump (using goto instead of 'if', 'for', etc)")
protected boolean fallbackMode = false; protected boolean fallbackMode = false;
@Parameter(
names = { "--comments-level" },
description = "set code comments level, values: error, warn, info, debug, user_only, none",
converter = CommentsLevelConverter.class
)
protected CommentsLevel commentsLevel = CommentsLevel.INFO;
@Parameter( @Parameter(
names = { "--log-level" }, names = { "--log-level" },
description = "set log level, values: QUIET, PROGRESS, ERROR, WARN, INFO, DEBUG", description = "set log level, values: quiet, progress, error, warn, info, debug",
converter = LogHelper.LogLevelConverter.class converter = LogHelper.LogLevelConverter.class
) )
protected LogHelper.LogLevelEnum logLevel = LogHelper.LogLevelEnum.PROGRESS; protected LogHelper.LogLevelEnum logLevel = LogHelper.LogLevelEnum.PROGRESS;
...@@ -222,6 +230,7 @@ public class JadxCLIArgs { ...@@ -222,6 +230,7 @@ public class JadxCLIArgs {
args.setInlineMethods(inlineMethods); args.setInlineMethods(inlineMethods);
args.setRenameFlags(renameFlags); args.setRenameFlags(renameFlags);
args.setFsCaseSensitive(fsCaseSensitive); args.setFsCaseSensitive(fsCaseSensitive);
args.setCommentsLevel(commentsLevel);
return args; return args;
} }
...@@ -349,6 +358,10 @@ public class JadxCLIArgs { ...@@ -349,6 +358,10 @@ public class JadxCLIArgs {
return fsCaseSensitive; return fsCaseSensitive;
} }
public CommentsLevel getCommentsLevel() {
return commentsLevel;
}
static class RenameConverter implements IStringConverter<Set<RenameEnum>> { static class RenameConverter implements IStringConverter<Set<RenameEnum>> {
private final String paramName; private final String paramName;
...@@ -378,9 +391,22 @@ public class JadxCLIArgs { ...@@ -378,9 +391,22 @@ public class JadxCLIArgs {
} }
} }
public static class CommentsLevelConverter implements IStringConverter<CommentsLevel> {
@Override
public CommentsLevel convert(String value) {
try {
return CommentsLevel.valueOf(value.toUpperCase());
} catch (Exception e) {
throw new IllegalArgumentException(
'\'' + value + "' is unknown comments level, possible values are: "
+ JadxCLIArgs.enumValuesString(CommentsLevel.values()));
}
}
}
public static String enumValuesString(Enum<?>[] values) { public static String enumValuesString(Enum<?>[] values) {
return Stream.of(values) return Stream.of(values)
.map(v -> '\'' + v.name().toLowerCase(Locale.ROOT) + '\'') .map(v -> v.name().toLowerCase(Locale.ROOT))
.collect(Collectors.joining(", ")); .collect(Collectors.joining(", "));
} }
} }
...@@ -42,8 +42,7 @@ public class RenameConverterTest { ...@@ -42,8 +42,7 @@ public class RenameConverterTest {
() -> converter.convert("wrong"), () -> converter.convert("wrong"),
"Expected convert() to throw, but it didn't"); "Expected convert() to throw, but it didn't");
assertEquals("'wrong' is unknown for parameter someParam, " assertEquals("'wrong' is unknown for parameter someParam, possible values are case, valid, printable",
+ "possible values are 'case', 'valid', 'printable'",
thrown.getMessage()); thrown.getMessage());
} }
} }
package jadx.api;
public enum CommentsLevel {
NONE,
USER_ONLY,
ERROR,
WARN,
INFO,
DEBUG;
public boolean filter(CommentsLevel limit) {
return this.ordinal() <= limit.ordinal();
}
}
...@@ -83,6 +83,8 @@ public class JadxArgs { ...@@ -83,6 +83,8 @@ public class JadxArgs {
private ICodeData codeData; private ICodeData codeData;
private CommentsLevel commentsLevel = CommentsLevel.INFO;
public JadxArgs() { public JadxArgs() {
// use default options // use default options
} }
...@@ -413,6 +415,14 @@ public class JadxArgs { ...@@ -413,6 +415,14 @@ public class JadxArgs {
this.codeData = codeData; this.codeData = codeData;
} }
public CommentsLevel getCommentsLevel() {
return commentsLevel;
}
public void setCommentsLevel(CommentsLevel commentsLevel) {
this.commentsLevel = commentsLevel;
}
@Override @Override
public String toString() { public String toString() {
return "JadxArgs{" + "inputFiles=" + inputFiles return "JadxArgs{" + "inputFiles=" + inputFiles
...@@ -441,6 +451,7 @@ public class JadxArgs { ...@@ -441,6 +451,7 @@ public class JadxArgs {
+ ", fsCaseSensitive=" + fsCaseSensitive + ", fsCaseSensitive=" + fsCaseSensitive
+ ", renameFlags=" + renameFlags + ", renameFlags=" + renameFlags
+ ", outputFormat=" + outputFormat + ", outputFormat=" + outputFormat
+ ", commentsLevel=" + commentsLevel
+ ", codeCache=" + codeCache + ", codeCache=" + codeCache
+ ", codeWriter=" + codeWriterProvider.apply(this).getClass().getSimpleName() + ", codeWriter=" + codeWriterProvider.apply(this).getClass().getSimpleName()
+ '}'; + '}';
......
...@@ -51,6 +51,7 @@ import jadx.core.xmlgen.ResourcesSaver; ...@@ -51,6 +51,7 @@ import jadx.core.xmlgen.ResourcesSaver;
* *
* <pre> * <pre>
* <code> * <code>
*
* JadxArgs args = new JadxArgs(); * JadxArgs args = new JadxArgs();
* args.getInputFiles().add(new File("test.apk")); * args.getInputFiles().add(new File("test.apk"));
* args.setOutDir(new File("jadx-test-output")); * args.setOutDir(new File("jadx-test-output"));
...@@ -65,6 +66,7 @@ import jadx.core.xmlgen.ResourcesSaver; ...@@ -65,6 +66,7 @@ import jadx.core.xmlgen.ResourcesSaver;
* *
* <pre> * <pre>
* <code> * <code>
*
* for(JavaClass cls : jadx.getClasses()) { * for(JavaClass cls : jadx.getClasses()) {
* System.out.println(cls.getCode()); * System.out.println(cls.getCode());
* } * }
......
...@@ -10,6 +10,7 @@ import java.util.jar.Manifest; ...@@ -10,6 +10,7 @@ import java.util.jar.Manifest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.JadxArgs; import jadx.api.JadxArgs;
import jadx.core.dex.visitors.AttachCommentsVisitor; import jadx.core.dex.visitors.AttachCommentsVisitor;
import jadx.core.dex.visitors.AttachMethodDetails; import jadx.core.dex.visitors.AttachMethodDetails;
...@@ -101,7 +102,9 @@ public class Jadx { ...@@ -101,7 +102,9 @@ public class Jadx {
passes.add(new DebugInfoAttachVisitor()); passes.add(new DebugInfoAttachVisitor());
} }
passes.add(new AttachTryCatchVisitor()); passes.add(new AttachTryCatchVisitor());
passes.add(new AttachCommentsVisitor()); if (args.getCommentsLevel() != CommentsLevel.NONE) {
passes.add(new AttachCommentsVisitor());
}
passes.add(new AttachMethodDetails()); passes.add(new AttachMethodDetails());
passes.add(new ProcessInstructionsVisitor()); passes.add(new ProcessInstructionsVisitor());
......
...@@ -14,6 +14,7 @@ import java.util.stream.Stream; ...@@ -14,6 +14,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import jadx.api.CommentsLevel;
import jadx.api.ICodeInfo; import jadx.api.ICodeInfo;
import jadx.api.ICodeWriter; import jadx.api.ICodeWriter;
import jadx.api.JadxArgs; import jadx.api.JadxArgs;
...@@ -24,11 +25,9 @@ import jadx.api.plugins.input.data.attributes.JadxAttrType; ...@@ -24,11 +25,9 @@ import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.core.Consts; import jadx.core.Consts;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.AttrNode;
import jadx.core.dex.attributes.FieldInitInsnAttr; import jadx.core.dex.attributes.FieldInitInsnAttr;
import jadx.core.dex.attributes.nodes.EnumClassAttr; import jadx.core.dex.attributes.nodes.EnumClassAttr;
import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField; import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.attributes.nodes.LineAttrNode;
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr; import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
...@@ -44,7 +43,6 @@ import jadx.core.dex.nodes.MethodNode; ...@@ -44,7 +43,6 @@ import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.CodeGenUtils; import jadx.core.utils.CodeGenUtils;
import jadx.core.utils.EncodedValueUtils; import jadx.core.utils.EncodedValueUtils;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.Utils; import jadx.core.utils.Utils;
import jadx.core.utils.android.AndroidResourcesUtils; import jadx.core.utils.android.AndroidResourcesUtils;
import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.CodegenException;
...@@ -125,9 +123,8 @@ public class ClassGen { ...@@ -125,9 +123,8 @@ public class ClassGen {
if (Consts.DEBUG_USAGE) { if (Consts.DEBUG_USAGE) {
addClassUsageInfo(code, cls); addClassUsageInfo(code, cls);
} }
insertDecompilationProblems(code, cls); CodeGenUtils.addErrorsAndComments(code, cls);
CodeGenUtils.addSourceFileInfo(code, cls); CodeGenUtils.addSourceFileInfo(code, cls);
CodeGenUtils.addComments(code, cls);
addClassDeclaration(code); addClassDeclaration(code);
addClassBody(code); addClassBody(code);
} }
...@@ -151,7 +148,7 @@ public class ClassGen { ...@@ -151,7 +148,7 @@ public class ClassGen {
annotationGen.addForClass(clsCode); annotationGen.addForClass(clsCode);
insertRenameInfo(clsCode, cls); insertRenameInfo(clsCode, cls);
CodeGenUtils.addInputFileInfo(clsCode, cls); CodeGenUtils.addInputFileInfo(clsCode, cls);
clsCode.startLineWithNum(cls.getSourceLine()).add(af.makeString()); clsCode.startLineWithNum(cls.getSourceLine()).add(af.makeString(cls.checkCommentsLevel(CommentsLevel.INFO)));
if (af.isInterface()) { if (af.isInterface()) {
if (af.isAnnotation()) { if (af.isAnnotation()) {
clsCode.add('@'); clsCode.add('@');
...@@ -247,7 +244,7 @@ public class ClassGen { ...@@ -247,7 +244,7 @@ public class ClassGen {
*/ */
public void addClassBody(ICodeWriter clsCode, boolean printClassName) throws CodegenException { public void addClassBody(ICodeWriter clsCode, boolean printClassName) throws CodegenException {
clsCode.add('{'); clsCode.add('{');
if (printClassName) { if (printClassName && cls.checkCommentsLevel(CommentsLevel.INFO)) {
clsCode.add(" // from class: " + cls.getClassInfo().getFullName()); clsCode.add(" // from class: " + cls.getClassInfo().getFullName());
} }
setBodyGenStarted(true); setBodyGenStarted(true);
...@@ -304,12 +301,9 @@ public class ClassGen { ...@@ -304,12 +301,9 @@ public class ClassGen {
if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) { if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) {
throw new JadxRuntimeException("Method generation error", e); throw new JadxRuntimeException("Method generation error", e);
} }
code.newLine().add("/*"); mth.addError("Method generation error", e);
code.newLine().addMultiLine(ErrorsCounter.error(mth, "Method generation error", e)); CodeGenUtils.addErrors(code, mth);
Utils.appendStackTrace(code, e);
code.newLine().add("*/");
code.setIndent(savedIndent); code.setIndent(savedIndent);
mth.addError("Method generation error: " + e.getMessage(), e);
} }
} }
...@@ -323,8 +317,7 @@ public class ClassGen { ...@@ -323,8 +317,7 @@ public class ClassGen {
} }
public void addMethodCode(ICodeWriter code, MethodNode mth) throws CodegenException { public void addMethodCode(ICodeWriter code, MethodNode mth) throws CodegenException {
CodeGenUtils.addComments(code, mth); CodeGenUtils.addErrorsAndComments(code, mth);
insertDecompilationProblems(code, mth);
if (mth.isNoCode()) { if (mth.isNoCode()) {
MethodGen mthGen = new MethodGen(this, mth); MethodGen mthGen = new MethodGen(this, mth);
mthGen.addDefinition(code); mthGen.addDefinition(code);
...@@ -332,7 +325,6 @@ public class ClassGen { ...@@ -332,7 +325,6 @@ public class ClassGen {
} else { } else {
boolean badCode = mth.contains(AFlag.INCONSISTENT_CODE); boolean badCode = mth.contains(AFlag.INCONSISTENT_CODE);
if (badCode && showInconsistentCode) { if (badCode && showInconsistentCode) {
mth.remove(AFlag.INCONSISTENT_CODE);
badCode = false; badCode = false;
} }
MethodGen mthGen; MethodGen mthGen;
...@@ -352,27 +344,6 @@ public class ClassGen { ...@@ -352,27 +344,6 @@ public class ClassGen {
} }
} }
public void insertDecompilationProblems(ICodeWriter code, AttrNode node) {
List<JadxError> errors = node.getAll(AType.JADX_ERROR);
if (!errors.isEmpty()) {
errors.stream().distinct().sorted().forEach(err -> {
code.startLine("/* JADX ERROR: ").add(err.getError());
Throwable cause = err.getCause();
if (cause != null) {
code.incIndent();
Utils.appendStackTrace(code, cause);
code.decIndent();
}
code.add("*/");
});
}
List<String> warns = node.getAll(AType.JADX_WARN);
if (!warns.isEmpty()) {
warns.stream().distinct().sorted()
.forEach(warn -> code.startLine("/* JADX WARNING: ").addMultiLine(warn).add(" */"));
}
}
private void addFields(ICodeWriter code) throws CodegenException { private void addFields(ICodeWriter code) throws CodegenException {
addEnumFields(code); addEnumFields(code);
for (FieldNode f : cls.getFields()) { for (FieldNode f : cls.getFields()) {
...@@ -390,11 +361,12 @@ public class ClassGen { ...@@ -390,11 +361,12 @@ public class ClassGen {
CodeGenUtils.addComments(code, f); CodeGenUtils.addComments(code, f);
annotationGen.addForField(code, f); annotationGen.addForField(code, f);
if (f.getFieldInfo().isRenamed()) { boolean addInfoComments = f.checkCommentsLevel(CommentsLevel.INFO);
if (f.getFieldInfo().isRenamed() && addInfoComments) {
code.newLine(); code.newLine();
CodeGenUtils.addRenamedComment(code, f, f.getName()); CodeGenUtils.addRenamedComment(code, f, f.getName());
} }
code.startLine(f.getAccessFlags().makeString()); code.startLine(f.getAccessFlags().makeString(addInfoComments));
useType(code, f.getType()); useType(code, f.getType());
code.add(' '); code.add(' ');
code.attachDefinition(f); code.attachDefinition(f);
...@@ -707,7 +679,7 @@ public class ClassGen { ...@@ -707,7 +679,7 @@ public class ClassGen {
private void insertRenameInfo(ICodeWriter code, ClassNode cls) { private void insertRenameInfo(ICodeWriter code, ClassNode cls) {
ClassInfo classInfo = cls.getClassInfo(); ClassInfo classInfo = cls.getClassInfo();
if (classInfo.hasAlias()) { if (classInfo.hasAlias() && cls.checkCommentsLevel(CommentsLevel.INFO)) {
CodeGenUtils.addRenamedComment(code, cls, classInfo.getType().getObject()); CodeGenUtils.addRenamedComment(code, cls, classInfo.getType().getObject());
} }
} }
......
...@@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable; ...@@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.ICodeWriter; import jadx.api.ICodeWriter;
import jadx.api.data.annotations.InsnCodeOffset; import jadx.api.data.annotations.InsnCodeOffset;
import jadx.api.plugins.input.data.MethodHandleType; import jadx.api.plugins.input.data.MethodHandleType;
...@@ -278,7 +279,7 @@ public class InsnGen { ...@@ -278,7 +279,7 @@ public class InsnGen {
makeInsnBody(code, insn, EMPTY_FLAGS); makeInsnBody(code, insn, EMPTY_FLAGS);
if (flag != Flags.INLINE) { if (flag != Flags.INLINE) {
code.add(';'); code.add(';');
CodeGenUtils.addCodeComments(code, insn); CodeGenUtils.addCodeComments(code, mth, insn);
} }
} }
} catch (Exception e) { } catch (Exception e) {
...@@ -608,7 +609,9 @@ public class InsnGen { ...@@ -608,7 +609,9 @@ public class InsnGen {
* Use one by one array fill (can be replaced with System.arrayCopy) * Use one by one array fill (can be replaced with System.arrayCopy)
*/ */
private void fillArray(ICodeWriter code, FillArrayInsn arrayNode) throws CodegenException { private void fillArray(ICodeWriter code, FillArrayInsn arrayNode) throws CodegenException {
code.add("// fill-array-data instruction"); if (mth.checkCommentsLevel(CommentsLevel.INFO)) {
code.add("// fill-array-data instruction");
}
code.startLine(); code.startLine();
InsnArg arrArg = arrayNode.getArg(0); InsnArg arrArg = arrayNode.getArg(0);
ArgType arrayType = arrArg.getType(); ArgType arrayType = arrArg.getType();
......
...@@ -9,6 +9,7 @@ import java.util.stream.Stream; ...@@ -9,6 +9,7 @@ import java.util.stream.Stream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.ICodeWriter; import jadx.api.ICodeWriter;
import jadx.api.data.annotations.InsnCodeOffset; import jadx.api.data.annotations.InsnCodeOffset;
import jadx.api.plugins.input.data.AccessFlags; import jadx.api.plugins.input.data.AccessFlags;
...@@ -110,12 +111,12 @@ public class MethodGen { ...@@ -110,12 +111,12 @@ public class MethodGen {
if (mth.getMethodInfo().hasAlias() && !ai.isConstructor()) { if (mth.getMethodInfo().hasAlias() && !ai.isConstructor()) {
CodeGenUtils.addRenamedComment(code, mth, mth.getName()); CodeGenUtils.addRenamedComment(code, mth, mth.getName());
} }
if (mth.contains(AFlag.INCONSISTENT_CODE)) { if (mth.contains(AFlag.INCONSISTENT_CODE) && mth.checkCommentsLevel(CommentsLevel.ERROR)) {
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */"); code.startLine("/* Code decompiled incorrectly, please refer to instructions dump */");
} }
code.startLineWithNum(mth.getSourceLine()); code.startLineWithNum(mth.getSourceLine());
code.add(ai.makeString()); code.add(ai.makeString(mth.checkCommentsLevel(CommentsLevel.INFO)));
if (clsAccFlags.isInterface() && !mth.isNoCode() && !mth.getAccessFlags().isStatic()) { if (clsAccFlags.isInterface() && !mth.isNoCode() && !mth.getAccessFlags().isStatic()) {
// add 'default' for method with code in interface // add 'default' for method with code in interface
code.add("default "); code.add("default ");
...@@ -171,8 +172,11 @@ public class MethodGen { ...@@ -171,8 +172,11 @@ public class MethodGen {
} }
if (!overrideAttr.isAtBaseMth()) { if (!overrideAttr.isAtBaseMth()) {
code.startLine("@Override"); code.startLine("@Override");
code.add(" // "); if (mth.checkCommentsLevel(CommentsLevel.INFO)) {
code.add(Utils.listToString(overrideAttr.getOverrideList(), ", ", md -> md.getMethodInfo().getDeclClass().getAliasFullName())); code.add(" // ");
code.add(Utils.listToString(overrideAttr.getOverrideList(), ", ",
md -> md.getMethodInfo().getDeclClass().getAliasFullName()));
}
} }
if (Consts.DEBUG) { if (Consts.DEBUG) {
code.startLine("// related by override: "); code.startLine("// related by override: ");
...@@ -217,7 +221,7 @@ public class MethodGen { ...@@ -217,7 +221,7 @@ public class MethodGen {
classGen.useType(code, elType); classGen.useType(code, elType);
code.add("..."); code.add("...");
} else { } else {
mth.addComment("JADX INFO: Last argument in varargs method is not array: " + var); mth.addWarnComment("Last argument in varargs method is not array: " + var);
classGen.useType(code, argType); classGen.useType(code, argType);
} }
} else { } else {
...@@ -261,23 +265,24 @@ public class MethodGen { ...@@ -261,23 +265,24 @@ public class MethodGen {
regionGen.makeRegion(code, mth.getRegion()); regionGen.makeRegion(code, mth.getRegion());
} catch (StackOverflowError | BootstrapMethodError e) { } catch (StackOverflowError | BootstrapMethodError e) {
mth.addError("Method code generation error", new JadxOverflowException("StackOverflow")); mth.addError("Method code generation error", new JadxOverflowException("StackOverflow"));
classGen.insertDecompilationProblems(code, mth); CodeGenUtils.addErrors(code, mth);
dumpInstructions(code); dumpInstructions(code);
} catch (Exception e) { } catch (Exception e) {
if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) { if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) {
throw e; throw e;
} }
mth.addError("Method code generation error", e); mth.addError("Method code generation error", e);
classGen.insertDecompilationProblems(code, mth); CodeGenUtils.addErrors(code, mth);
dumpInstructions(code); dumpInstructions(code);
} }
} }
public void dumpInstructions(ICodeWriter code) { public void dumpInstructions(ICodeWriter code) {
code.startLine("/*"); if (mth.checkCommentsLevel(CommentsLevel.ERROR)) {
addFallbackMethodCode(code, COMMENTED_DUMP); code.startLine("/*");
code.startLine("*/"); addFallbackMethodCode(code, COMMENTED_DUMP);
code.startLine("*/");
}
code.startLine("throw new UnsupportedOperationException(\"Method not decompiled: ") code.startLine("throw new UnsupportedOperationException(\"Method not decompiled: ")
.add(mth.getParentClass().getClassInfo().getAliasFullName()) .add(mth.getParentClass().getClassInfo().getAliasFullName())
.add('.') .add('.')
...@@ -313,7 +318,7 @@ public class MethodGen { ...@@ -313,7 +318,7 @@ public class MethodGen {
code.startLine("// Can't load method instructions."); code.startLine("// Can't load method instructions.");
return; return;
} }
if (fallbackOption == COMMENTED_DUMP) { if (fallbackOption == COMMENTED_DUMP && mth.getCommentsLevel() != CommentsLevel.DEBUG) {
long insnCountEstimate = Stream.of(insnArr) long insnCountEstimate = Stream.of(insnArr)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(insn -> insn.getType() != InsnType.NOP) .filter(insn -> insn.getType() != InsnType.NOP)
...@@ -386,7 +391,7 @@ public class MethodGen { ...@@ -386,7 +391,7 @@ public class MethodGen {
if (catchAttr != null) { if (catchAttr != null) {
code.add(" // " + catchAttr); code.add(" // " + catchAttr);
} }
CodeGenUtils.addCodeComments(code, insn); CodeGenUtils.addCodeComments(code, mth, insn);
} catch (Exception e) { } catch (Exception e) {
LOG.debug("Error generate fallback instruction: ", e.getCause()); LOG.debug("Error generate fallback instruction: ", e.getCause());
code.setIndent(startIndent); code.setIndent(startIndent);
......
...@@ -8,6 +8,7 @@ import java.util.Objects; ...@@ -8,6 +8,7 @@ import java.util.Objects;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.ICodeWriter; import jadx.api.ICodeWriter;
import jadx.api.data.ICodeComment; import jadx.api.data.ICodeComment;
import jadx.api.data.annotations.CustomOffsetRef; import jadx.api.data.annotations.CustomOffsetRef;
...@@ -86,7 +87,7 @@ public class RegionGen extends InsnGen { ...@@ -86,7 +87,7 @@ public class RegionGen extends InsnGen {
code.attachLineAnnotation(new CustomOffsetRef(offset, ICodeComment.AttachType.VAR_DECLARE)); code.attachLineAnnotation(new CustomOffsetRef(offset, ICodeComment.AttachType.VAR_DECLARE));
} }
} }
CodeGenUtils.addCodeComments(code, assignReg); CodeGenUtils.addCodeComments(code, mth, assignReg);
} }
private void makeRegionIndent(ICodeWriter code, IContainer region) throws CodegenException { private void makeRegionIndent(ICodeWriter code, IContainer region) throws CodegenException {
...@@ -131,7 +132,7 @@ public class RegionGen extends InsnGen { ...@@ -131,7 +132,7 @@ public class RegionGen extends InsnGen {
BlockNode blockNode = conditionBlocks.get(0); BlockNode blockNode = conditionBlocks.get(0);
InsnNode lastInsn = BlockUtils.getLastInsn(blockNode); InsnNode lastInsn = BlockUtils.getLastInsn(blockNode);
InsnCodeOffset.attach(code, lastInsn); InsnCodeOffset.attach(code, lastInsn);
CodeGenUtils.addCodeComments(code, lastInsn); CodeGenUtils.addCodeComments(code, mth, lastInsn);
} }
} }
makeRegionIndent(code, region.getThenRegion()); makeRegionIndent(code, region.getThenRegion());
...@@ -205,7 +206,7 @@ public class RegionGen extends InsnGen { ...@@ -205,7 +206,7 @@ public class RegionGen extends InsnGen {
code.add("; "); code.add("; ");
makeInsn(forLoop.getIncrInsn(), code, Flags.INLINE); makeInsn(forLoop.getIncrInsn(), code, Flags.INLINE);
code.add(") {"); code.add(") {");
CodeGenUtils.addCodeComments(code, condInsn); CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody()); makeRegionIndent(code, region.getBody());
code.startLine('}'); code.startLine('}');
return; return;
...@@ -217,7 +218,7 @@ public class RegionGen extends InsnGen { ...@@ -217,7 +218,7 @@ public class RegionGen extends InsnGen {
code.add(" : "); code.add(" : ");
addArg(code, forEachLoop.getIterableArg(), false); addArg(code, forEachLoop.getIterableArg(), false);
code.add(") {"); code.add(") {");
CodeGenUtils.addCodeComments(code, condInsn); CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody()); makeRegionIndent(code, region.getBody());
code.startLine('}'); code.startLine('}');
return; return;
...@@ -226,7 +227,7 @@ public class RegionGen extends InsnGen { ...@@ -226,7 +227,7 @@ public class RegionGen extends InsnGen {
} }
if (region.isConditionAtEnd()) { if (region.isConditionAtEnd()) {
code.add("do {"); code.add("do {");
CodeGenUtils.addCodeComments(code, condInsn); CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody()); makeRegionIndent(code, region.getBody());
code.startLineWithNum(region.getConditionSourceLine()); code.startLineWithNum(region.getConditionSourceLine());
code.add("} while ("); code.add("} while (");
...@@ -236,7 +237,7 @@ public class RegionGen extends InsnGen { ...@@ -236,7 +237,7 @@ public class RegionGen extends InsnGen {
code.add("while ("); code.add("while (");
conditionGen.add(code, condition); conditionGen.add(code, condition);
code.add(") {"); code.add(") {");
CodeGenUtils.addCodeComments(code, condInsn); CodeGenUtils.addCodeComments(code, mth, condInsn);
makeRegionIndent(code, region.getBody()); makeRegionIndent(code, region.getBody());
code.startLine('}'); code.startLine('}');
} }
...@@ -249,7 +250,7 @@ public class RegionGen extends InsnGen { ...@@ -249,7 +250,7 @@ public class RegionGen extends InsnGen {
code.add(") {"); code.add(") {");
InsnCodeOffset.attach(code, monitorEnterInsn); InsnCodeOffset.attach(code, monitorEnterInsn);
CodeGenUtils.addCodeComments(code, monitorEnterInsn); CodeGenUtils.addCodeComments(code, mth, monitorEnterInsn);
makeRegionIndent(code, cont.getRegion()); makeRegionIndent(code, cont.getRegion());
code.startLine('}'); code.startLine('}');
...@@ -263,7 +264,7 @@ public class RegionGen extends InsnGen { ...@@ -263,7 +264,7 @@ public class RegionGen extends InsnGen {
addArg(code, arg, false); addArg(code, arg, false);
code.add(") {"); code.add(") {");
InsnCodeOffset.attach(code, insn); InsnCodeOffset.attach(code, insn);
CodeGenUtils.addCodeComments(code, insn); CodeGenUtils.addCodeComments(code, mth, insn);
code.incIndent(); code.incIndent();
for (CaseInfo caseInfo : sw.getCases()) { for (CaseInfo caseInfo : sw.getCases()) {
...@@ -291,10 +292,12 @@ public class RegionGen extends InsnGen { ...@@ -291,10 +292,12 @@ public class RegionGen extends InsnGen {
code.add(fn.getAlias()); code.add(fn.getAlias());
} else { } else {
staticField(code, fn.getFieldInfo()); staticField(code, fn.getFieldInfo());
// print original value, sometimes replaced with incorrect field if (mth.checkCommentsLevel(CommentsLevel.INFO)) {
EncodedValue constVal = fn.get(JadxAttrType.CONSTANT_VALUE); // print original value, sometimes replaced with incorrect field
if (constVal != null && constVal.getValue() != null) { EncodedValue constVal = fn.get(JadxAttrType.CONSTANT_VALUE);
code.add(" /* ").add(constVal.getValue().toString()).add(" */"); if (constVal != null && constVal.getValue() != null) {
code.add(" /* ").add(constVal.getValue().toString()).add(" */");
}
} }
} }
} else if (k instanceof Integer) { } else if (k instanceof Integer) {
...@@ -309,7 +312,7 @@ public class RegionGen extends InsnGen { ...@@ -309,7 +312,7 @@ public class RegionGen extends InsnGen {
InsnNode insn = BlockUtils.getFirstInsn(Utils.first(region.getTryCatchBlock().getBlocks())); InsnNode insn = BlockUtils.getFirstInsn(Utils.first(region.getTryCatchBlock().getBlocks()));
InsnCodeOffset.attach(code, insn); InsnCodeOffset.attach(code, insn);
CodeGenUtils.addCodeComments(code, insn); CodeGenUtils.addCodeComments(code, mth, insn);
makeRegionIndent(code, region.getTryRegion()); makeRegionIndent(code, region.getTryRegion());
// TODO: move search of 'allHandler' to 'TryCatchRegion' // TODO: move search of 'allHandler' to 'TryCatchRegion'
...@@ -388,7 +391,7 @@ public class RegionGen extends InsnGen { ...@@ -388,7 +391,7 @@ public class RegionGen extends InsnGen {
code.add(") {"); code.add(") {");
InsnCodeOffset.attach(code, handler.getHandlerOffset()); InsnCodeOffset.attach(code, handler.getHandlerOffset());
CodeGenUtils.addCodeComments(code, handler.getHandlerBlock()); CodeGenUtils.addCodeComments(code, mth, handler.getHandlerBlock());
makeRegionIndent(code, region); makeRegionIndent(code, region);
} }
......
...@@ -85,8 +85,7 @@ public class JsonCodeGen { ...@@ -85,8 +85,7 @@ public class JsonCodeGen {
} }
ICodeWriter cw = new SimpleCodeWriter(); ICodeWriter cw = new SimpleCodeWriter();
CodeGenUtils.addComments(cw, cls); CodeGenUtils.addErrorsAndComments(cw, cls);
classGen.insertDecompilationProblems(cw, cls);
classGen.addClassDeclaration(cw); classGen.addClassDeclaration(cw);
jsonCls.setDeclaration(cw.getCodeStr()); jsonCls.setDeclaration(cw.getCodeStr());
......
...@@ -10,6 +10,7 @@ import jadx.core.dex.attributes.nodes.EnumMapAttr; ...@@ -10,6 +10,7 @@ import jadx.core.dex.attributes.nodes.EnumMapAttr;
import jadx.core.dex.attributes.nodes.FieldReplaceAttr; import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.ForceReturnAttr; import jadx.core.dex.attributes.nodes.ForceReturnAttr;
import jadx.core.dex.attributes.nodes.GenericInfoAttr; import jadx.core.dex.attributes.nodes.GenericInfoAttr;
import jadx.core.dex.attributes.nodes.JadxCommentsAttr;
import jadx.core.dex.attributes.nodes.JadxError; import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JumpInfo; import jadx.core.dex.attributes.nodes.JumpInfo;
import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr; import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr;
...@@ -43,9 +44,8 @@ public final class AType<T extends IJadxAttribute> implements IJadxAttrType<T> { ...@@ -43,9 +44,8 @@ public final class AType<T extends IJadxAttribute> implements IJadxAttrType<T> {
public static final AType<RenameReasonAttr> RENAME_REASON = new AType<>(); public static final AType<RenameReasonAttr> RENAME_REASON = new AType<>();
// class, method // class, method
public static final AType<AttrList<JadxError>> JADX_ERROR = new AType<>(); // code failed to decompile completely public static final AType<AttrList<JadxError>> JADX_ERROR = new AType<>(); // code failed to decompile
public static final AType<AttrList<String>> JADX_WARN = new AType<>(); // mark code as inconsistent (code can be viewed) public static final AType<JadxCommentsAttr> JADX_COMMENTS = new AType<>(); // additional info about decompilation
public static final AType<AttrList<String>> COMMENTS = new AType<>(); // any additional info about decompilation
// class // class
public static final AType<EnumClassAttr> ENUM_CLASS = new AType<>(); public static final AType<EnumClassAttr> ENUM_CLASS = new AType<>();
......
package jadx.core.dex.attributes.nodes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import jadx.api.CommentsLevel;
import jadx.api.plugins.input.data.attributes.IJadxAttrType;
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
import jadx.core.dex.attributes.AType;
public class JadxCommentsAttr implements IJadxAttribute {
private final Map<CommentsLevel, List<String>> comments = new EnumMap<>(CommentsLevel.class);
public void add(CommentsLevel level, String comment) {
comments.computeIfAbsent(level, (l) -> new ArrayList<>()).add(comment);
}
public List<String> formatAndFilter(CommentsLevel level) {
if (level == CommentsLevel.NONE || level == CommentsLevel.USER_ONLY) {
return Collections.emptyList();
}
return comments.entrySet().stream()
.filter(e -> e.getKey().filter(level))
.flatMap(e -> {
String levelName = e.getKey().name();
return e.getValue().stream()
.map(v -> "JADX " + levelName + ": " + v);
})
.distinct()
.sorted()
.collect(Collectors.toList());
}
public Map<CommentsLevel, List<String>> getComments() {
return comments;
}
@Override
public IJadxAttrType<JadxCommentsAttr> getAttrType() {
return AType.JADX_COMMENTS;
}
}
...@@ -27,7 +27,7 @@ public class MethodInlineAttr extends PinnedAttribute { ...@@ -27,7 +27,7 @@ public class MethodInlineAttr extends PinnedAttribute {
MethodInlineAttr mia = new MethodInlineAttr(replaceInsn, regNums); MethodInlineAttr mia = new MethodInlineAttr(replaceInsn, regNums);
mth.addAttr(mia); mth.addAttr(mia);
if (Consts.DEBUG) { if (Consts.DEBUG) {
mth.addAttr(AType.COMMENTS, "Removed for inline"); mth.addDebugComment("Removed for inline");
} else { } else {
mth.add(AFlag.DONT_GENERATE); mth.add(AFlag.DONT_GENERATE);
} }
......
package jadx.core.dex.attributes.nodes; package jadx.core.dex.attributes.nodes;
import org.jetbrains.annotations.Nullable; import jadx.api.CommentsLevel;
import org.slf4j.Logger; import jadx.api.ICodeWriter;
import org.slf4j.LoggerFactory; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.nodes.ICodeNode; import jadx.core.dex.nodes.ICodeNode;
import jadx.core.utils.ErrorsCounter; import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.Utils;
public abstract class NotificationAttrNode extends LineAttrNode implements ICodeNode { public abstract class NotificationAttrNode extends LineAttrNode implements ICodeNode {
private static final Logger LOG = LoggerFactory.getLogger(NotificationAttrNode.class);
public boolean checkCommentsLevel(CommentsLevel required) {
return required.filter(this.root().getArgs().getCommentsLevel());
}
public void addError(String errStr, Throwable e) { public void addError(String errStr, Throwable e) {
ErrorsCounter.error(this, errStr, e); ErrorsCounter.error(this, errStr, e);
} }
public void addWarn(String warnStr) { public void addWarn(String warn) {
ErrorsCounter.warning(this, warnStr); ErrorsCounter.warning(this, warn);
initCommentsAttr().add(CommentsLevel.WARN, warn);
this.add(AFlag.INCONSISTENT_CODE);
} }
public void addWarnComment(String warn) { public void addWarnComment(String warn) {
addWarnComment(warn, null); initCommentsAttr().add(CommentsLevel.WARN, warn);
} }
public void addWarnComment(String warn, @Nullable Throwable exc) { public void addWarnComment(String warn, Throwable exc) {
String commentStr = "JADX WARN: " + warn; String commentStr = warn + ICodeWriter.NL + Utils.getStackTrace(exc);
addAttr(AType.COMMENTS, commentStr); initCommentsAttr().add(CommentsLevel.WARN, commentStr);
if (exc != null) {
LOG.warn("{} in {}", warn, this, exc);
} else {
LOG.warn("{} in {}", warn, this);
}
} }
public void addComment(String commentStr) { public void addInfoComment(String commentStr) {
addAttr(AType.COMMENTS, commentStr); initCommentsAttr().add(CommentsLevel.INFO, commentStr);
} }
public void addDebugComment(String commentStr) { public void addDebugComment(String commentStr) {
addAttr(AType.COMMENTS, "JADX DEBUG: " + commentStr); initCommentsAttr().add(CommentsLevel.DEBUG, commentStr);
}
public CommentsLevel getCommentsLevel() {
return this.root().getArgs().getCommentsLevel();
}
private JadxCommentsAttr initCommentsAttr() {
JadxCommentsAttr commentsAttr = this.get(AType.JADX_COMMENTS);
if (commentsAttr == null) {
commentsAttr = new JadxCommentsAttr();
this.addAttr(commentsAttr);
}
return commentsAttr;
} }
} }
...@@ -155,7 +155,7 @@ public class AccessInfo { ...@@ -155,7 +155,7 @@ public class AccessInfo {
return type; return type;
} }
public String makeString() { public String makeString(boolean showHidden) {
StringBuilder code = new StringBuilder(); StringBuilder code = new StringBuilder();
if (isPublic()) { if (isPublic()) {
code.append("public "); code.append("public ");
...@@ -183,11 +183,13 @@ public class AccessInfo { ...@@ -183,11 +183,13 @@ public class AccessInfo {
if (isSynchronized()) { if (isSynchronized()) {
code.append("synchronized "); code.append("synchronized ");
} }
if (isBridge()) { if (showHidden) {
code.append("/* bridge */ "); if (isBridge()) {
} code.append("/* bridge */ ");
if (Consts.DEBUG && isVarArgs()) { }
code.append("/* varargs */ "); if (Consts.DEBUG && isVarArgs()) {
code.append("/* varargs */ ");
}
} }
break; break;
...@@ -204,20 +206,22 @@ public class AccessInfo { ...@@ -204,20 +206,22 @@ public class AccessInfo {
if ((accFlags & AccessFlags.STRICT) != 0) { if ((accFlags & AccessFlags.STRICT) != 0) {
code.append("strict "); code.append("strict ");
} }
if (isModuleInfo()) { if (showHidden) {
code.append("/* module-info */ "); if (isModuleInfo()) {
} code.append("/* module-info */ ");
if (Consts.DEBUG) {
if ((accFlags & AccessFlags.SUPER) != 0) {
code.append("/* super */ ");
} }
if ((accFlags & AccessFlags.ENUM) != 0) { if (Consts.DEBUG) {
code.append("/* enum */ "); if ((accFlags & AccessFlags.SUPER) != 0) {
code.append("/* super */ ");
}
if ((accFlags & AccessFlags.ENUM) != 0) {
code.append("/* enum */ ");
}
} }
} }
break; break;
} }
if (isSynthetic()) { if (isSynthetic() && showHidden) {
code.append("/* synthetic */ "); code.append("/* synthetic */ ");
} }
return code.toString(); return code.toString();
...@@ -245,6 +249,6 @@ public class AccessInfo { ...@@ -245,6 +249,6 @@ public class AccessInfo {
@Override @Override
public String toString() { public String toString() {
return "AccessInfo: " + type + " 0x" + Integer.toHexString(accFlags) + " (" + makeString() + ')'; return "AccessInfo: " + type + " 0x" + Integer.toHexString(accFlags) + " (" + makeString(true) + ')';
} }
} }
...@@ -4,13 +4,13 @@ import java.util.Collections; ...@@ -4,13 +4,13 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import jadx.api.plugins.input.data.IFieldData; import jadx.api.plugins.input.data.IFieldData;
import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.attributes.nodes.NotificationAttrNode;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.AccessInfo.AFType; import jadx.core.dex.info.AccessInfo.AFType;
import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
public class FieldNode extends LineAttrNode implements ICodeNode { public class FieldNode extends NotificationAttrNode implements ICodeNode {
private final ClassNode parentClass; private final ClassNode parentClass;
private final FieldInfo fieldInfo; private final FieldInfo fieldInfo;
......
...@@ -22,7 +22,6 @@ import jadx.api.plugins.input.data.IClassData; ...@@ -22,7 +22,6 @@ import jadx.api.plugins.input.data.IClassData;
import jadx.api.plugins.input.data.ILoadResult; import jadx.api.plugins.input.data.ILoadResult;
import jadx.core.Jadx; import jadx.core.Jadx;
import jadx.core.clsp.ClspGraph; import jadx.core.clsp.ClspGraph;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.ConstStorage; import jadx.core.dex.info.ConstStorage;
import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.FieldInfo;
...@@ -146,7 +145,7 @@ public class RootNode { ...@@ -146,7 +145,7 @@ public class RootNode {
.filter(s -> !s.equals(thisSource)) .filter(s -> !s.equals(thisSource))
.sorted() .sorted()
.collect(Collectors.joining("\n ")); .collect(Collectors.joining("\n "));
cls.addAttr(AType.COMMENTS, "WARNING: Classes with same name are omitted:\n " + otherSourceStr + '\n'); cls.addWarnComment("Classes with same name are omitted:\n " + otherSourceStr + '\n');
}); });
}); });
} }
......
...@@ -23,8 +23,8 @@ import jadx.core.dex.nodes.MethodNode; ...@@ -23,8 +23,8 @@ import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
@JadxVisitor( @JadxVisitor(
name = "Attach comments", name = "AttachComments",
desc = "Attach comments", desc = "Attach user code comments",
runBefore = { runBefore = {
ProcessInstructionsVisitor.class ProcessInstructionsVisitor.class
} }
......
...@@ -7,7 +7,6 @@ import java.util.Objects; ...@@ -7,7 +7,6 @@ import java.util.Objects;
import jadx.api.plugins.input.data.AccessFlags; import jadx.api.plugins.input.data.AccessFlags;
import jadx.core.Consts; import jadx.core.Consts;
import jadx.core.dex.attributes.AFlag; 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.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr; import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
...@@ -149,7 +148,7 @@ public class ClassModifier extends AbstractVisitor { ...@@ -149,7 +148,7 @@ public class ClassModifier extends AbstractVisitor {
ClassNode cls = mth.getParentClass(); ClassNode cls = mth.getParentClass();
if (removeBridgeMethod(cls, mth)) { if (removeBridgeMethod(cls, mth)) {
if (Consts.DEBUG) { if (Consts.DEBUG) {
mth.addAttr(AType.COMMENTS, "Removed as synthetic bridge method"); mth.addDebugComment("Removed as synthetic bridge method");
} else { } else {
mth.add(AFlag.DONT_GENERATE); mth.add(AFlag.DONT_GENERATE);
} }
......
...@@ -116,7 +116,7 @@ public class DotGraphVisitor extends AbstractVisitor { ...@@ -116,7 +116,7 @@ public class DotGraphVisitor extends AbstractVisitor {
} }
dot.startLine("MethodNode[shape=record,label=\"{"); dot.startLine("MethodNode[shape=record,label=\"{");
dot.add(escape(mth.getAccessFlags().makeString())); dot.add(escape(mth.getAccessFlags().makeString(true)));
dot.add(escape(mth.getReturnType() + " " dot.add(escape(mth.getReturnType() + " "
+ mth.getParentClass() + '.' + mth.getName() + mth.getParentClass() + '.' + mth.getName()
+ '(' + Utils.listToString(mth.getAllArgRegs()) + ") ")); + '(' + Utils.listToString(mth.getAllArgRegs()) + ") "));
......
...@@ -15,7 +15,6 @@ import jadx.api.plugins.input.data.AccessFlags; ...@@ -15,7 +15,6 @@ import jadx.api.plugins.input.data.AccessFlags;
import jadx.core.codegen.TypeGen; import jadx.core.codegen.TypeGen;
import jadx.core.deobf.NameMapper; import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.EnumClassAttr; import jadx.core.dex.attributes.nodes.EnumClassAttr;
import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField; import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField;
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr; import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
...@@ -76,7 +75,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -76,7 +75,7 @@ public class EnumVisitor extends AbstractVisitor {
AccessInfo accessFlags = cls.getAccessFlags(); AccessInfo accessFlags = cls.getAccessFlags();
if (accessFlags.isEnum()) { if (accessFlags.isEnum()) {
cls.setAccessFlags(accessFlags.remove(AccessFlags.ENUM)); cls.setAccessFlags(accessFlags.remove(AccessFlags.ENUM));
cls.addAttr(AType.COMMENTS, "JADX INFO: Failed to restore enum class, 'enum' modifier removed"); cls.addWarnComment("Failed to restore enum class, 'enum' modifier removed");
} }
} }
return true; return true;
...@@ -88,7 +87,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -88,7 +87,7 @@ public class EnumVisitor extends AbstractVisitor {
} }
MethodNode classInitMth = cls.getClassInitMth(); MethodNode classInitMth = cls.getClassInitMth();
if (classInitMth == null) { if (classInitMth == null) {
cls.addAttr(AType.COMMENTS, "JADX INFO: Enum class init method not found"); cls.addWarnComment("Enum class init method not found");
return false; return false;
} }
if (classInitMth.getBasicBlocks().isEmpty()) { if (classInitMth.getBasicBlocks().isEmpty()) {
...@@ -117,7 +116,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -117,7 +116,7 @@ public class EnumVisitor extends AbstractVisitor {
} }
} }
if (valuesCandidates.size() != 1) { if (valuesCandidates.size() != 1) {
cls.addAttr(AType.COMMENTS, "JADX INFO: found several \"values\" enum fields: " + valuesCandidates); cls.addWarnComment("Found several \"values\" enum fields: " + valuesCandidates);
return false; return false;
} }
FieldNode valuesField = valuesCandidates.get(0); FieldNode valuesField = valuesCandidates.get(0);
...@@ -352,7 +351,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -352,7 +351,7 @@ public class EnumVisitor extends AbstractVisitor {
FieldInfo fldInfo = FieldInfo.from(cls.root(), cls.getClassInfo(), name, cls.getType()); FieldInfo fldInfo = FieldInfo.from(cls.root(), cls.getClassInfo(), name, cls.getType());
enumFieldNode = new FieldNode(cls, fldInfo, 0); enumFieldNode = new FieldNode(cls, fldInfo, 0);
enumFieldNode.add(AFlag.SYNTHETIC); enumFieldNode.add(AFlag.SYNTHETIC);
enumFieldNode.addAttr(AType.COMMENTS, "Fake field, exist only in values array"); enumFieldNode.addInfoComment("Fake field, exist only in values array");
return enumFieldNode; return enumFieldNode;
} }
......
...@@ -4,9 +4,9 @@ import jadx.api.plugins.input.data.AccessFlags; ...@@ -4,9 +4,9 @@ import jadx.api.plugins.input.data.AccessFlags;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.MethodOverrideAttr; import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
import jadx.core.dex.attributes.nodes.NotificationAttrNode;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.ICodeNode;
import jadx.core.dex.nodes.IMethodDetails; import jadx.core.dex.nodes.IMethodDetails;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
...@@ -49,12 +49,12 @@ public class FixAccessModifiers extends AbstractVisitor { ...@@ -49,12 +49,12 @@ public class FixAccessModifiers extends AbstractVisitor {
} }
} }
public static void changeVisibility(ICodeNode node, int newVisFlag) { public static void changeVisibility(NotificationAttrNode node, int newVisFlag) {
AccessInfo accessFlags = node.getAccessFlags(); AccessInfo accessFlags = node.getAccessFlags();
AccessInfo newAccFlags = accessFlags.changeVisibility(newVisFlag); AccessInfo newAccFlags = accessFlags.changeVisibility(newVisFlag);
if (newAccFlags != accessFlags) { if (newAccFlags != accessFlags) {
node.setAccessFlags(newAccFlags); node.setAccessFlags(newAccFlags);
node.addAttr(AType.COMMENTS, "access modifiers changed from: " + accessFlags.visibilityName()); node.addInfoComment("Access modifiers changed from: " + accessFlags.visibilityName());
} }
} }
......
...@@ -132,7 +132,7 @@ public class MarkMethodsForInline extends AbstractVisitor { ...@@ -132,7 +132,7 @@ public class MarkMethodsForInline extends AbstractVisitor {
} }
} }
if (Consts.DEBUG) { if (Consts.DEBUG) {
mth.addAttr(AType.COMMENTS, "JADX DEBUG: can't inline method, not implemented redirect type: " + insn); mth.addDebugComment("can't inline method, not implemented redirect type: " + insn);
} }
return false; return false;
} }
......
...@@ -80,7 +80,7 @@ public class MethodInvokeVisitor extends AbstractVisitor { ...@@ -80,7 +80,7 @@ public class MethodInvokeVisitor extends AbstractVisitor {
IMethodDetails mthDetails = root.getMethodUtils().getMethodDetails(invokeInsn); IMethodDetails mthDetails = root.getMethodUtils().getMethodDetails(invokeInsn);
if (mthDetails == null) { if (mthDetails == null) {
if (Consts.DEBUG) { if (Consts.DEBUG) {
parentMth.addComment("JADX DEBUG: Method info not found: " + callMth); parentMth.addDebugComment("Method info not found: " + callMth);
} }
processUnknown(invokeInsn); processUnknown(invokeInsn);
} else { } else {
...@@ -276,7 +276,7 @@ public class MethodInvokeVisitor extends AbstractVisitor { ...@@ -276,7 +276,7 @@ public class MethodInvokeVisitor extends AbstractVisitor {
} }
if (Consts.DEBUG_OVERLOADED_CASTS) { if (Consts.DEBUG_OVERLOADED_CASTS) {
// TODO: try to minimize casts count // TODO: try to minimize casts count
parentMth.addComment("JADX DEBUG: Failed to find minimal casts for resolve overloaded methods, cast all args instead" parentMth.addDebugComment("Failed to find minimal casts for resolve overloaded methods, cast all args instead"
+ ICodeWriter.NL + " method: " + mthDetails + ICodeWriter.NL + " method: " + mthDetails
+ ICodeWriter.NL + " arg types: " + compilerVarTypes + ICodeWriter.NL + " arg types: " + compilerVarTypes
+ ICodeWriter.NL + " candidates:" + ICodeWriter.NL + " candidates:"
......
...@@ -253,7 +253,7 @@ public class OverrideMethodVisitor extends AbstractVisitor { ...@@ -253,7 +253,7 @@ public class OverrideMethodVisitor extends AbstractVisitor {
return; return;
} }
if (updateReturnType(mth, baseMth, superTypes)) { if (updateReturnType(mth, baseMth, superTypes)) {
mth.addComment("Return type fixed from '" + returnType + "' to match base method"); mth.addInfoComment("Return type fixed from '" + returnType + "' to match base method");
} }
} }
......
...@@ -231,11 +231,11 @@ public class PrepareForCodeGen extends AbstractVisitor { ...@@ -231,11 +231,11 @@ public class PrepareForCodeGen extends AbstractVisitor {
Set<RegisterArg> regArgs = new HashSet<>(); Set<RegisterArg> regArgs = new HashSet<>();
constrInsn.getRegisterArgs(regArgs); constrInsn.getRegisterArgs(regArgs);
regArgs.remove(mth.getThisArg()); regArgs.remove(mth.getThisArg());
regArgs.removeAll(mth.getArgRegs()); mth.getArgRegs().forEach(regArgs::remove);
if (!regArgs.isEmpty()) { if (!regArgs.isEmpty()) {
mth.addWarn("Illegal instructions before constructor call"); mth.addWarn("Illegal instructions before constructor call");
} else { } else {
mth.addComment("JADX INFO: '" + callType + "' call moved to the top of the method (can break code semantics)"); mth.addWarnComment("'" + callType + "' call moved to the top of the method (can break code semantics)");
} }
} }
} }
......
...@@ -31,7 +31,6 @@ import jadx.core.dex.visitors.ssa.SSATransform; ...@@ -31,7 +31,6 @@ import jadx.core.dex.visitors.ssa.SSATransform;
import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor; import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor;
import jadx.core.dex.visitors.typeinference.TypeUpdateResult; import jadx.core.dex.visitors.typeinference.TypeUpdateResult;
import jadx.core.utils.BlockUtils; import jadx.core.utils.BlockUtils;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
@JadxVisitor( @JadxVisitor(
...@@ -54,7 +53,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor { ...@@ -54,7 +53,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
} }
checkTypes(mth); checkTypes(mth);
} catch (Exception e) { } catch (Exception e) {
LOG.error("Error to apply debug info: {}", ErrorsCounter.formatMsg(mth, e.getMessage()), e); mth.addWarnComment("Failed to apply debug info", e);
} }
} }
...@@ -94,7 +93,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor { ...@@ -94,7 +93,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
RegDebugInfoAttr debugInfo = debugInfoSet.iterator().next(); RegDebugInfoAttr debugInfo = debugInfoSet.iterator().next();
applyDebugInfo(mth, ssaVar, debugInfo.getRegType(), debugInfo.getName()); applyDebugInfo(mth, ssaVar, debugInfo.getRegType(), debugInfo.getName());
} else { } else {
mth.addComment("JADX INFO: Multiple debug info for " + ssaVar + ": " + debugInfoSet); mth.addInfoComment("Multiple debug info for " + ssaVar + ": " + debugInfoSet);
for (RegDebugInfoAttr debugInfo : debugInfoSet) { for (RegDebugInfoAttr debugInfo : debugInfoSet) {
applyDebugInfo(mth, ssaVar, debugInfo.getRegType(), debugInfo.getName()); applyDebugInfo(mth, ssaVar, debugInfo.getRegType(), debugInfo.getName());
} }
...@@ -207,7 +206,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor { ...@@ -207,7 +206,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
if (names.size() == 1) { if (names.size() == 1) {
setNameForInsn(phiInsn, names.iterator().next()); setNameForInsn(phiInsn, names.iterator().next());
} else if (names.size() > 1) { } else if (names.size() > 1) {
LOG.warn("Different names in phi insn: {}, use first", names); mth.addDebugComment("Different variable names in phi insn: " + names + ", use first");
setNameForInsn(phiInsn, names.iterator().next()); setNameForInsn(phiInsn, names.iterator().next());
} }
} }
......
...@@ -3,10 +3,6 @@ package jadx.core.dex.visitors.debuginfo; ...@@ -3,10 +3,6 @@ package jadx.core.dex.visitors.debuginfo;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.ICodeWriter;
import jadx.api.plugins.input.data.IDebugInfo; import jadx.api.plugins.input.data.IDebugInfo;
import jadx.api.plugins.input.data.ILocalVar; import jadx.api.plugins.input.data.ILocalVar;
import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr; import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr;
...@@ -21,8 +17,6 @@ import jadx.core.dex.visitors.AbstractVisitor; ...@@ -21,8 +17,6 @@ import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.dex.visitors.JadxVisitor; import jadx.core.dex.visitors.JadxVisitor;
import jadx.core.dex.visitors.blocks.BlockSplitter; import jadx.core.dex.visitors.blocks.BlockSplitter;
import jadx.core.dex.visitors.ssa.SSATransform; import jadx.core.dex.visitors.ssa.SSATransform;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
@JadxVisitor( @JadxVisitor(
...@@ -35,8 +29,6 @@ import jadx.core.utils.exceptions.JadxException; ...@@ -35,8 +29,6 @@ import jadx.core.utils.exceptions.JadxException;
) )
public class DebugInfoAttachVisitor extends AbstractVisitor { public class DebugInfoAttachVisitor extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(DebugInfoAttachVisitor.class);
@Override @Override
public void visit(MethodNode mth) throws JadxException { public void visit(MethodNode mth) throws JadxException {
try { try {
...@@ -45,9 +37,7 @@ public class DebugInfoAttachVisitor extends AbstractVisitor { ...@@ -45,9 +37,7 @@ public class DebugInfoAttachVisitor extends AbstractVisitor {
processDebugInfo(mth, debugInfo); processDebugInfo(mth, debugInfo);
} }
} catch (Exception e) { } catch (Exception e) {
mth.addComment("JADX WARNING: Error to parse debug info: " mth.addWarnComment("Failed to parse debug info", e);
+ ErrorsCounter.formatMsg(mth, e.getMessage())
+ ICodeWriter.NL + Utils.getStackTrace(e));
} }
} }
...@@ -129,21 +119,21 @@ public class DebugInfoAttachVisitor extends AbstractVisitor { ...@@ -129,21 +119,21 @@ public class DebugInfoAttachVisitor extends AbstractVisitor {
try { try {
ArgType gType = new SignatureParser(sign).consumeType(); ArgType gType = new SignatureParser(sign).consumeType();
ArgType expandedType = mth.root().getTypeUtils().expandTypeVariables(mth, gType); ArgType expandedType = mth.root().getTypeUtils().expandTypeVariables(mth, gType);
if (checkSignature(type, expandedType)) { if (checkSignature(mth, type, expandedType)) {
return expandedType; return expandedType;
} }
} catch (Exception e) { } catch (Exception e) {
LOG.error("Can't parse signature for local variable: {}", sign, e); mth.addWarnComment("Can't parse signature for local variable: " + sign, e);
} }
return type; return type;
} }
private static boolean checkSignature(ArgType type, ArgType gType) { private static boolean checkSignature(MethodNode mth, ArgType type, ArgType gType) {
boolean apply; boolean apply;
ArgType el = gType.getArrayRootElement(); ArgType el = gType.getArrayRootElement();
if (el.isGeneric()) { if (el.isGeneric()) {
if (!type.getArrayRootElement().getObject().equals(el.getObject())) { if (!type.getArrayRootElement().getObject().equals(el.getObject())) {
LOG.warn("Generic type in debug info not equals: {} != {}", type, gType); mth.addWarnComment("Generic types in debug info not equals: " + type + " != " + gType);
} }
apply = true; apply = true;
} else { } else {
......
...@@ -179,7 +179,7 @@ public class MarkFinallyVisitor extends AbstractVisitor { ...@@ -179,7 +179,7 @@ public class MarkFinallyVisitor extends AbstractVisitor {
return false; return false;
} }
if (!checkSlices(extractInfo)) { if (!checkSlices(extractInfo)) {
mth.addComment("JADX INFO: finally extract failed"); mth.addWarnComment("Finally extract failed");
return false; return false;
} }
......
...@@ -44,7 +44,6 @@ import jadx.core.dex.trycatch.ExcHandlerAttr; ...@@ -44,7 +44,6 @@ import jadx.core.dex.trycatch.ExcHandlerAttr;
import jadx.core.dex.trycatch.ExceptionHandler; import jadx.core.dex.trycatch.ExceptionHandler;
import jadx.core.dex.trycatch.TryCatchBlockAttr; import jadx.core.dex.trycatch.TryCatchBlockAttr;
import jadx.core.utils.BlockUtils; import jadx.core.utils.BlockUtils;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.RegionUtils; import jadx.core.utils.RegionUtils;
import jadx.core.utils.Utils; import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxOverflowException; import jadx.core.utils.exceptions.JadxOverflowException;
...@@ -839,7 +838,7 @@ public class RegionMaker { ...@@ -839,7 +838,7 @@ public class RegionMaker {
if (!fallThroughCases.isEmpty() && isBadCasesOrder(blocksMap, fallThroughCases)) { if (!fallThroughCases.isEmpty() && isBadCasesOrder(blocksMap, fallThroughCases)) {
Map<BlockNode, List<Object>> newBlocksMap = reOrderSwitchCases(blocksMap, fallThroughCases); Map<BlockNode, List<Object>> newBlocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
if (isBadCasesOrder(newBlocksMap, fallThroughCases)) { if (isBadCasesOrder(newBlocksMap, fallThroughCases)) {
mth.addComment("JADX INFO: Can't fix incorrect switch cases order, some code will duplicate"); mth.addWarnComment("Can't fix incorrect switch cases order, some code will duplicate");
fallThroughCases.clear(); fallThroughCases.clear();
} else { } else {
blocksMap = newBlocksMap; blocksMap = newBlocksMap;
...@@ -1019,7 +1018,7 @@ public class RegionMaker { ...@@ -1019,7 +1018,7 @@ public class RegionMaker {
blocks.add(handlerBlock); blocks.add(handlerBlock);
splitters.add(BlockUtils.getTopSplitterForHandler(handlerBlock)); splitters.add(BlockUtils.getTopSplitterForHandler(handlerBlock));
} else { } else {
LOG.debug(ErrorsCounter.formatMsg(mth, "No exception handler block: " + handler)); mth.addDebugComment("No exception handler block: " + handler);
} }
} }
Set<BlockNode> exits = new HashSet<>(); Set<BlockNode> exits = new HashSet<>();
...@@ -1030,7 +1029,7 @@ public class RegionMaker { ...@@ -1030,7 +1029,7 @@ public class RegionMaker {
} }
List<BlockNode> s = splitter.getSuccessors(); List<BlockNode> s = splitter.getSuccessors();
if (s.isEmpty()) { if (s.isEmpty()) {
LOG.debug(ErrorsCounter.formatMsg(mth, "No successors for splitter: " + splitter)); mth.addDebugComment("No successors for splitter: " + splitter);
continue; continue;
} }
BlockNode ss = s.get(0); BlockNode ss = s.get(0);
......
...@@ -100,7 +100,7 @@ public class TypeSearch { ...@@ -100,7 +100,7 @@ public class TypeSearch {
for (TypeSearchVarInfo var : updatedVars) { for (TypeSearchVarInfo var : updatedVars) {
TypeUpdateResult res = typeUpdate.applyWithWiderIgnSame(mth, var.getVar(), var.getCurrentType()); TypeUpdateResult res = typeUpdate.applyWithWiderIgnSame(mth, var.getVar(), var.getCurrentType());
if (res == TypeUpdateResult.REJECT) { if (res == TypeUpdateResult.REJECT) {
mth.addComment("JADX DEBUG: Multi-variable search result rejected for " + var); mth.addDebugComment("Multi-variable search result rejected for " + var);
applySuccess = false; applySuccess = false;
} }
} }
......
...@@ -5,12 +5,15 @@ import java.util.List; ...@@ -5,12 +5,15 @@ import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import jadx.api.CodePosition; import jadx.api.CodePosition;
import jadx.api.CommentsLevel;
import jadx.api.ICodeWriter; import jadx.api.ICodeWriter;
import jadx.api.plugins.input.data.attributes.JadxAttrType; import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.types.SourceFileAttr; import jadx.api.plugins.input.data.attributes.types.SourceFileAttr;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.AttrNode;
import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.attributes.nodes.JadxCommentsAttr;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.NotificationAttrNode;
import jadx.core.dex.attributes.nodes.RenameReasonAttr; import jadx.core.dex.attributes.nodes.RenameReasonAttr;
import jadx.core.dex.instructions.args.CodeVar; import jadx.core.dex.instructions.args.CodeVar;
import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.RegisterArg;
...@@ -20,16 +23,49 @@ import jadx.core.dex.nodes.ICodeNode; ...@@ -20,16 +23,49 @@ import jadx.core.dex.nodes.ICodeNode;
public class CodeGenUtils { public class CodeGenUtils {
public static void addComments(ICodeWriter code, IAttributeNode node) { public static void addErrorsAndComments(ICodeWriter code, NotificationAttrNode node) {
List<String> comments = node.getAll(AType.COMMENTS); addErrors(code, node);
if (!comments.isEmpty()) { addComments(code, node);
comments.stream().distinct() }
public static void addErrors(ICodeWriter code, NotificationAttrNode node) {
if (!node.checkCommentsLevel(CommentsLevel.ERROR)) {
return;
}
List<JadxError> errors = node.getAll(AType.JADX_ERROR);
if (!errors.isEmpty()) {
errors.stream().distinct().sorted().forEach(err -> {
code.startLine("/* JADX ERROR: ").add(err.getError());
Throwable cause = err.getCause();
if (cause != null) {
code.incIndent();
Utils.appendStackTrace(code, cause);
code.decIndent();
}
code.add("*/");
});
}
}
public static void addComments(ICodeWriter code, NotificationAttrNode node) {
JadxCommentsAttr commentsAttr = node.get(AType.JADX_COMMENTS);
if (commentsAttr != null) {
commentsAttr.formatAndFilter(node.getCommentsLevel())
.forEach(comment -> code.startLine("/* ").addMultiLine(comment).add(" */")); .forEach(comment -> code.startLine("/* ").addMultiLine(comment).add(" */"));
} }
addCodeComments(code, node); addCodeComments(code, node, node);
}
public static void addCodeComments(ICodeWriter code, NotificationAttrNode parent, @Nullable IAttributeNode node) {
if (node == null) {
return;
}
if (parent.checkCommentsLevel(CommentsLevel.USER_ONLY)) {
addCodeComments(code, node);
}
} }
public static void addCodeComments(ICodeWriter code, @Nullable IAttributeNode node) { private static void addCodeComments(ICodeWriter code, @Nullable IAttributeNode node) {
if (node == null) { if (node == null) {
return; return;
} }
...@@ -38,7 +74,7 @@ public class CodeGenUtils { ...@@ -38,7 +74,7 @@ public class CodeGenUtils {
return; return;
} }
if (node instanceof ICodeNode) { if (node instanceof ICodeNode) {
// for classes, fields and methods add on line before node declaration // for classes, fields and methods add one line before node declaration
code.startLine(); code.startLine();
} else { } else {
code.add(' '); code.add(' ');
...@@ -78,7 +114,10 @@ public class CodeGenUtils { ...@@ -78,7 +114,10 @@ public class CodeGenUtils {
} }
} }
public static void addRenamedComment(ICodeWriter code, AttrNode node, String origName) { public static void addRenamedComment(ICodeWriter code, NotificationAttrNode node, String origName) {
if (!node.checkCommentsLevel(CommentsLevel.INFO)) {
return;
}
code.startLine("/* renamed from: ").add(origName); code.startLine("/* renamed from: ").add(origName);
RenameReasonAttr renameReasonAttr = node.get(AType.RENAME_REASON); RenameReasonAttr renameReasonAttr = node.get(AType.RENAME_REASON);
if (renameReasonAttr != null) { if (renameReasonAttr != null) {
...@@ -89,6 +128,9 @@ public class CodeGenUtils { ...@@ -89,6 +128,9 @@ public class CodeGenUtils {
} }
public static void addSourceFileInfo(ICodeWriter code, ClassNode node) { public static void addSourceFileInfo(ICodeWriter code, ClassNode node) {
if (!node.checkCommentsLevel(CommentsLevel.INFO)) {
return;
}
SourceFileAttr sourceFileAttr = node.get(JadxAttrType.SOURCE_FILE); SourceFileAttr sourceFileAttr = node.get(JadxAttrType.SOURCE_FILE);
if (sourceFileAttr != null) { if (sourceFileAttr != null) {
String fileName = sourceFileAttr.getFileName(); String fileName = sourceFileAttr.getFileName();
...@@ -102,7 +144,7 @@ public class CodeGenUtils { ...@@ -102,7 +144,7 @@ public class CodeGenUtils {
} }
public static void addInputFileInfo(ICodeWriter code, ClassNode node) { public static void addInputFileInfo(ICodeWriter code, ClassNode node) {
if (node.getClsData() != null) { if (node.getClsData() != null && node.checkCommentsLevel(CommentsLevel.INFO)) {
String inputFileName = node.getClsData().getInputFileName(); String inputFileName = node.getClsData().getInputFileName();
if (inputFileName != null) { if (inputFileName != null) {
code.startLine("/* loaded from: ").add(inputFileName).add(" */"); code.startLine("/* loaded from: ").add(inputFileName).add(" */");
......
...@@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable; ...@@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.attributes.nodes.JadxError; import jadx.core.dex.attributes.nodes.JadxError;
...@@ -31,8 +30,8 @@ public class ErrorsCounter { ...@@ -31,8 +30,8 @@ public class ErrorsCounter {
return node.root().getErrorsCounter().addError(node, warnMsg, th); return node.root().getErrorsCounter().addError(node, warnMsg, th);
} }
public static <N extends IDexNode & IAttributeNode> String warning(N node, String warnMsg) { public static <N extends IDexNode & IAttributeNode> void warning(N node, String warnMsg) {
return node.root().getErrorsCounter().addWarning(node, warnMsg); node.root().getErrorsCounter().addWarning(node, warnMsg);
} }
public static String formatMsg(IDexNode node, String msg) { public static String formatMsg(IDexNode node, String msg) {
...@@ -63,24 +62,14 @@ public class ErrorsCounter { ...@@ -63,24 +62,14 @@ public class ErrorsCounter {
} else { } else {
LOG.error(msg, e); LOG.error(msg, e);
} }
node.addAttr(AType.JADX_ERROR, new JadxError(error, e)); node.addAttr(AType.JADX_ERROR, new JadxError(error, e));
node.remove(AFlag.INCONSISTENT_CODE);
return msg; return msg;
} }
private synchronized <N extends IDexNode & IAttributeNode> String addWarning(N node, String warn) { private synchronized <N extends IDexNode & IAttributeNode> void addWarning(N node, String warn) {
warnNodes.add(node); warnNodes.add(node);
warnsCount++; warnsCount++;
LOG.warn(formatMsg(node, warn));
node.addAttr(AType.JADX_WARN, warn);
if (!node.contains(AType.JADX_ERROR)) {
node.add(AFlag.INCONSISTENT_CODE);
}
String msg = formatMsg(node, warn);
LOG.warn(msg);
return msg;
} }
public void printReport() { public void printReport() {
......
...@@ -16,7 +16,6 @@ import jadx.api.plugins.input.data.annotations.EncodedValue; ...@@ -16,7 +16,6 @@ import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.core.codegen.ClassGen; import jadx.core.codegen.ClassGen;
import jadx.core.deobf.NameMapper; import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.ConstStorage; import jadx.core.dex.info.ConstStorage;
...@@ -91,7 +90,7 @@ public class AndroidResourcesUtils { ...@@ -91,7 +90,7 @@ public class AndroidResourcesUtils {
private static ClassNode makeClass(RootNode root, String clsName, ResourceStorage resStorage) { private static ClassNode makeClass(RootNode root, String clsName, ResourceStorage resStorage) {
ClassNode rCls = ClassNode.addSyntheticClass(root, clsName, AccessFlags.PUBLIC | AccessFlags.FINAL); ClassNode rCls = ClassNode.addSyntheticClass(root, clsName, AccessFlags.PUBLIC | AccessFlags.FINAL);
rCls.addAttr(AType.COMMENTS, "This class is generated by JADX"); rCls.addInfoComment("This class is generated by JADX");
rCls.setState(ProcessState.PROCESS_COMPLETE); rCls.setState(ProcessState.PROCESS_COMPLETE);
return rCls; return rCls;
} }
...@@ -122,7 +121,7 @@ public class AndroidResourcesUtils { ...@@ -122,7 +121,7 @@ public class AndroidResourcesUtils {
rField.addAttr(new EncodedValue(EncodedType.ENCODED_INT, resource.getId())); rField.addAttr(new EncodedValue(EncodedType.ENCODED_INT, resource.getId()));
typeCls.getFields().add(rField); typeCls.getFields().add(rField);
if (rClsExists) { if (rClsExists) {
rField.addAttr(AType.COMMENTS, "added by JADX"); rField.addInfoComment("Added by JADX");
} }
} }
FieldNode fieldNode = resFieldsMap.get(resource.getId()); FieldNode fieldNode = resFieldsMap.get(resource.getId());
...@@ -142,7 +141,7 @@ public class AndroidResourcesUtils { ...@@ -142,7 +141,7 @@ public class AndroidResourcesUtils {
AccessFlags.PUBLIC | AccessFlags.STATIC | AccessFlags.FINAL); AccessFlags.PUBLIC | AccessFlags.STATIC | AccessFlags.FINAL);
resCls.addInnerClass(newTypeCls); resCls.addInnerClass(newTypeCls);
if (rClsExists) { if (rClsExists) {
newTypeCls.addAttr(AType.COMMENTS, "Added by JADX"); newTypeCls.addInfoComment("Added by JADX");
} }
return newTypeCls; return newTypeCls;
} }
......
...@@ -25,6 +25,7 @@ import org.slf4j.Logger; ...@@ -25,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.CodePosition; import jadx.api.CodePosition;
import jadx.api.CommentsLevel;
import jadx.api.ICodeInfo; import jadx.api.ICodeInfo;
import jadx.api.ICodeWriter; import jadx.api.ICodeWriter;
import jadx.api.JadxArgs; import jadx.api.JadxArgs;
...@@ -33,8 +34,8 @@ import jadx.api.JadxInternalAccess; ...@@ -33,8 +34,8 @@ import jadx.api.JadxInternalAccess;
import jadx.api.data.annotations.InsnCodeOffset; import jadx.api.data.annotations.InsnCodeOffset;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.AttrList;
import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.attributes.nodes.JadxCommentsAttr;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
...@@ -307,19 +308,13 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -307,19 +308,13 @@ public abstract class IntegrationTest extends TestUtils {
} }
private boolean hasErrors(IAttributeNode node) { private boolean hasErrors(IAttributeNode node) {
if (node.contains(AFlag.INCONSISTENT_CODE) if (node.contains(AFlag.INCONSISTENT_CODE) || node.contains(AType.JADX_ERROR)) {
|| node.contains(AType.JADX_ERROR)
|| (node.contains(AType.JADX_WARN) && !allowWarnInCode)) {
return true; return true;
} }
if (!allowWarnInCode) { if (!allowWarnInCode) {
AttrList<String> commentsAttr = node.get(AType.COMMENTS); JadxCommentsAttr commentsAttr = node.get(AType.JADX_COMMENTS);
if (commentsAttr != null) { if (commentsAttr != null) {
for (String comment : commentsAttr.getList()) { return commentsAttr.getComments().get(CommentsLevel.WARN) != null;
if (comment.contains("JADX WARN")) {
return true;
}
}
} }
} }
return false; return false;
......
...@@ -17,6 +17,6 @@ public class TestEnums10 extends SmaliTest { ...@@ -17,6 +17,6 @@ public class TestEnums10 extends SmaliTest {
.code() .code()
.doesNotContain("Failed to restore enum class") .doesNotContain("Failed to restore enum class")
.containsOne("enum TestEnums10 {") .containsOne("enum TestEnums10 {")
.countString(4, "/* Fake field"); .countString(4, "Fake field");
} }
} }
...@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; ...@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameter;
import jadx.api.CommentsLevel;
import jadx.api.JadxArgs; import jadx.api.JadxArgs;
import jadx.cli.JadxCLIArgs; import jadx.cli.JadxCLIArgs;
import jadx.cli.LogHelper; import jadx.cli.LogHelper;
...@@ -551,6 +552,10 @@ public class JadxSettings extends JadxCLIArgs { ...@@ -551,6 +552,10 @@ public class JadxSettings extends JadxCLIArgs {
this.adbDialogPort = port; this.adbDialogPort = port;
} }
public void setCommentsLevel(CommentsLevel level) {
this.commentsLevel = level;
}
private void upgradeSettings(int fromVersion) { private void upgradeSettings(int fromVersion) {
LOG.debug("upgrade settings from version: {} to {}", fromVersion, CURRENT_SETTINGS_VERSION); LOG.debug("upgrade settings from version: {} to {}", fromVersion, CURRENT_SETTINGS_VERSION);
if (fromVersion == 0) { if (fromVersion == 0) {
......
...@@ -58,6 +58,7 @@ import com.google.gson.JsonObject; ...@@ -58,6 +58,7 @@ import com.google.gson.JsonObject;
import say.swing.JFontChooser; import say.swing.JFontChooser;
import jadx.api.CommentsLevel;
import jadx.api.JadxArgs; import jadx.api.JadxArgs;
import jadx.gui.ui.MainWindow; import jadx.gui.ui.MainWindow;
import jadx.gui.ui.codearea.EditorTheme; import jadx.gui.ui.codearea.EditorTheme;
...@@ -500,6 +501,13 @@ public class JadxSettingsWindow extends JDialog { ...@@ -500,6 +501,13 @@ public class JadxSettingsWindow extends JDialog {
needReload(); needReload();
}); });
JComboBox<CommentsLevel> commentsLevel = new JComboBox<>(CommentsLevel.values());
commentsLevel.setSelectedItem(settings.getCommentsLevel());
commentsLevel.addActionListener(e -> {
settings.setCommentsLevel((CommentsLevel) commentsLevel.getSelectedItem());
needReload();
});
SettingsGroup other = new SettingsGroup(NLS.str("preferences.decompile")); SettingsGroup other = new SettingsGroup(NLS.str("preferences.decompile"));
other.addRow(NLS.str("preferences.threads"), threadsCount); other.addRow(NLS.str("preferences.threads"), threadsCount);
other.addRow(NLS.str("preferences.excludedPackages"), NLS.str("preferences.excludedPackages.tooltip"), other.addRow(NLS.str("preferences.excludedPackages"), NLS.str("preferences.excludedPackages.tooltip"),
...@@ -515,6 +523,7 @@ public class JadxSettingsWindow extends JDialog { ...@@ -515,6 +523,7 @@ public class JadxSettingsWindow extends JDialog {
other.addRow(NLS.str("preferences.fsCaseSensitive"), fsCaseSensitive); other.addRow(NLS.str("preferences.fsCaseSensitive"), fsCaseSensitive);
other.addRow(NLS.str("preferences.fallback"), fallback); other.addRow(NLS.str("preferences.fallback"), fallback);
other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode); other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode);
other.addRow(NLS.str("preferences.commentsLevel"), commentsLevel);
return other; return other;
} }
......
...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=Anonyme Inline-Klassen ...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=Anonyme Inline-Klassen
preferences.inlineMethods=Inline-Methoden preferences.inlineMethods=Inline-Methoden
preferences.fsCaseSensitive=Dateisystem unterscheidet zwischen Groß/Kleinschreibung preferences.fsCaseSensitive=Dateisystem unterscheidet zwischen Groß/Kleinschreibung
preferences.skipResourcesDecode=Keine Ressourcen dekodieren preferences.skipResourcesDecode=Keine Ressourcen dekodieren
#preferences.commentsLevel=Code comments level
preferences.autoSave=Autom. speichern preferences.autoSave=Autom. speichern
preferences.threads=Verarbeitungs-Thread-Anzahl preferences.threads=Verarbeitungs-Thread-Anzahl
preferences.excludedPackages=Ausgeschlossene Pakete preferences.excludedPackages=Ausgeschlossene Pakete
......
...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=Inline anonymous classes ...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=Inline anonymous classes
preferences.inlineMethods=Inline methods preferences.inlineMethods=Inline methods
preferences.fsCaseSensitive=File system is case sensitive preferences.fsCaseSensitive=File system is case sensitive
preferences.skipResourcesDecode=Don't decode resources preferences.skipResourcesDecode=Don't decode resources
preferences.commentsLevel=Code comments level
preferences.autoSave=Auto save preferences.autoSave=Auto save
preferences.threads=Processing threads count preferences.threads=Processing threads count
preferences.excludedPackages=Excluded packages preferences.excludedPackages=Excluded packages
......
...@@ -130,6 +130,7 @@ preferences.replaceConsts=Reemplazar constantes ...@@ -130,6 +130,7 @@ preferences.replaceConsts=Reemplazar constantes
#preferences.inlineMethods=Inline methods #preferences.inlineMethods=Inline methods
#preferences.fsCaseSensitive= #preferences.fsCaseSensitive=
preferences.skipResourcesDecode=No descodificar recursos preferences.skipResourcesDecode=No descodificar recursos
#preferences.commentsLevel=Code comments level
#preferences.autoSave= #preferences.autoSave=
preferences.threads=Número de hilos a procesar preferences.threads=Número de hilos a procesar
#preferences.excludedPackages= #preferences.excludedPackages=
......
...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=인라인 익명 클래스 ...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=인라인 익명 클래스
#preferences.inlineMethods=Inline methods #preferences.inlineMethods=Inline methods
preferences.fsCaseSensitive=파일 시스템 대소문자 구별 preferences.fsCaseSensitive=파일 시스템 대소문자 구별
preferences.skipResourcesDecode=리소스 디코딩 하지 않기 preferences.skipResourcesDecode=리소스 디코딩 하지 않기
#preferences.commentsLevel=Code comments level
preferences.autoSave=자동 저장 preferences.autoSave=자동 저장
preferences.threads=처리 스레드 수 preferences.threads=처리 스레드 수
preferences.excludedPackages=제외할 패키지 preferences.excludedPackages=제외할 패키지
......
...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=内联匿名类 ...@@ -130,6 +130,7 @@ preferences.inlineAnonymous=内联匿名类
#preferences.inlineMethods=Inline methods #preferences.inlineMethods=Inline methods
preferences.fsCaseSensitive=文件系统区分大小写 preferences.fsCaseSensitive=文件系统区分大小写
preferences.skipResourcesDecode=不反编译资源文件 preferences.skipResourcesDecode=不反编译资源文件
#preferences.commentsLevel=Code comments level
preferences.autoSave=自动保存 preferences.autoSave=自动保存
preferences.threads=并行线程数 preferences.threads=并行线程数
preferences.excludedPackages=排除的包 preferences.excludedPackages=排除的包
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册