Skip to content

Commit

Permalink
Fix all the cases where the tests indicated I messed up
Browse files Browse the repository at this point in the history
Also upload the intended test result for TestCorruptedSignatures
  • Loading branch information
sschr15 committed Sep 14, 2024
1 parent 1480c4b commit 1c14529
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor;
import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.generics.GenericsChecker;
import org.jetbrains.java.decompiler.util.*;
import org.jetbrains.java.decompiler.util.collections.VBStyleCollection;
import org.vineflower.kotlin.expr.KAnnotationExprent;
Expand Down Expand Up @@ -1082,10 +1083,24 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
exceptions.add(new VarType(attr.getExcClassname(i, node.classStruct.getPool()), true));
}
}

GenericClassDescriptor classSig = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0 ? node.classStruct.getSignature() : null;
GenericsChecker checker = null;
if (classSig != null) {
checker = classSig.getChecker();

ClassNode currentParent = node.parent;
while (currentParent != null) {
GenericClassDescriptor parentSignature = currentParent.classStruct.getSignature();
if (parentSignature != null) {
checker = checker.copy(parentSignature.getChecker());
}

currentParent = currentParent.parent;
}
}

descriptor.verifyTypes(classSig, params, mt.methodDescriptor().ret, exceptions);
descriptor.verifyTypes(checker, params, mt.methodDescriptor().ret, exceptions);
}

boolean throwsExceptions = false;
Expand Down
30 changes: 26 additions & 4 deletions src/org/jetbrains/java/decompiler/main/ClassWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor;
import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.generics.GenericsChecker;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.Key;
import org.jetbrains.java.decompiler.util.TextBuffer;
Expand Down Expand Up @@ -1157,12 +1158,23 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
GenericMethodDescriptor descriptor = mt.getSignature();
if (descriptor != null) {
List<VarType> params = new ArrayList<>(Arrays.asList(mt.methodDescriptor().params));
if ((node.access & CodeConstants.ACC_ENUM) != 0 && init) {
// Signatures skip enum parameters, the checker must as well

if (init && node.classStruct.hasModifier(CodeConstants.ACC_ENUM)) {
// Enum name and ordinal parameters need to be explicitly excluded
params.remove(0);
params.remove(0);
}

// Exclude any parameters that the signature itself won't contain
List<VarVersionPair> mask = methodWrapper.synthParameters;
if (mask != null) {
for (int i = 0, j = 0; i < mask.size(); i++, j++) {
if (mask.get(i) != null) {
params.remove(j--);
}
}
}

StructExceptionsAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_EXCEPTIONS);
List<VarType> exceptions = new ArrayList<>();
if (attr != null) {
Expand All @@ -1171,9 +1183,19 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
}
}

GenericClassDescriptor classSig = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0 ? node.classStruct.getSignature() : null;
GenericsChecker checker = new GenericsChecker();

ClassNode currentNode = node;
while (currentNode != null) {
GenericClassDescriptor parentSignature = currentNode.classStruct.getSignature();
if (parentSignature != null) {
checker = checker.copy(parentSignature.getChecker());
}

currentNode = currentNode.parent;
}

descriptor.verifyTypes(classSig, params, mt.methodDescriptor().ret, exceptions);
descriptor.verifyTypes(checker, params, mt.methodDescriptor().ret, exceptions);
}

boolean throwsExceptions = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ public GenericFieldDescriptor(VarType type) {
this.type = type;
}

