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