diff --git a/core/src/main/java/com/ibm/wala/types/generics/TypeSignature.java b/core/src/main/java/com/ibm/wala/types/generics/TypeSignature.java index e4591e1a47..dfb357079d 100644 --- a/core/src/main/java/com/ibm/wala/types/generics/TypeSignature.java +++ b/core/src/main/java/com/ibm/wala/types/generics/TypeSignature.java @@ -85,10 +85,6 @@ public static TypeSignature make(String s) throws IllegalArgumentException { * signatures. The string should start with either {@code (} or {@code <} and have a respective * matching {@code )} or {@code >}. * - *
TODO handle wildcards - * - *
TODO test on all methods in JDK - * * @param typeSigs a string of consecutive type signatures * @return an array of top-level type signatures */ @@ -189,6 +185,16 @@ public static String[] parseForTypeSignatures(String typeSigs) throws IllegalArg result[j] = it.next(); } return result; + case (byte) '*': // unbounded wildcard + sigs.add("*"); + break; + case (byte) '-': // bounded wildcard + case (byte) '+': // bounded wildcard + int boundedStart = i - 1; + i++; // to skip 'L' + i = getEndIndexOfClassType(typeSigs, i); + sigs.add(typeSigs.substring(boundedStart, i)); + break; default: throw new IllegalArgumentException("bad type signature list " + typeSigs); } diff --git a/core/src/test/java/com/ibm/wala/types/generics/TypeSignatureTest.java b/core/src/test/java/com/ibm/wala/types/generics/TypeSignatureTest.java index 5a09c49ee6..635a30f847 100644 --- a/core/src/test/java/com/ibm/wala/types/generics/TypeSignatureTest.java +++ b/core/src/test/java/com/ibm/wala/types/generics/TypeSignatureTest.java @@ -4,6 +4,17 @@ import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.is; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.ShrikeCTMethod; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.ClassHierarchyFactory; +import com.ibm.wala.shrike.shrikeCT.InvalidClassFileException; +import java.io.IOException; import org.junit.jupiter.api.Test; public class TypeSignatureTest { @@ -21,4 +32,43 @@ void multiDimArray() { TypeSignature.parseForTypeSignatures("<[[Ljava/lang/String;[[[J>"), arrayContaining(is("[[Ljava/lang/String;"), is("[[[J"))); } + + @Test + void wildcards() { + assertThat( + TypeSignature.parseForTypeSignatures(""), arrayContaining(is("B"), is("*"), is("J"))); + assertThat( + TypeSignature.parseForTypeSignatures("<+Ljava/lang/Object;>"), + arrayContaining(is("+Ljava/lang/Object;"))); + assertThat( + TypeSignature.parseForTypeSignatures("<-Ljava/lang/Double;BB>"), + arrayContaining(is("-Ljava/lang/Double;"), is("B"), is("B"))); + } + + @Test + void testAllGenericMethodSigs() + throws IOException, ClassHierarchyException, InvalidClassFileException { + AnalysisScope scope = + CallGraphTestUtil.makeJ2SEAnalysisScope( + TestConstants.WALA_TESTDATA, "J2SEClassHierarchyExclusions.txt"); + ClassHierarchy cha = ClassHierarchyFactory.make(scope); + for (IClass klass : cha) { + for (IMethod m : klass.getDeclaredMethods()) { + if (m instanceof ShrikeCTMethod) { + ShrikeCTMethod method = (ShrikeCTMethod) m; + MethodTypeSignature methodTypeSignature = method.getMethodTypeSignature(); + if (methodTypeSignature != null) { + String typeSigStr = methodTypeSignature.toString(); + for (int i = 0; i < typeSigStr.length(); i++) { + if ((typeSigStr.charAt(i) == '<' && i != 0) || typeSigStr.charAt(i) == '(') { + // parsing will automatically end at the matching '>' or ')' + // this is just testing for crashes + TypeSignature.parseForTypeSignatures(typeSigStr.substring(i)); + } + } + } + } + } + } + } }