feat: add the option to always use source file name as class name alias (PR #2287)
This commit is contained in:
@@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.api.args.GeneratedRenamesMappingFileMode;
|
||||
import jadx.api.args.IntegerFormat;
|
||||
import jadx.api.args.ResourceNameSource;
|
||||
import jadx.api.args.UseSourceNameAsClassNameAlias;
|
||||
import jadx.api.args.UserRenamesMappingsMode;
|
||||
import jadx.api.data.ICodeData;
|
||||
import jadx.api.deobf.IAliasProvider;
|
||||
@@ -98,7 +99,7 @@ public class JadxArgs implements Closeable {
|
||||
private UserRenamesMappingsMode userRenamesMappingsMode = UserRenamesMappingsMode.getDefault();
|
||||
|
||||
private boolean deobfuscationOn = false;
|
||||
private boolean useSourceNameAsClassAlias = false;
|
||||
private UseSourceNameAsClassNameAlias useSourceNameAsClassNameAlias = UseSourceNameAsClassNameAlias.getDefault();
|
||||
|
||||
private File generatedRenamesMappingFile = null;
|
||||
private GeneratedRenamesMappingFileMode generatedRenamesMappingFileMode = GeneratedRenamesMappingFileMode.getDefault();
|
||||
@@ -430,12 +431,29 @@ public class JadxArgs implements Closeable {
|
||||
this.generatedRenamesMappingFileMode = mode;
|
||||
}
|
||||
|
||||
public boolean isUseSourceNameAsClassAlias() {
|
||||
return useSourceNameAsClassAlias;
|
||||
public UseSourceNameAsClassNameAlias getUseSourceNameAsClassNameAlias() {
|
||||
return useSourceNameAsClassNameAlias;
|
||||
}
|
||||
|
||||
public void setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias useSourceNameAsClassNameAlias) {
|
||||
this.useSourceNameAsClassNameAlias = useSourceNameAsClassNameAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getUseSourceNameAsClassNameAlias()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isUseSourceNameAsClassAlias() {
|
||||
return getUseSourceNameAsClassNameAlias().toBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setUseSourceNameAsClassAlias(boolean useSourceNameAsClassAlias) {
|
||||
this.useSourceNameAsClassAlias = useSourceNameAsClassAlias;
|
||||
final var useSourceNameAsClassNameAlias = UseSourceNameAsClassNameAlias.create(useSourceNameAsClassAlias);
|
||||
setUseSourceNameAsClassNameAlias(useSourceNameAsClassNameAlias);
|
||||
}
|
||||
|
||||
public int getDeobfuscationMinLength() {
|
||||
@@ -729,10 +747,11 @@ public class JadxArgs implements Closeable {
|
||||
String argStr = "args:" + decompilationMode + useImports + showInconsistentCode
|
||||
+ inlineAnonymousClasses + inlineMethods + moveInnerClasses + allowInlineKotlinLambda
|
||||
+ deobfuscationOn + deobfuscationMinLength + deobfuscationMaxLength + deobfuscationWhitelist
|
||||
+ useSourceNameAsClassNameAlias
|
||||
+ resourceNameSource
|
||||
+ useKotlinMethodsForVarNames
|
||||
+ insertDebugLines + extractFinally
|
||||
+ debugInfo + useSourceNameAsClassAlias + escapeUnicode + replaceConsts
|
||||
+ debugInfo + escapeUnicode + replaceConsts
|
||||
+ respectBytecodeAccModifiers + fsCaseSensitive + renameFlags
|
||||
+ commentsLevel + useDxInput + integerFormat
|
||||
+ "|" + buildPluginsHash(decompiler);
|
||||
@@ -768,7 +787,7 @@ public class JadxArgs implements Closeable {
|
||||
+ ", generatedRenamesMappingFile=" + generatedRenamesMappingFile
|
||||
+ ", generatedRenamesMappingFileMode=" + generatedRenamesMappingFileMode
|
||||
+ ", resourceNameSource=" + resourceNameSource
|
||||
+ ", useSourceNameAsClassAlias=" + useSourceNameAsClassAlias
|
||||
+ ", useSourceNameAsClassNameAlias=" + useSourceNameAsClassNameAlias
|
||||
+ ", useKotlinMethodsForVarNames=" + useKotlinMethodsForVarNames
|
||||
+ ", insertDebugLines=" + insertDebugLines
|
||||
+ ", extractFinally=" + extractFinally
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package jadx.api.args;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public enum UseSourceNameAsClassNameAlias {
|
||||
ALWAYS,
|
||||
IF_BETTER,
|
||||
NEVER;
|
||||
|
||||
public static UseSourceNameAsClassNameAlias getDefault() {
|
||||
return NEVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link UseSourceNameAsClassNameAlias} directly.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean toBoolean() {
|
||||
switch (this) {
|
||||
case IF_BETTER:
|
||||
return true;
|
||||
case NEVER:
|
||||
return false;
|
||||
case ALWAYS:
|
||||
throw new JadxRuntimeException("No match between " + this + " and boolean");
|
||||
default:
|
||||
throw new JadxRuntimeException("Unhandled strategy: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link UseSourceNameAsClassNameAlias} directly.
|
||||
*/
|
||||
@Deprecated
|
||||
public static UseSourceNameAsClassNameAlias create(boolean useSourceNameAsAlias) {
|
||||
return useSourceNameAsAlias ? IF_BETTER : NEVER;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.args.UseSourceNameAsClassNameAlias;
|
||||
import jadx.api.plugins.input.data.attributes.JadxAttrType;
|
||||
import jadx.api.plugins.input.data.attributes.types.SourceFileAttr;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
@@ -18,6 +19,7 @@ import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.BetterName;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public class SourceFileRename extends AbstractVisitor {
|
||||
|
||||
@@ -28,9 +30,11 @@ public class SourceFileRename extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
public void init(RootNode root) throws JadxException {
|
||||
if (!root.getArgs().isUseSourceNameAsClassAlias()) {
|
||||
final var useSourceName = root.getArgs().getUseSourceNameAsClassNameAlias();
|
||||
if (useSourceName == UseSourceNameAsClassNameAlias.NEVER) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ClassNode> classes = root.getClasses();
|
||||
Map<String, Boolean> canUseAlias = new HashMap<>();
|
||||
for (ClassNode cls : classes) {
|
||||
@@ -55,16 +59,15 @@ public class SourceFileRename extends AbstractVisitor {
|
||||
for (ClsRename clsRename : renames) {
|
||||
String alias = clsRename.getAlias();
|
||||
if (canUseAlias.get(alias) == Boolean.TRUE) {
|
||||
applyRename(clsRename.getCls(), alias);
|
||||
applyRename(clsRename.getCls(), alias, useSourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyRename(ClassNode cls, String alias) {
|
||||
private static void applyRename(ClassNode cls, String alias, UseSourceNameAsClassNameAlias useSourceName) {
|
||||
if (cls.getClassInfo().hasAlias()) {
|
||||
// ignore source name if current alias is "better"
|
||||
String currentAlias = cls.getAlias();
|
||||
String betterName = BetterName.compareAndGet(alias, currentAlias);
|
||||
String betterName = getBetterName(currentAlias, alias, useSourceName);
|
||||
if (betterName.equals(currentAlias)) {
|
||||
return;
|
||||
}
|
||||
@@ -73,6 +76,19 @@ public class SourceFileRename extends AbstractVisitor {
|
||||
cls.addAttr(new RenameReasonAttr(cls).append("use source file name"));
|
||||
}
|
||||
|
||||
private static String getBetterName(String currentName, String sourceName, UseSourceNameAsClassNameAlias useSourceName) {
|
||||
switch (useSourceName) {
|
||||
case ALWAYS:
|
||||
return sourceName;
|
||||
case IF_BETTER:
|
||||
return BetterName.compareAndGet(sourceName, currentName);
|
||||
case NEVER:
|
||||
return currentName;
|
||||
default:
|
||||
throw new JadxRuntimeException("Unhandled strategy: " + useSourceName);
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable String getAliasFromSourceFile(ClassNode cls) {
|
||||
SourceFileAttr sourceFileAttr = cls.get(JadxAttrType.SOURCE_FILE);
|
||||
if (sourceFileAttr == null) {
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package jadx.tests.integration.deobf;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBadSourceFile extends SmaliTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// use source name disabled by default
|
||||
enableDeobfuscation();
|
||||
args.setDeobfuscationMinLength(100); // rename everything
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class C0000b {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithUseSourceName() {
|
||||
args.setUseSourceNameAsClassAlias(true);
|
||||
// deobfuscation disabled
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class a {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithUseSourceNameAndDeobf() {
|
||||
args.setUseSourceNameAsClassAlias(true);
|
||||
enableDeobfuscation();
|
||||
args.setDeobfuscationMinLength(100); // rename everything
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class C0000b {")
|
||||
.containsOne("/* compiled from: a.java */");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package jadx.tests.integration.rename;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.api.args.UseSourceNameAsClassNameAlias;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestUsingSourceFileName extends SmaliTest {
|
||||
|
||||
@Test
|
||||
public void testNeverUseSourceName() {
|
||||
args.setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias.NEVER);
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class b {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlwaysUseSourceName() {
|
||||
args.setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias.ALWAYS);
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class a {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeverUseSourceNameWithDeobf() {
|
||||
args.setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias.NEVER);
|
||||
enableDeobfuscation();
|
||||
args.setDeobfuscationMinLength(100); // rename everything
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class C0000b {")
|
||||
.containsOne("/* compiled from: a.java */");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlwaysUseSourceNameWithDeobf() {
|
||||
args.setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias.ALWAYS);
|
||||
enableDeobfuscation();
|
||||
args.setDeobfuscationMinLength(100); // rename everything
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class a {")
|
||||
.containsOne("/* compiled from: a.java */");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecatedDontUseSourceName() {
|
||||
// noinspection deprecation
|
||||
args.setUseSourceNameAsClassAlias(false);
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class b {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecatedUseSourceName() {
|
||||
// noinspection deprecation
|
||||
args.setUseSourceNameAsClassAlias(true);
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class a {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecatedUseSourceNameWithDeobf() {
|
||||
// noinspection deprecation
|
||||
args.setUseSourceNameAsClassAlias(true);
|
||||
enableDeobfuscation();
|
||||
args.setDeobfuscationMinLength(100); // rename everything
|
||||
assertThat(searchCls(loadFromSmaliFiles(), "b"))
|
||||
.code()
|
||||
.containsOne("class C0000b {")
|
||||
.containsOne("/* compiled from: a.java */");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user