diff options
author | acolyer <acolyer> | 2005-07-28 10:55:30 +0000 |
---|---|---|
committer | acolyer <acolyer> | 2005-07-28 10:55:30 +0000 |
commit | b94dee2854b998ccd1bc1738e91f0ce36e781cbb (patch) | |
tree | 289c679c26b31f97fb15bd871a5b6194749fef01 | |
parent | 8cb70f37f86030709e51d62e8d1579e418ecc107 (diff) | |
download | aspectj-b94dee2854b998ccd1bc1738e91f0ce36e781cbb.tar.gz aspectj-b94dee2854b998ccd1bc1738e91f0ce36e781cbb.zip |
full support for generic wildcard (?, ? extends, ? super)
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); + } +} |