feat: add support for 'package-info' (#1967)
This commit is contained in:
@@ -249,7 +249,6 @@ public class SimpleCodeWriter implements ICodeWriter {
|
||||
|
||||
@Override
|
||||
public String getCodeStr() {
|
||||
removeFirstEmptyLine();
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -96,16 +96,29 @@ public class ClassGen {
|
||||
}
|
||||
|
||||
public ICodeInfo makeClass() throws CodegenException {
|
||||
if (cls.contains(AFlag.PACKAGE_INFO)) {
|
||||
return makePackageInfo();
|
||||
}
|
||||
ICodeWriter clsBody = cls.root().makeCodeWriter();
|
||||
addClassCode(clsBody);
|
||||
|
||||
ICodeWriter clsCode = cls.root().makeCodeWriter();
|
||||
addPackage(clsCode);
|
||||
clsCode.newLine();
|
||||
addImports(clsCode);
|
||||
clsCode.add(clsBody);
|
||||
return clsCode.finish();
|
||||
}
|
||||
|
||||
private void addPackage(ICodeWriter clsCode) {
|
||||
if (cls.getPackage().isEmpty()) {
|
||||
clsCode.add("// default package");
|
||||
} else {
|
||||
clsCode.add("package ").add(cls.getPackage()).add(';');
|
||||
}
|
||||
clsCode.newLine();
|
||||
}
|
||||
|
||||
private void addImports(ICodeWriter clsCode) {
|
||||
int importsCount = imports.size();
|
||||
if (importsCount != 0) {
|
||||
List<ClassInfo> sortedImports = new ArrayList<>(imports);
|
||||
@@ -122,8 +135,17 @@ public class ClassGen {
|
||||
clsCode.newLine();
|
||||
imports.clear();
|
||||
}
|
||||
clsCode.add(clsBody);
|
||||
return clsCode.finish();
|
||||
}
|
||||
|
||||
private ICodeInfo makePackageInfo() {
|
||||
ICodeWriter code = cls.root().makeCodeWriter();
|
||||
annotationGen.addForClass(code);
|
||||
code.newLine();
|
||||
code.attachDefinition(cls);
|
||||
addPackage(code);
|
||||
code.newLine();
|
||||
addImports(code);
|
||||
return code.finish();
|
||||
}
|
||||
|
||||
public void addClassCode(ICodeWriter code) throws CodegenException {
|
||||
|
||||
@@ -44,6 +44,8 @@ public enum AFlag {
|
||||
THIS,
|
||||
SUPER,
|
||||
|
||||
PACKAGE_INFO,
|
||||
|
||||
/**
|
||||
* Mark Android resources class
|
||||
*/
|
||||
|
||||
@@ -127,6 +127,7 @@ public class ClassNode extends NotificationAttrNode
|
||||
}
|
||||
initStaticValues(fields);
|
||||
processAttributes(this);
|
||||
processSpecialClasses(this);
|
||||
buildCache();
|
||||
|
||||
// TODO: implement module attribute parsing
|
||||
@@ -167,6 +168,15 @@ public class ClassNode extends NotificationAttrNode
|
||||
this.interfaces = interfaces;
|
||||
}
|
||||
|
||||
private static void processSpecialClasses(ClassNode cls) {
|
||||
AccessInfo flags = cls.getAccessFlags();
|
||||
if (flags.isSynthetic() && flags.isInterface() && flags.isAbstract()
|
||||
&& cls.getName().equals("package-info")) {
|
||||
cls.add(AFlag.PACKAGE_INFO);
|
||||
cls.add(AFlag.DONT_RENAME);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processAttributes(ClassNode cls) {
|
||||
// move AnnotationDefault from cls to methods (dex specific)
|
||||
AnnotationDefaultClassAttr defAttr = cls.get(JadxAttrType.ANNOTATION_DEFAULT_CLASS);
|
||||
|
||||
@@ -50,6 +50,9 @@ public class ClassModifier extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
public boolean visit(ClassNode cls) throws JadxException {
|
||||
if (cls.contains(AFlag.PACKAGE_INFO)) {
|
||||
return false;
|
||||
}
|
||||
for (ClassNode inner : cls.getInnerClasses()) {
|
||||
visit(inner);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,9 @@ public class RenameVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static void checkClassName(IAliasProvider aliasProvider, ClassNode cls, JadxArgs args) {
|
||||
if (cls.contains(AFlag.DONT_RENAME)) {
|
||||
return;
|
||||
}
|
||||
ClassInfo classInfo = cls.getClassInfo();
|
||||
String clsName = classInfo.getAliasShortName();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import javax.tools.ToolProvider;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import jadx.api.impl.SimpleCodeWriter;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.utils.files.FileUtils;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
@@ -80,12 +81,16 @@ public class TestCompiler implements Closeable {
|
||||
arguments.add(javaVerStr);
|
||||
arguments.addAll(options.getArguments());
|
||||
|
||||
DiagnosticListener<? super JavaFileObject> diagnostic =
|
||||
diagObj -> System.out.println("Compiler diagnostic: " + diagObj);
|
||||
SimpleCodeWriter output = new SimpleCodeWriter();
|
||||
DiagnosticListener<JavaFileObject> diagnostic = diagObj -> {
|
||||
String msg = "Compiler diagnostic: " + diagObj;
|
||||
output.startLine(msg);
|
||||
System.out.println(msg);
|
||||
};
|
||||
Writer out = new PrintWriter(System.out);
|
||||
CompilationTask compilerTask = compiler.getTask(out, fileManager, diagnostic, arguments, null, jfObjects);
|
||||
if (Boolean.FALSE.equals(compilerTask.call())) {
|
||||
throw new RuntimeException("Compilation failed");
|
||||
throw new RuntimeException("Compilation failed: " + output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ public class TestArrayAccessReorder extends IntegrationTest {
|
||||
@Test
|
||||
public void test() {
|
||||
noDebugInfo();
|
||||
getArgs().setRawCFGOutput(true);
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("i++");
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package jadx.tests.integration.special;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestPackageInfoSupport extends SmaliTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
disableCompilation();
|
||||
List<ClassNode> classes = loadFromSmaliFiles();
|
||||
assertThat(searchCls(classes, "special.pkg1.package-info"))
|
||||
.satisfies(cls -> assertThat(cls.getAlias()).isEqualTo("package-info")) // shouldn't be renamed
|
||||
.code()
|
||||
.containsLines(
|
||||
"@Deprecated",
|
||||
"package special.pkg1;");
|
||||
assertThat(searchCls(classes, "special.pkg2.package-info"))
|
||||
.code()
|
||||
.containsLines(
|
||||
"@ApiStatus.Internal",
|
||||
"package special.pkg2;",
|
||||
"",
|
||||
"import org.jetbrains.annotations.ApiStatus;");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
.class interface abstract synthetic Lspecial/pkg1/package-info;
|
||||
.super Ljava/lang/Object;
|
||||
.source "package-info.java"
|
||||
|
||||
.annotation runtime Ljava/lang/Deprecated;
|
||||
.end annotation
|
||||
@@ -0,0 +1,5 @@
|
||||
.class interface abstract synthetic Lspecial/pkg2/package-info;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.annotation runtime Lorg/jetbrains/annotations/ApiStatus$Internal;
|
||||
.end annotation
|
||||
Reference in New Issue
Block a user