mirror of
https://github.com/skylot/jadx.git
synced 2024-10-07 01:53:34 +00:00
fix: additional checks for class signature (#2272)
Some checks failed
Build Artifacts / build-win-bundle (push) Waiting to run
Build Test / tests (windows-latest) (push) Waiting to run
Build Artifacts / build (push) Failing after 0s
Build Test / tests (ubuntu-latest) (push) Failing after 0s
Validate Gradle Wrapper / Validation (push) Failing after 0s
CodeQL / Analyze (java) (push) Failing after 1s
Some checks failed
Build Artifacts / build-win-bundle (push) Waiting to run
Build Test / tests (windows-latest) (push) Waiting to run
Build Artifacts / build (push) Failing after 0s
Build Test / tests (ubuntu-latest) (push) Failing after 0s
Validate Gradle Wrapper / Validation (push) Failing after 0s
CodeQL / Analyze (java) (push) Failing after 1s
This commit is contained in:
parent
fd80e03809
commit
889a945cf1
@ -169,6 +169,24 @@ public class SignatureParser {
|
||||
throw new JadxRuntimeException("Can't parse type: " + debugString() + ", unexpected: " + ch);
|
||||
}
|
||||
|
||||
public List<ArgType> consumeTypeList() {
|
||||
List<ArgType> list = null;
|
||||
while (true) {
|
||||
ArgType type = consumeType();
|
||||
if (type == null) {
|
||||
break;
|
||||
}
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
list.add(type);
|
||||
}
|
||||
if (list == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private ArgType consumeObjectType(boolean innerType) {
|
||||
mark();
|
||||
int ch;
|
||||
|
@ -48,23 +48,49 @@ public class SignatureProcessor extends AbstractVisitor {
|
||||
}
|
||||
try {
|
||||
List<ArgType> generics = sp.consumeGenericTypeParameters();
|
||||
ArgType superClass = validateClsType(cls, sp.consumeType(), cls.getSuperClass());
|
||||
List<ArgType> interfaces = cls.getInterfaces();
|
||||
for (int i = 0; i < interfaces.size(); i++) {
|
||||
ArgType type = sp.consumeType();
|
||||
if (type != null) {
|
||||
interfaces.set(i, validateClsType(cls, type, interfaces.get(i)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
generics = fixTypeParamDeclarations(cls, generics, superClass, interfaces);
|
||||
cls.updateGenericClsData(generics, superClass, interfaces);
|
||||
ArgType superClass = processSuperType(cls, sp.consumeType());
|
||||
List<ArgType> interfaces = processInterfaces(cls, sp.consumeTypeList());
|
||||
List<ArgType> resultGenerics = fixTypeParamDeclarations(cls, generics, superClass, interfaces);
|
||||
cls.updateGenericClsData(resultGenerics, superClass, interfaces);
|
||||
} catch (Exception e) {
|
||||
cls.addWarnComment("Failed to parse class signature: " + sp.getSignature(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private ArgType processSuperType(ClassNode cls, ArgType parsedType) {
|
||||
ArgType superType = cls.getSuperClass();
|
||||
if (Objects.equals(parsedType.getObject(), cls.getClassInfo().getType().getObject())) {
|
||||
cls.addWarnComment("Incorrect class signature: super class is equals to this class");
|
||||
return superType;
|
||||
}
|
||||
return bestClsType(cls, parsedType, superType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse, validate and update class interfaces types.
|
||||
*/
|
||||
private List<ArgType> processInterfaces(ClassNode cls, List<ArgType> parsedTypes) {
|
||||
List<ArgType> interfaces = cls.getInterfaces();
|
||||
if (parsedTypes.isEmpty()) {
|
||||
return interfaces;
|
||||
}
|
||||
int parsedCount = parsedTypes.size();
|
||||
int interfacesCount = interfaces.size();
|
||||
List<ArgType> result = new ArrayList<>(interfacesCount);
|
||||
int count = Math.min(interfacesCount, parsedCount);
|
||||
for (int i = 0; i < interfacesCount; i++) {
|
||||
if (i < count) {
|
||||
result.add(bestClsType(cls, parsedTypes.get(i), interfaces.get(i)));
|
||||
} else {
|
||||
result.add(interfaces.get(i));
|
||||
}
|
||||
}
|
||||
if (interfacesCount < parsedCount) {
|
||||
cls.addWarnComment("Unexpected interfaces in signature: " + parsedTypes.subList(interfacesCount, parsedCount));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add missing type parameters from super type and interfaces to make code compilable
|
||||
*/
|
||||
@ -106,16 +132,22 @@ public class SignatureProcessor extends AbstractVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ArgType validateClsType(ClassNode cls, ArgType candidateType, ArgType currentType) {
|
||||
private ArgType bestClsType(ClassNode cls, ArgType candidateType, ArgType currentType) {
|
||||
if (validateClsType(cls, candidateType)) {
|
||||
return candidateType;
|
||||
}
|
||||
return currentType;
|
||||
}
|
||||
|
||||
private boolean validateClsType(ClassNode cls, ArgType candidateType) {
|
||||
if (candidateType == null) {
|
||||
return false;
|
||||
}
|
||||
if (!candidateType.isObject()) {
|
||||
cls.addWarnComment("Incorrect class signature, class is not object: " + SignatureParser.getSignature(cls));
|
||||
return currentType;
|
||||
cls.addWarnComment("Incorrect class signature, class is not an object: " + candidateType);
|
||||
return false;
|
||||
}
|
||||
if (Objects.equals(candidateType.getObject(), cls.getClassInfo().getType().getObject())) {
|
||||
cls.addWarnComment("Incorrect class signature, class is equals to this class: " + SignatureParser.getSignature(cls));
|
||||
return currentType;
|
||||
}
|
||||
return candidateType;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseFieldSignature(FieldNode field) {
|
||||
|
@ -0,0 +1,32 @@
|
||||
package jadx.tests.integration.others;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.RaungTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestClassImplementsSignature extends RaungTest {
|
||||
|
||||
public static class TestCls {
|
||||
public abstract static class A<T> implements Comparable<A<T>> {
|
||||
T value;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("public static abstract class A<T> implements Comparable<A<T>> {");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaung() {
|
||||
allowWarnInCode();
|
||||
assertThat(getClassNodeFromRaung())
|
||||
.code()
|
||||
.containsOne("public class TestClassImplementsSignature<T> {")
|
||||
.containsOne("Unexpected interfaces in signature");
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
.version 52 # Java 8
|
||||
.class public super others/TestClassImplementsSignature
|
||||
.signature <T:Ljava/lang/Object;>Ljava/lang/Object;Ljava/lang/Comparable<Lothers/TestClassImplementsSignature<LT;>;>;
|
||||
|
||||
.field value Ljava/lang/Object;
|
||||
.signature TT;
|
||||
.end field
|
||||
|
||||
.method public <init>()V
|
||||
.max stack 1
|
||||
.max locals 1
|
||||
|
||||
aload 0
|
||||
invokespecial java/lang/Object <init> ()V
|
||||
return
|
||||
.end method
|
Loading…
Reference in New Issue
Block a user