public void verifyType(GenericClassDescriptor containingClassGenerics, VarType actualType) {
public void verifyType(GenericClassDescriptor containingClassGenerics, VarType realType) {
if (containingClassGenerics == null) {
DecompilerContext.getLogger().writeMessage("Class generics were not found, verifying type loosely", IFernflowerLogger.Severity.INFO);
verifyLoosely(actualType);
verifyLoosely(realType);
return;
}

GenericsChecker checker = containingClassGenerics.getChecker();

if (!checker.isProperlyBounded(actualType, type)) {
DecompilerContext.getLogger().writeMessage("Mismatched field signature, expected: " + type.value + ", actual: " + actualType.value, IFernflowerLogger.Severity.WARN);
type = actualType;
if (!checker.isProperlyBounded(type, realType)) {
DecompilerContext.getLogger().writeMessage("Mismatched field signature, expected: " + realType.value + ", actual: " + type.value, IFernflowerLogger.Severity.WARN);
type = realType;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,30 @@ private static <T> List<T> substitute(List<T> list) {
return list.isEmpty() ? Collections.emptyList() : list;
}

public void verifyTypes(GenericClassDescriptor descriptor, List<VarType> realParamTypes, VarType realReturnType, List<VarType> realExceptionTypes) {
GenericsChecker checker = descriptor == null ? new GenericsChecker(typeParameters, typeParameterBounds) : descriptor.getChecker().copy(typeParameters, typeParameterBounds);
public void verifyTypes(GenericsChecker checker, List<VarType> realParamTypes, VarType realReturnType, List<VarType> realExceptionTypes) {
checker = checker == null ? new GenericsChecker(typeParameters, typeParameterBounds) : checker.copy(typeParameters, typeParameterBounds);

for (int i = 0; i < parameterTypes.size(); i++) {
VarType parameterType = parameterTypes.get(i);
VarType actualType = realParamTypes.get(i);
VarType realType = realParamTypes.get(i);

if (!checker.isProperlyBounded(parameterType, actualType)) {
DecompilerContext.getLogger().writeMessage("Mismatched method parameter signature, expected: " + actualType.value + ", actual: " + parameterType.value, IFernflowerLogger.Severity.WARN);
parameterTypes.set(i, actualType);
if (!checker.isProperlyBounded(parameterType, realType)) {
DecompilerContext.getLogger().writeMessage("Mismatched method parameter signature, expected: " + realType.value + ", actual: " + parameterType.value, IFernflowerLogger.Severity.WARN);
parameterTypes.set(i, realType);
}
}

if (!checker.isProperlyBounded(returnType, realReturnType)) {
DecompilerContext.getLogger().writeMessage("Mismatched method parameter signature, expected: " + realReturnType.value + ", actual: " + returnType.value, IFernflowerLogger.Severity.WARN);
DecompilerContext.getLogger().writeMessage("Mismatched method return signature, expected: " + realReturnType.value + ", actual: " + returnType.value, IFernflowerLogger.Severity.WARN);
returnType = realReturnType;
}

for (int i = 0; i < exceptionTypes.size(); i++) {
VarType exceptionType = exceptionTypes.get(i);
VarType realType = realExceptionTypes.get(i);
if (!checker.isProperlyBounded(exceptionType, realType)) {
DecompilerContext.getLogger().writeMessage("Mismatched method exception signature, expected: " + realType.value + ", actual: " + exceptionType.value, IFernflowerLogger.Severity.WARN);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,57 @@
import org.jetbrains.java.decompiler.struct.gen.CodeType;
import org.jetbrains.java.decompiler.struct.gen.VarType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GenericsChecker {
private final Map<String, List<VarType>> boundsMap;

public GenericsChecker() {
boundsMap = Map.of();
}

public GenericsChecker(List<String> typeVariables, List<List<VarType>> bounds) {
boundsMap = new HashMap<>(typeVariables.size(), 1);
for (int i = 0; i < typeVariables.size(); i++) {
boundsMap.put(typeVariables.get(i), bounds.get(i));
}
}

private GenericsChecker(Map<String, List<VarType>> existingBounds, List<String> typeVariables, List<List<VarType>> bounds) {
boundsMap = new HashMap<>(existingBounds);
private GenericsChecker(Map<String, List<VarType>> boundsMap) {
this.boundsMap = boundsMap;
}

public GenericsChecker copy(List<String> typeVariables, List<List<VarType>> bounds) {
HashMap<String, List<VarType>> newBounds = new HashMap<>(boundsMap);
for (int i = 0; i < typeVariables.size(); i++) {
boundsMap.put(typeVariables.get(i), bounds.get(i));
newBounds.put(typeVariables.get(i), bounds.get(i));
}

return new GenericsChecker(newBounds);
}

public GenericsChecker copy(List<String> typeVariables, List<List<VarType>> bounds) {
return new GenericsChecker(boundsMap, typeVariables, bounds);
public GenericsChecker copy(GenericsChecker parent) {
HashMap<String, List<VarType>> newBoundsMap = new HashMap<>(this.boundsMap);
for (Map.Entry<String, List<VarType>> entry : parent.boundsMap.entrySet()) {
if (!newBoundsMap.containsKey(entry.getKey())) {
newBoundsMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
}

return new GenericsChecker(newBoundsMap);
}

public boolean isProperlyBounded(VarType type, VarType bound) {
if (type.isSuperset(bound)) {
return true;
}

// Get base type if array
bound = bound.resizeArrayDim(0);

if (type.type == CodeType.GENVAR && type instanceof GenericType genericType) {
List<VarType> typeBounds = boundsMap.get(genericType.value);
if (typeBounds != null) {
Expand Down
11 changes: 5 additions & 6 deletions testData/results/TestCorruptedSignatures.dec
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

abstract class Signatures implements Map<String, String> {
Map<String, String> field = new ArrayList();
abstract class Signatures implements List {
List field = new ArrayList();

void method(Map<String, String> o) {
void method(List o) {
}// 9
}

class 'Signatures' {
method 'method (Ljava/util/List;)V' {
0 8
0 7
}
}

Lines mapping:
9 <-> 9
9 <-> 8

0 comments on commit 1c14529

Please sign in to comment.