aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoracolyer <acolyer>2005-07-28 10:55:30 +0000
committeracolyer <acolyer>2005-07-28 10:55:30 +0000
commitb94dee2854b998ccd1bc1738e91f0ce36e781cbb (patch)
tree289c679c26b31f97fb15bd871a5b6194749fef01
parent8cb70f37f86030709e51d62e8d1579e418ecc107 (diff)
downloadaspectj-b94dee2854b998ccd1bc1738e91f0ce36e781cbb.tar.gz
aspectj-b94dee2854b998ccd1bc1738e91f0ce36e781cbb.zip
full support for generic wildcard (?, ? extends, ? super)
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java3
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java205
-rw-r--r--weaver/testsrc/BcweaverModuleTests15.java4
-rw-r--r--weaver/testsrc/org/aspectj/weaver/GenericsWildCardTypeXTestCase.java37
-rw-r--r--weaver/testsrc/org/aspectj/weaver/patterns/WildTypePatternResolutionTestCase.java470
5 files changed, 590 insertions, 129 deletions
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java b/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java
index 0c937e848..6e4c2f246 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java
@@ -17,7 +17,6 @@ import java.util.Map;
import org.aspectj.apache.bcel.classfile.Signature;
import org.aspectj.apache.bcel.classfile.Signature.SimpleClassTypeSignature;
import org.aspectj.weaver.BoundedReferenceType;
-import org.aspectj.weaver.GenericsWildcardTypeX;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedMember;
@@ -153,7 +152,7 @@ public class BcelGenericSignatureToTypeXConverter {
Signature.FormalTypeParameter[] typeParams,
World world,
Map inProgressTypeVariableResolutions) {
- if (aTypeArgument.isWildcard) return GenericsWildcardTypeX.GENERIC_WILDCARD.resolve(world);
+ if (aTypeArgument.isWildcard) return UnresolvedType.SOMETHING.resolve(world);
if (aTypeArgument.isMinus) {
UnresolvedType bound = fieldTypeSignature2TypeX(aTypeArgument.signature, typeParams,world,inProgressTypeVariableResolutions);
ReferenceType rBound = (ReferenceType) world.resolve(bound);
diff --git a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
index 4382bcff8..59e2a6567 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
@@ -25,7 +25,9 @@ import org.aspectj.util.FileUtil;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.BoundedReferenceType;
import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.TypeFactory;
import org.aspectj.weaver.TypeVariable;
@@ -35,7 +37,6 @@ import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
-//XXX need to use dim in matching
/**
* The PatternParser always creates WildTypePatterns for type patterns in pointcut
* expressions (apart from *, which is sometimes directly turned into TypePattern.ANY).
@@ -51,27 +52,6 @@ import org.aspectj.weaver.WeaverMessages;
* resolveBindings resolves Foo to RT(Foo - raw)
* return ExactTypePattern(LFoo;)
*
- * <E>... Foo<E> where Foo exists and has one unbound type var
- * Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{E}
- * resolveBindings requireExactType = true | false
- * resolves typeParameters to ExactTypePattern(TVRT(E))
- * resolves Foo to RT(Foo - raw)
- * returns ExactTypePattern(<1:>LFoo; - generic) 1=E
- *
- * <E>... Foo<E> where Foo exists and is not generic (or has different bounds)
- * Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{E}
- * resolveBindings resolves typeParameters to ExactTypePattern(TVRT(E))
- * resolves Foo to RT(Foo)
- * finds that Foo is not generic / type var mismatch
- * requireExactType = true ->returns TypePattern.NO (and issues error)
- * = false -> XLint then return ExactTypePattern(<1:>LFoo;)
- *
- * <E>... Foo<E extends Number> where Foo exists and bounds match
- * Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{E},uB=WTP{Number}
- * resolveBindings resolves typeParameters to ExactTypePattern(TVRT(E extends Number))
- * resolves Foo to RT(Foo)
- * returns ExactTypePattern(<1:Ljava/lang/Number;>LFoo;) 1=E
- *
* Foo<String> where Foo exists and String meets the bounds
* Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{String}
* resolveBindings resolves typeParameters to ExactTypePattern(String)
@@ -89,39 +69,6 @@ import org.aspectj.weaver.WeaverMessages;
* resolveBindings resolves typeParameters to ETP{String}
* returns WildTypePattern(name = Fo*, typeParameters = ETP{String} isGeneric=false)
*
- * <E>... Fo*<E>
- * Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{E}
- * resolveBindings resolves typeParameters to ETP{TVRT(E)}
- * returns WildTypePattern(name = Fo*, typeParameters = ETP{TVRT(E)} isGeneric=true)
- *
- * <E>... Fo*<E extends Number>
- * Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{E,uB=WTP(Number)}
- * resolveBindings resolves typeParameters to ETP{TVRT(E extends Number)}
- * returns WildTypePattern(name = Fo*, typeParameters = ETP{TVRT(E extends Number)} isGeneric=true)
- *
- * <E>... Foo<E extends Number+> where Foo exists and takes one bound
- * Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{E,uB=WTP(Number+)}
- * resolveBindings resolves typeParameters to WildTypeVariableReferencePattern{TVP(name="E",uB=Number+)}
- * resolves Foo to RT(Foo)
- * if requireExactType (but this doesn't allow + ? )
- * if typeParameters.matches(RT(Foo - generic).getTypeVariables()
- * return ETP(<1:Ljava/lang/Number;>LFoo;)
- * else return TypePattern.NO and issue warning
- * else
- * if !typeParameters.matches(RT(Foo - generic).getTypeVariables()
- * issue warning (XLint?)
- * return WildTypePattern(name=Foo, typeParameters=WTVRP{TVP(E,Number+)} isGeneric=true
- *
- * <E>... Fo*<E extends Number+>
- * Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{E,uB=WTP(Number+)}
- * resolveBindings resolves typeParameters to WildTypeVariableReferencePattern{TVP(name="E",uB=Number+)}
- * returns WildTypePattern(name=Fo*, typeParamters = WTVRP{TVP(name="E" ub=Number+)} isGeneric=true)
- *
- * TODO:
- *
- * <E>... Foo<E,String>
- *
- * <S,T>... Foo<S,T extends S>
*
* Foo<?>
*
@@ -133,6 +80,7 @@ import org.aspectj.weaver.WeaverMessages;
*
*/
public class WildTypePattern extends TypePattern {
+ private static final String GENERIC_WILDCARD_CHARACTER = "?";
private NamePattern[] namePatterns;
int ellipsisCount;
String[] importedPrefixes;
@@ -194,6 +142,18 @@ public class WildTypePattern extends TypePattern {
this.additionalInterfaceBounds = additionalInterfaceBounds;
}
+ public WildTypePattern(
+ List names,
+ boolean includeSubtypes,
+ int dim,
+ int endPos,
+ boolean isVarArg,
+ TypePatternList typeParams)
+ {
+ this((NamePattern[])names.toArray(new NamePattern[names.size()]),includeSubtypes,dim,isVarArg,typeParams);
+ this.end = endPos;
+ }
+
public NamePattern[] getNamePatterns() {
return namePatterns;
}
@@ -264,25 +224,37 @@ public class WildTypePattern extends TypePattern {
annotationPattern.resolve(type.getWorld());
return matchesExactlyByName(targetTypeName) &&
- // matchesParameters(type) &&
+ matchesParameters(type,STATIC) &&
+ matchesBounds(type,STATIC) &&
annotationPattern.matches(annotatedType).alwaysTrue();
}
// we've matched against the base (or raw) type, but if this type pattern specifies parameters or
// type variables we need to make sure we match against them too
- private boolean matchesParameters(ResolvedType aType) {
- if (isGeneric) {
- if (!aType.isGenericType()) return false;
- // we have to match type variables
-
- } else if (typeParameters.size() > 0) {
+ private boolean matchesParameters(ResolvedType aType, MatchKind staticOrDynamic) {
+ if (!isGeneric && typeParameters.size() > 0) {
if(!aType.isParameterizedType()) return false;
// we have to match type parameters
+ return typeParameters.matches(aType.getResolvedTypeParameters(), staticOrDynamic).alwaysTrue();
}
return true;
}
+ // we've matched against the base (or raw) type, but if this type pattern specifies bounds because
+ // it is a ? extends or ? super deal then we have to match them too.
+ private boolean matchesBounds(ResolvedType aType, MatchKind staticOrDynamic) {
+ if (upperBound == null && lowerBound == null) return true;
+ if (!namePatterns[0].matches(GENERIC_WILDCARD_CHARACTER)) throw new IllegalStateException("Well, well, well. I really wasn't expecting *that* to happen. There's no excusing it, Adrian's screwed up an assumption here alright");
+ if (upperBound != null) {
+ // match ? extends
+ return upperBound.matches((ResolvedType)aType.getUpperBound(),staticOrDynamic).alwaysTrue();
+ } else {
+ // match ? super
+ return lowerBound.matches((ResolvedType)aType.getLowerBound(),staticOrDynamic).alwaysTrue();
+ }
+ }
+
/**
* Used in conjunction with checks on 'isStar()' to tell you if this pattern represents '*' or '*[]' which are
* different !
@@ -300,11 +272,13 @@ public class WildTypePattern extends TypePattern {
* @return
*/
private boolean matchesExactlyByName(String targetTypeName) {
- if (typeParameters == TypePatternList.EMPTY) {
- // we can ignore anything after an < as we want raw matching
- if (targetTypeName.indexOf('<') != -1) {
- targetTypeName = targetTypeName.substring(0,targetTypeName.indexOf('<'));
- }
+ // we deal with parameter matching separately...
+ if (targetTypeName.indexOf('<') != -1) {
+ targetTypeName = targetTypeName.substring(0,targetTypeName.indexOf('<'));
+ }
+ // we deal with bounds matching separately too...
+ if (targetTypeName.startsWith(GENERIC_WILDCARD_CHARACTER)) {
+ targetTypeName = GENERIC_WILDCARD_CHARACTER;
}
//XXX hack
if (knownMatches == null && importedPrefixes == null) {
@@ -567,6 +541,11 @@ public class WildTypePattern extends TypePattern {
}
}
+ // resolve any bounds
+ if (upperBound != null) upperBound = upperBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
+ if (lowerBound != null) lowerBound = lowerBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
+ // amc - additional interface bounds only needed if we support type vars again.
+
String fullyQualifiedName = maybeGetCleanName();
if (fullyQualifiedName != null) {
return resolveBindingsFromFullyQualifiedTypeName(fullyQualifiedName, scope, bindings, allowBinding, requireExactType);
@@ -657,27 +636,10 @@ public class WildTypePattern extends TypePattern {
// we have to set the bounds on it based on the bounds of this pattern
ret = resolveBindingsForTypeVariable(scope, (UnresolvedTypeVariableReferenceType) aType);
} else if (typeParameters.size()>0) {
- if (!verifyTypeParameters(aType.resolve(scope.getWorld()),scope,requireExactType)) return TypePattern.NO; // messages already isued
- // Only if the type is exact *and* the type parameters are exact should we create an
- // ExactTypePattern for this WildTypePattern
- if (typeParameters.areAllExact()) {
- TypePattern[] typePats = typeParameters.getTypePatterns();
- UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
- for (int i = 0; i < typeParameterTypes.length; i++) {
- typeParameterTypes[i] = ((ExactTypePattern)typePats[i]).getExactType();
- }
- ResolvedType type = TypeFactory.createParameterizedType(aType.resolve(scope.getWorld()), typeParameterTypes, scope.getWorld());
- if (isGeneric) type = type.getGenericType();
-// UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
-// UnresolvedType type = scope.getWorld().resolve(tx,true);
- if (dim != 0) type = ResolvedType.makeArray(type, dim);
- ret = new ExactTypePattern(type,includeSubtypes,isVarArgs);
- } else {
- // AMC... just leave it as a wild type pattern then?
- importedPrefixes = scope.getImportedPrefixes();
- knownMatches = preMatch(scope.getImportedNames());
- return this;
- }
+ ret = resolveParameterizedType(scope, aType, requireExactType);
+ } else if (upperBound != null || lowerBound != null) {
+ // this must be a generic wildcard with bounds
+ ret = resolveGenericWildcard(scope, aType);
} else {
if (dim != 0) aType = UnresolvedType.makeArray(aType, dim);
ret = new ExactTypePattern(aType,includeSubtypes,isVarArgs);
@@ -686,6 +648,65 @@ public class WildTypePattern extends TypePattern {
ret.copyLocationFrom(this);
return ret;
}
+
+ private TypePattern resolveGenericWildcard(IScope scope, UnresolvedType aType) {
+ if (!aType.getSignature().equals(GENERIC_WILDCARD_CHARACTER)) throw new IllegalStateException("Can only have bounds for a generic wildcard");
+ boolean canBeExact = true;
+ if ((upperBound != null) && (upperBound.getExactType() == ResolvedType.MISSING)) canBeExact = false;
+ if ((lowerBound != null) && (lowerBound.getExactType() == ResolvedType.MISSING)) canBeExact = false;
+ if (canBeExact) {
+ ResolvedType type = null;
+ if (upperBound != null) {
+ if (upperBound.isIncludeSubtypes()) {
+ canBeExact = false;
+ } else {
+ ReferenceType upper = (ReferenceType) upperBound.getExactType().resolve(scope.getWorld());
+ type = new BoundedReferenceType(upper,true,scope.getWorld());
+ }
+ } else {
+ if (lowerBound.isIncludeSubtypes()) {
+ canBeExact = false;
+ } else {
+ ReferenceType lower = (ReferenceType) lowerBound.getExactType().resolve(scope.getWorld());
+ type = new BoundedReferenceType(lower,false,scope.getWorld());
+ }
+ }
+ if (canBeExact) {
+ // might have changed if we find out include subtypes is set on one of the bounds...
+ return new ExactTypePattern(type,includeSubtypes,isVarArgs);
+ }
+ }
+
+ // we weren't able to resolve to an exact type pattern...
+ // leave as wild type pattern
+ importedPrefixes = scope.getImportedPrefixes();
+ knownMatches = preMatch(scope.getImportedNames());
+ return this;
+ }
+
+ private TypePattern resolveParameterizedType(IScope scope, UnresolvedType aType, boolean requireExactType) {
+ if (!verifyTypeParameters(aType.resolve(scope.getWorld()),scope,requireExactType)) return TypePattern.NO; // messages already isued
+ // Only if the type is exact *and* the type parameters are exact should we create an
+ // ExactTypePattern for this WildTypePattern
+ if (typeParameters.areAllExact()) {
+ TypePattern[] typePats = typeParameters.getTypePatterns();
+ UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
+ for (int i = 0; i < typeParameterTypes.length; i++) {
+ typeParameterTypes[i] = ((ExactTypePattern)typePats[i]).getExactType();
+ }
+ ResolvedType type = TypeFactory.createParameterizedType(aType.resolve(scope.getWorld()), typeParameterTypes, scope.getWorld());
+ if (isGeneric) type = type.getGenericType();
+// UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
+// UnresolvedType type = scope.getWorld().resolve(tx,true);
+ if (dim != 0) type = ResolvedType.makeArray(type, dim);
+ return new ExactTypePattern(type,includeSubtypes,isVarArgs);
+ } else {
+ // AMC... just leave it as a wild type pattern then?
+ importedPrefixes = scope.getImportedPrefixes();
+ knownMatches = preMatch(scope.getImportedNames());
+ return this;
+ }
+ }
private TypePattern resolveBindingsForMissingType(ResolvedType typeFoundInWholeWorldSearch, String nameWeLookedFor, IScope scope, Bindings bindings,
boolean allowBinding, boolean requireExactType) {
@@ -935,6 +956,14 @@ public class WildTypePattern extends TypePattern {
buf.append(name.toString());
}
}
+ if (upperBound != null) {
+ buf.append(" extends ");
+ buf.append(upperBound.toString());
+ }
+ if (lowerBound != null) {
+ buf.append(" super ");
+ buf.append(lowerBound.toString());
+ }
if (typeParameters!=null && typeParameters.size()!=0) {
buf.append("<");
buf.append(typeParameters.toString());
diff --git a/weaver/testsrc/BcweaverModuleTests15.java b/weaver/testsrc/BcweaverModuleTests15.java
index b4612e6d4..dce28d325 100644
--- a/weaver/testsrc/BcweaverModuleTests15.java
+++ b/weaver/testsrc/BcweaverModuleTests15.java
@@ -14,12 +14,12 @@ import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.aspectj.weaver.BoundedReferenceTypeTestCase;
-import org.aspectj.weaver.GenericsWildCardTypeXTestCase;
import org.aspectj.weaver.MemberTestCase15;
import org.aspectj.weaver.ReferenceTypeTestCase;
import org.aspectj.weaver.TypeVariableReferenceTypeTestCase;
import org.aspectj.weaver.TypeVariableTestCase;
import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXTestCase;
+import org.aspectj.weaver.patterns.WildTypePatternResolutionTestCase;
public class BcweaverModuleTests15 extends TestCase {
public static Test suite() {
@@ -28,9 +28,9 @@ public class BcweaverModuleTests15 extends TestCase {
suite.addTestSuite(ReferenceTypeTestCase.class);
suite.addTestSuite(BoundedReferenceTypeTestCase.class);
suite.addTestSuite(TypeVariableReferenceTypeTestCase.class);
- suite.addTestSuite(GenericsWildCardTypeXTestCase.class);
suite.addTestSuite(MemberTestCase15.class);
suite.addTestSuite(BcelGenericSignatureToTypeXTestCase.class);
+ suite.addTestSuite(WildTypePatternResolutionTestCase.class);
return suite;
}
diff --git a/weaver/testsrc/org/aspectj/weaver/GenericsWildCardTypeXTestCase.java b/weaver/testsrc/org/aspectj/weaver/GenericsWildCardTypeXTestCase.java
deleted file mode 100644
index 3545a496c..000000000
--- a/weaver/testsrc/org/aspectj/weaver/GenericsWildCardTypeXTestCase.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* *******************************************************************
- * Copyright (c) 2005 Contributors.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Adrian Colyer Initial implementation
- * ******************************************************************/
-package org.aspectj.weaver;
-
-import org.aspectj.weaver.bcel.BcelWorld;
-
-import junit.framework.TestCase;
-
-/**
- * @author colyer
- *
- */
-public class GenericsWildCardTypeXTestCase extends TestCase {
-
- public void testIdentity() {
- UnresolvedType anything = GenericsWildcardTypeX.GENERIC_WILDCARD;
- assertEquals("Ljava/lang/Object;",anything.getSignature());
- }
-
- public void testResolving() {
- BoundedReferenceType brt = (BoundedReferenceType)
- GenericsWildcardTypeX.GENERIC_WILDCARD.resolve(new BcelWorld());
- assertEquals("Ljava/lang/Object;",brt.getSignature());
- assertTrue(brt.isExtends());
- assertEquals("Ljava/lang/Object;",brt.getUpperBound().getSignature());
- }
-
-}
diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/WildTypePatternResolutionTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/WildTypePatternResolutionTestCase.java
new file mode 100644
index 000000000..59fdb7d63
--- /dev/null
+++ b/weaver/testsrc/org/aspectj/weaver/patterns/WildTypePatternResolutionTestCase.java
@@ -0,0 +1,470 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.aspectj.weaver.BoundedReferenceType;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeFactory;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.bcel.BcelWorld;
+
+// TODO write test cases for instanceof matching
+
+ public class WildTypePatternResolutionTestCase extends TestCase {
+
+ private World world;
+ private Bindings bindings;
+ private SimpleScope scope;
+ private ResolvedType javaUtilList;
+ private ResolvedType javaLangString;
+ private ResolvedType javaUtilListOfString;
+ private ResolvedType javaUtilListOfDouble;
+ private ResolvedType javaUtilListOfSomething;
+
+ /**
+ * Foo where Foo exists and is generic
+ * Parser creates WildTypePattern namePatterns={Foo}
+ * resolveBindings resolves Foo to RT(Foo - raw)
+ * return ExactTypePattern(LFoo;)
+ */
+ public void testSimpleFoo() {
+ TypePattern rtp = resolveWildTypePattern("List", false);
+
+ assertTrue("resolves to exact type",rtp instanceof ExactTypePattern);
+ UnresolvedType exactType = rtp.getExactType();
+ assertTrue(exactType.isRawType());
+ assertEquals("Ljava/util/List;",exactType.getSignature());
+
+ ResolvedType rt = exactType.resolve(world);
+ assertEquals("Ljava/util/List;",rt.getSignature());
+ assertTrue(rt.isRawType());
+
+ ExactTypePattern etp = (ExactTypePattern) writeAndRead((ExactTypePattern)rtp);
+ exactType = etp.getExactType();
+
+ assertEquals("Ljava/util/List;",exactType.getSignature());
+
+ rt = exactType.resolve(world);
+ assertEquals("Ljava/util/List;",rt.getSignature());
+ assertTrue(rt.isRawType());
+
+ assertTrue("matches List",etp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertTrue("matches generic List",etp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertTrue("matches parameterized list",etp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",etp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ }
+
+ /**
+ * Foo<String> where Foo exists and String meets the bounds
+ * Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{String}
+ * resolveBindings resolves typeParameters to ExactTypePattern(String)
+ * resolves Foo to RT(Foo)
+ * returns ExactTypePattern(PFoo<String>; - parameterized)
+ */
+ public void testParameterized() {
+ TypePattern rtp = resolveWildTypePattern("List<String>", false);
+
+ assertTrue("resolves to exact type",rtp instanceof ExactTypePattern);
+ UnresolvedType exactType = rtp.getExactType();
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<Ljava/lang/String;>;",exactType.getSignature());
+
+ ResolvedType rt = exactType.resolve(world);
+ assertEquals("Pjava/util/List<Ljava/lang/String;>;",rt.getSignature());
+ assertTrue(rt.isParameterizedType());
+
+ ExactTypePattern etp = (ExactTypePattern) writeAndRead((ExactTypePattern)rtp);
+ exactType = etp.getExactType();
+
+ assertEquals("Pjava/util/List<Ljava/lang/String;>;",rt.getSignature());
+ assertTrue(rt.isParameterizedType());
+
+ rt = exactType.resolve(world);
+ assertEquals("Pjava/util/List<Ljava/lang/String;>;",rt.getSignature());
+ assertTrue(rt.isParameterizedType());
+
+ assertFalse("does not match List",etp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",etp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertTrue("matches parameterized list",etp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",etp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",etp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+
+ }
+
+ /**
+ * Foo<Str*> where Foo exists and takes one bound
+ * Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{Str*}
+ * resolveBindings resolves typeParameters to WTP{Str*}
+ * resolves Foo to RT(Foo)
+ * returns WildTypePattern(name = Foo, typeParameters = WTP{Str*} isGeneric=false)
+ */
+ public void testParameterizedWildCard() {
+ TypePattern rtp = resolveWildTypePattern("List<Str*>", false);
+
+ assertTrue("resolves to WildTypePattern",rtp instanceof WildTypePattern);
+ assertTrue("one type parameter", rtp.typeParameters.size() == 1);
+ assertEquals("missing",ResolvedType.MISSING,rtp.getExactType());
+
+ WildTypePattern wtp = (WildTypePattern) writeAndRead(rtp);
+ assertTrue("one type parameter", wtp.typeParameters.size() == 1);
+ assertEquals("missing",ResolvedType.MISSING,wtp.getExactType());
+ assertEquals("Str*",wtp.getTypeParameters().getTypePatterns()[0].toString());
+
+ assertFalse("does not match List",wtp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",wtp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertTrue("matches parameterized list",wtp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",wtp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",wtp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ }
+
+ /**
+ * Fo*<String>
+ * Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{String}
+ * resolveBindings resolves typeParameters to ETP{String}
+ * returns WildTypePattern(name = Fo*, typeParameters = ETP{String} isGeneric=false)
+ */
+ public void testWildcardParameterized() {
+ TypePattern rtp = resolveWildTypePattern("Li*<String>", false);
+
+ assertTrue("resolves to WildTypePattern",rtp instanceof WildTypePattern);
+ assertTrue("one type parameter", rtp.typeParameters.size() == 1);
+ assertEquals("Ljava/lang/String;",rtp.typeParameters.getTypePatterns()[0].getExactType().getSignature());
+
+ WildTypePattern wtp = (WildTypePattern) writeAndRead(rtp);
+ assertTrue("one type parameter", wtp.typeParameters.size() == 1);
+ assertEquals("Ljava/lang/String;",wtp.typeParameters.getTypePatterns()[0].getExactType().getSignature());
+
+ assertFalse("does not match List",wtp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",wtp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertTrue("matches parameterized list",wtp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",wtp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",wtp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ }
+
+ /**
+ * Foo<?>
+ */
+ public void testSomething() {
+ TypePattern rtp = resolveWildTypePattern("List<?>", false);
+
+ assertTrue("resolves to exact type",rtp instanceof ExactTypePattern);
+ UnresolvedType exactType = rtp.getExactType();
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<?>;",exactType.getSignature());
+
+ ExactTypePattern etp = (ExactTypePattern) writeAndRead(rtp);
+ exactType = etp.getExactType();
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<?>;",exactType.getSignature());
+
+ assertFalse("does not match List",etp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",etp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list",etp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",etp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",etp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+
+ assertTrue("matches list of something",etp.matches(javaUtilListOfSomething,TypePattern.STATIC).alwaysTrue());
+ }
+
+ /**
+ * Foo<? extends Number>
+ */
+ public void testSomethingExtends() {
+ TypePattern rtp = resolveWildTypePattern("List<? extends Number>", false);
+
+ assertTrue("resolves to exact type",rtp instanceof ExactTypePattern);
+ UnresolvedType exactType = rtp.getExactType();
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<+Ljava/lang/Number;>;",exactType.getSignature());
+ assertTrue("got a bounded reference type",exactType.getTypeParameters()[0] instanceof BoundedReferenceType);
+
+ ExactTypePattern etp = (ExactTypePattern) writeAndRead(rtp);
+ exactType = etp.getExactType();
+ exactType = exactType.resolve(world);
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<+Ljava/lang/Number;>;",exactType.getSignature());
+ assertTrue("got a bounded reference type",exactType.getTypeParameters()[0] instanceof BoundedReferenceType);
+
+ assertFalse("does not match List",etp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",etp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list",etp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",etp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",etp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ assertFalse("does not match list of something",etp.matches(javaUtilListOfSomething,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType listOfNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Number").resolve(world)},
+ world);
+
+ ResolvedType listOfDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Double").resolve(world)},
+ world);
+
+ assertFalse("does not match list of number",etp.matches(listOfNumber,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match list of double",etp.matches(listOfDouble,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType extendsNumber = TypeFactory.createTypeFromSignature("+Ljava/lang/Number;").resolve(world);
+ ResolvedType listOfExtendsNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {extendsNumber},
+ world);
+
+ assertTrue("matches list of ? extends number",etp.matches(listOfExtendsNumber,TypePattern.STATIC).alwaysTrue());
+
+ }
+
+ /**
+ * Foo<? extends Number+>
+ */
+ public void testSomethingExtendsPattern() {
+ TypePattern rtp = resolveWildTypePattern("List<? extends Number+>", false);
+
+ assertTrue("resolves to wild type pattern",rtp instanceof WildTypePattern);
+ assertEquals("one type parameter",1,rtp.getTypeParameters().size());
+ TypePattern tp = rtp.getTypeParameters().getTypePatterns()[0];
+ assertTrue("parameter is wild",tp instanceof WildTypePattern);
+ WildTypePattern tpwtp = (WildTypePattern) tp;
+ assertEquals("?",tpwtp.getNamePatterns()[0].maybeGetSimpleName());
+ assertEquals("java.lang.Number+",tpwtp.upperBound.toString());
+
+
+ WildTypePattern wtp = (WildTypePattern) writeAndRead(rtp);
+ assertEquals("one type parameter",1,wtp.getTypeParameters().size());
+ tp = rtp.getTypeParameters().getTypePatterns()[0];
+ assertTrue("parameter is wild",tp instanceof WildTypePattern);
+ tpwtp = (WildTypePattern) tp;
+ assertEquals("?",tpwtp.getNamePatterns()[0].maybeGetSimpleName());
+ assertEquals("java.lang.Number+",tpwtp.upperBound.toString());
+
+ assertFalse("does not match List",wtp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",wtp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list",wtp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",wtp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",wtp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ assertFalse("does not match list of something",wtp.matches(javaUtilListOfSomething,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType listOfNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Number").resolve(world)},
+ world);
+
+ ResolvedType listOfDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Double").resolve(world)},
+ world);
+
+ assertFalse("does not match list of number",wtp.matches(listOfNumber,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match list of double",wtp.matches(listOfDouble,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType extendsNumber = TypeFactory.createTypeFromSignature("+Ljava/lang/Number;").resolve(world);
+ ResolvedType listOfExtendsNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {extendsNumber},
+ world);
+
+ assertTrue("matches list of ? extends number",wtp.matches(listOfExtendsNumber,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType extendsDouble = TypeFactory.createTypeFromSignature("+Ljava/lang/Double;").resolve(world);
+ ResolvedType listOfExtendsDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {extendsDouble},
+ world);
+
+ assertTrue("matches list of ? extends double",wtp.matches(listOfExtendsDouble,TypePattern.STATIC).alwaysTrue());
+
+ }
+
+
+ /**
+ * Foo<? extends Num*>
+ */
+ public void testSomethingExtendsPatternv2() {
+ TypePattern rtp = resolveWildTypePattern("List<? extends Num*>", false);
+
+ assertTrue("resolves to wild type pattern",rtp instanceof WildTypePattern);
+ assertEquals("one type parameter",1,rtp.getTypeParameters().size());
+ TypePattern tp = rtp.getTypeParameters().getTypePatterns()[0];
+ assertTrue("parameter is wild",tp instanceof WildTypePattern);
+ WildTypePattern tpwtp = (WildTypePattern) tp;
+ assertEquals("?",tpwtp.getNamePatterns()[0].maybeGetSimpleName());
+ assertEquals("Num*",tpwtp.upperBound.toString());
+
+
+ WildTypePattern wtp = (WildTypePattern) writeAndRead(rtp);
+ assertEquals("one type parameter",1,wtp.getTypeParameters().size());
+ tp = rtp.getTypeParameters().getTypePatterns()[0];
+ assertTrue("parameter is wild",tp instanceof WildTypePattern);
+ tpwtp = (WildTypePattern) tp;
+ assertEquals("?",tpwtp.getNamePatterns()[0].maybeGetSimpleName());
+ assertEquals("Num*",tpwtp.upperBound.toString());
+
+ assertFalse("does not match List",wtp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",wtp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list",wtp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",wtp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",wtp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ assertFalse("does not match list of something",wtp.matches(javaUtilListOfSomething,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType listOfNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Number").resolve(world)},
+ world);
+
+ ResolvedType listOfDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Double").resolve(world)},
+ world);
+
+ assertFalse("does not match list of number",wtp.matches(listOfNumber,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match list of double",wtp.matches(listOfDouble,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType extendsNumber = TypeFactory.createTypeFromSignature("+Ljava/lang/Number;").resolve(world);
+ ResolvedType listOfExtendsNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {extendsNumber},
+ world);
+
+ assertTrue("matches list of ? extends number",wtp.matches(listOfExtendsNumber,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType extendsDouble = TypeFactory.createTypeFromSignature("+Ljava/lang/Double;").resolve(world);
+ ResolvedType listOfExtendsDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {extendsDouble},
+ world);
+
+ assertFalse("does not match list of ? extends double",wtp.matches(listOfExtendsDouble,TypePattern.STATIC).alwaysTrue());
+ }
+
+ /**
+ * Foo<? super Number>
+ *
+ */
+ public void testSomethingSuper() {
+ TypePattern rtp = resolveWildTypePattern("List<? super Double>", false);
+
+ assertTrue("resolves to exact type",rtp instanceof ExactTypePattern);
+ UnresolvedType exactType = rtp.getExactType();
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<-Ljava/lang/Double;>;",exactType.getSignature());
+ assertTrue("got a bounded reference type",exactType.getTypeParameters()[0] instanceof BoundedReferenceType);
+
+ ExactTypePattern etp = (ExactTypePattern) writeAndRead(rtp);
+ exactType = etp.getExactType();
+ exactType = exactType.resolve(world);
+ assertTrue(exactType.isParameterizedType());
+ assertEquals("Pjava/util/List<-Ljava/lang/Double;>;",exactType.getSignature());
+ assertTrue("got a bounded reference type",exactType.getTypeParameters()[0] instanceof BoundedReferenceType);
+
+ assertFalse("does not match List",etp.matches(javaUtilList, TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match generic List",etp.matches(javaUtilList.getGenericType(),TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list",etp.matches(javaUtilListOfString,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match parameterized list of double",etp.matches(javaUtilListOfDouble,TypePattern.STATIC).alwaysTrue());
+ assertTrue("does not match String",etp.matches(javaLangString,TypePattern.STATIC).alwaysFalse());
+ assertFalse("does not match list of something",etp.matches(javaUtilListOfSomething,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType listOfNumber =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Number").resolve(world)},
+ world);
+
+ ResolvedType listOfDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Double").resolve(world)},
+ world);
+
+ assertFalse("does not match list of number",etp.matches(listOfNumber,TypePattern.STATIC).alwaysTrue());
+ assertFalse("does not match list of double",etp.matches(listOfDouble,TypePattern.STATIC).alwaysTrue());
+
+ ResolvedType superDouble = TypeFactory.createTypeFromSignature("-Ljava/lang/Double;").resolve(world);
+ ResolvedType listOfSuperDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {superDouble},
+ world);
+
+ assertTrue("matches list of ? super double",etp.matches(listOfSuperDouble,TypePattern.STATIC).alwaysTrue());
+ }
+
+ private TypePattern resolveWildTypePattern(String source, boolean requireExact) {
+ WildTypePattern wtp = makeWildTypePattern(source);
+ return wtp.resolveBindings(scope, bindings, false, requireExact);
+ }
+
+ private WildTypePattern makeWildTypePattern(String source) {
+ PatternParser parser = new PatternParser(source);
+ return (WildTypePattern) parser.parseTypePattern();
+ }
+
+ private TypePattern writeAndRead(TypePattern etp) {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ etp.write(dos);
+ dos.flush();
+ dos.close();
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ VersionedDataInputStream in = new VersionedDataInputStream(bais);
+ in.setVersion(new WeaverVersionInfo());
+ TypePattern ret = TypePattern.read(in, null);
+ return ret;
+ } catch (IOException ioEx) {
+ fail(ioEx + " thrown during serialization");
+ }
+ return null;
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.world = new BcelWorld();
+ this.bindings = new Bindings(0);
+ this.scope = new SimpleScope(world , new FormalBinding[] {});
+ this.scope.setImportedPrefixes(new String[] {"java.io.","java.util.","java.lang."});
+ this.javaLangString = UnresolvedType.forName("java.lang.String").resolve(world);
+ this.javaUtilList = UnresolvedType.forName("java.util.List").resolve(world);
+ this.javaUtilListOfString = TypeFactory.createParameterizedType(javaUtilList, new UnresolvedType[] {javaLangString}, world);
+ this.javaUtilListOfDouble =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.forName("java.lang.Double").resolve(world)},
+ world);
+ this.javaUtilListOfSomething =
+ TypeFactory.createParameterizedType(
+ javaUtilList,
+ new UnresolvedType[] {UnresolvedType.SOMETHING.resolve(world)},
+ world);
+ }
+}