aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--weaver/src/org/aspectj/weaver/ReferenceType.java8
-rw-r--r--weaver/src/org/aspectj/weaver/ResolvedType.java11
-rw-r--r--weaver/src/org/aspectj/weaver/TypeVariable.java49
-rw-r--r--weaver/src/org/aspectj/weaver/TypeVariableReference.java22
-rw-r--r--weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java4
-rw-r--r--weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java13
-rw-r--r--weaver/src/org/aspectj/weaver/World.java7
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java157
8 files changed, 253 insertions, 18 deletions
diff --git a/weaver/src/org/aspectj/weaver/ReferenceType.java b/weaver/src/org/aspectj/weaver/ReferenceType.java
index c377daf50..de65d1d86 100644
--- a/weaver/src/org/aspectj/weaver/ReferenceType.java
+++ b/weaver/src/org/aspectj/weaver/ReferenceType.java
@@ -283,7 +283,13 @@ public class ReferenceType extends ResolvedType {
}
public TypeVariable[] getTypeVariables() {
- return delegate.getTypeVariables();
+ if (this.typeVariables == null) {
+ this.typeVariables = delegate.getTypeVariables();
+ for (int i = 0; i < this.typeVariables.length; i++) {
+ this.typeVariables[i].resolve(world);
+ }
+ }
+ return this.typeVariables;
}
public PerClause getPerClause() { return delegate.getPerClause(); }
diff --git a/weaver/src/org/aspectj/weaver/ResolvedType.java b/weaver/src/org/aspectj/weaver/ResolvedType.java
index 20ecf94ed..f1aa7761e 100644
--- a/weaver/src/org/aspectj/weaver/ResolvedType.java
+++ b/weaver/src/org/aspectj/weaver/ResolvedType.java
@@ -616,6 +616,11 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
public static final Missing MISSING = new Missing();
// ---- types
+ public static ResolvedType makeArray(ResolvedType type, int dim) {
+ if (dim == 0) return type;
+ ResolvedType array = new Array("[" + type.getSignature(),type.getWorld(),type);
+ return makeArray(array,dim-1);
+ }
static class Array extends ResolvedType {
ResolvedType componentType;
@@ -1405,7 +1410,7 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
throw new BCException("The type "+getBaseName()+" is not parameterized or raw - it has no generic type");
return null;
}
-
+
public ResolvedType parameterizedWith(UnresolvedType[] typeParameters) {
if (!(isGenericType() || isParameterizedType())) return this;
return TypeFactory.createParameterizedType(this.getGenericType(), typeParameters, getWorld());
@@ -1420,7 +1425,7 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
if (!isParameterizedType()) throw new IllegalStateException("Can't parameterize a type that is not a parameterized type");
boolean workToDo = false;
for (int i = 0; i < typeParameters.length; i++) {
- if (typeParameters[i].isTypeVariable()) {
+ if (typeParameters[i].isTypeVariableReference()) {
workToDo = true;
}
}
@@ -1430,7 +1435,7 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
UnresolvedType[] newTypeParams = new UnresolvedType[typeParameters.length];
for (int i = 0; i < newTypeParams.length; i++) {
newTypeParams[i] = typeParameters[i];
- if (newTypeParams[i].isTypeVariable()) {
+ if (newTypeParams[i].isTypeVariableReference()) {
TypeVariableReferenceType tvrt = (TypeVariableReferenceType) newTypeParams[i];
UnresolvedType binding = (UnresolvedType) typeBindings.get(tvrt.getTypeVariable().getName());
if (binding != null) newTypeParams[i] = binding;
diff --git a/weaver/src/org/aspectj/weaver/TypeVariable.java b/weaver/src/org/aspectj/weaver/TypeVariable.java
index 042f4425f..b4b4d0261 100644
--- a/weaver/src/org/aspectj/weaver/TypeVariable.java
+++ b/weaver/src/org/aspectj/weaver/TypeVariable.java
@@ -105,7 +105,11 @@ public class TypeVariable {
*/
public boolean canBeBoundTo(ResolvedType aCandidateType) {
if (!isResolved) throw new IllegalStateException("Can't answer binding questions prior to resolving");
- // can be bound iff...
+ if (aCandidateType.isTypeVariableReference()) {
+ return matchingBounds((TypeVariableReferenceType)aCandidateType);
+ }
+
+ // otherwise can be bound iff...
// aCandidateType is a subtype of upperBound
if (!isASubtypeOf(upperBound,aCandidateType)) {
return false;
@@ -123,20 +127,59 @@ public class TypeVariable {
return true;
}
+ // can match any type in the range of the type variable...
+ // XXX what about interfaces?
+ private boolean matchingBounds(TypeVariableReferenceType tvrt) {
+ boolean upperMatch = canBeBoundTo(tvrt.getUpperBound());
+ boolean lowerMatch = true;
+ if (tvrt.hasLowerBound()) lowerMatch = canBeBoundTo(tvrt.getLowerBound());
+ return upperMatch && lowerMatch;
+ }
+
private boolean isASubtypeOf(UnresolvedType candidateSuperType, UnresolvedType candidateSubType) {
ResolvedType superType = (ResolvedType) candidateSuperType;
ResolvedType subType = (ResolvedType) candidateSubType;
return superType.isAssignableFrom(subType);
}
- // only used when resolving circular dependencies
+ // only used when resolving
public void setUpperBound(UnresolvedType aTypeX) {
this.upperBound = aTypeX;
}
+ // only used when resolving
+ public void setLowerBound(UnresolvedType aTypeX) {
+ this.lowerBound = aTypeX;
+ }
+
+ // only used when resolving
+ public void setAdditionalInterfaceBounds(UnresolvedType[] someTypeXs) {
+ this.additionalInterfaceBounds = someTypeXs;
+ }
+
+ public String getDisplayName() {
+ StringBuffer ret = new StringBuffer();
+ ret.append(name);
+ if (!upperBound.getName().equals("java.lang.Object")) {
+ ret.append(" extends ");
+ ret.append(upperBound.getName());
+ if (additionalInterfaceBounds != null) {
+ for (int i = 0; i < additionalInterfaceBounds.length; i++) {
+ ret.append(" & ");
+ ret.append(additionalInterfaceBounds[i].getName());
+ }
+ }
+ }
+ if (lowerBound != null) {
+ ret.append(" super ");
+ ret.append(lowerBound.getName());
+ }
+ return ret.toString();
+ }
+
// good enough approximation
public String toString() {
- return "T" + upperBound.getSignature();
+ return "TypeVar " + getDisplayName();
}
/**
diff --git a/weaver/src/org/aspectj/weaver/TypeVariableReference.java b/weaver/src/org/aspectj/weaver/TypeVariableReference.java
new file mode 100644
index 000000000..fc6a989c7
--- /dev/null
+++ b/weaver/src/org/aspectj/weaver/TypeVariableReference.java
@@ -0,0 +1,22 @@
+/* *******************************************************************
+ * 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;
+
+/**
+ * Implemented by Types that represent references to type variables
+ *
+ */
+public interface TypeVariableReference {
+
+ TypeVariable getTypeVariable();
+
+}
diff --git a/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java b/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java
index c37bd6369..bb37f3473 100644
--- a/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java
+++ b/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java
@@ -14,7 +14,7 @@ package org.aspectj.weaver;
/**
* Represents a type variable in a type or generic method declaration
*/
-public class TypeVariableReferenceType extends BoundedReferenceType {
+public class TypeVariableReferenceType extends BoundedReferenceType implements TypeVariableReference {
private TypeVariable typeVariable;
@@ -41,7 +41,7 @@ public class TypeVariableReferenceType extends BoundedReferenceType {
return typeVariable;
}
- public boolean isTypeVariable() {
+ public boolean isTypeVariableReference() {
return true;
}
diff --git a/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java b/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java
index 32dd637fe..667c10c43 100644
--- a/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java
+++ b/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java
@@ -16,7 +16,7 @@ package org.aspectj.weaver;
* Represents a type variable encountered in the Eclipse Source world,
* which when resolved will turn into a TypeVariableReferenceType
*/
-public class UnresolvedTypeVariableReferenceType extends UnresolvedType {
+public class UnresolvedTypeVariableReferenceType extends UnresolvedType implements TypeVariableReference {
private TypeVariable typeVariable;
@@ -42,10 +42,19 @@ public class UnresolvedTypeVariableReferenceType extends UnresolvedType {
return new TypeVariableReferenceType(typeVariable,world);
}
- public boolean isTypeVariable() {
+ public boolean isTypeVariableReference() {
return true;
}
+
+ public TypeVariable getTypeVariable() {
+ return typeVariable;
+ }
+// public String getName() {
+// if (typeVariable == null) return "<type variable not set!>";
+// return typeVariable.getDisplayName();
+// }
+
public String toString() {
if (typeVariable == null) {
return "<type variable not set!>";
diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java
index d54ebfb57..0f9ca3410 100644
--- a/weaver/src/org/aspectj/weaver/World.java
+++ b/weaver/src/org/aspectj/weaver/World.java
@@ -115,7 +115,7 @@ public abstract class World implements Dump.INode {
// if we already have an rtx, don't re-resolve it
public ResolvedType resolve(ResolvedType ty) {
- if (ty.isTypeVariable()) return ty; // until type variables have proper sigs...
+ if (ty.isTypeVariableReference()) return ty; // until type variables have proper sigs...
ResolvedType resolved = typeMap.get(ty.getSignature());
if (resolved == null) {
typeMap.put(ty.getSignature(), ty);
@@ -151,7 +151,10 @@ public abstract class World implements Dump.INode {
// raw type from a source type, it won't if its been created just through
// being referenced, e.g. java.util.List
ResolvedType generic = ret.getGenericType();
- if (generic != null) { generic.world = this; return generic; }
+ if (generic != null) {
+ generic.world = this;
+ return generic;
+ }
// Fault in the generic that underpins the raw type ;)
ReferenceTypeDelegate thegen = resolveObjectType((ReferenceType)ret);
diff --git a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
index 0d43a4797..a4234982f 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
@@ -28,7 +28,10 @@ import org.aspectj.weaver.BCException;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.TypeFactory;
+import org.aspectj.weaver.TypeVariable;
+import org.aspectj.weaver.TypeVariableReference;
import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
@@ -47,6 +50,10 @@ public class WildTypePattern extends TypePattern {
TypePattern[] additionalInterfaceBounds; // extends Foo & A,B,C
TypePattern lowerBound; // super Foo
+ // if we have type parameters, these fields indicate whether we should be a generic type pattern or a parameterized
+ // type pattern. We can only tell during resolve bindings.
+ private boolean isGeneric = true;
+
WildTypePattern(NamePattern[] namePatterns, boolean includeSubtypes, int dim, boolean isVarArgs, TypePatternList typeParams) {
super(includeSubtypes,isVarArgs,typeParams);
this.namePatterns = namePatterns;
@@ -434,6 +441,19 @@ public class WildTypePattern extends TypePattern {
// resolve any type parameters
if (typeParameters!=null && typeParameters.size()>0) {
typeParameters.resolveBindings(scope,bindings,allowBinding,requireExactType);
+ // now we have to decide whether to create a "generic" type pattern or a "parameterized" type
+ // pattern
+ // start with the simple rule that if all parameters have resolved to a type variable based pattern
+ // then it is generic, otherwise it is parameterized
+ // if we have e.g. staticinitialization<T>(Foo<T,String>) then that's a parameterized type
+ isGeneric = true;
+ TypePattern[] tps = typeParameters.getTypePatterns();
+ for (int i = 0; i < tps.length; i++) {
+ if (!tps[i].getExactType().isTypeVariableReference()) {
+ isGeneric = false;
+ break;
+ }
+ }
}
String fullyQualifiedName = maybeGetCleanName();
@@ -522,7 +542,11 @@ public class WildTypePattern extends TypePattern {
private TypePattern resolveBindingsForExactType(IScope scope, UnresolvedType aType, String fullyQualifiedName) {
TypePattern ret = null;
- if (typeParameters.size()>0) {
+ if (aType.isTypeVariableReference()) {
+ // 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)) 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()) {
@@ -531,14 +555,13 @@ public class WildTypePattern extends TypePattern {
for (int i = 0; i < typeParameterTypes.length; i++) {
typeParameterTypes[i] = ((ExactTypePattern)typePats[i]).getExactType();
}
- UnresolvedType type = TypeFactory.createParameterizedType(aType.resolve(scope.getWorld()), typeParameterTypes, scope.getWorld());
+ 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 = UnresolvedType.makeArray(type, dim);
+ if (dim != 0) type = ResolvedType.makeArray(type, dim);
ret = new ExactTypePattern(type,includeSubtypes,isVarArgs);
} else {
- // TODO generics not written yet - when the type parameters are not exact
- //throw new RuntimeException("Type parameters are not exact");
// AMC... just leave it as a wild type pattern then?
importedPrefixes = scope.getImportedPrefixes();
knownMatches = preMatch(scope.getImportedNames());
@@ -575,6 +598,130 @@ public class WildTypePattern extends TypePattern {
return this;
}
+ /**
+ * We resolved the type to a type variable declared in the pointcut designator.
+ * Now we have to create either an exact type pattern or a wild type pattern for it,
+ * with upper and lower bounds set accordingly.
+ * XXX none of this stuff gets serialized yet
+ * @param scope
+ * @param tvrType
+ * @return
+ */
+ private TypePattern resolveBindingsForTypeVariable(IScope scope, UnresolvedTypeVariableReferenceType tvrType) {
+ Bindings emptyBindings = new Bindings(0);
+ if (upperBound != null) {
+ upperBound = upperBound.resolveBindings(scope, emptyBindings, false, false);
+ }
+ if (lowerBound != null) {
+ lowerBound = lowerBound.resolveBindings(scope, emptyBindings, false, false);
+ }
+ if (additionalInterfaceBounds != null) {
+ TypePattern[] resolvedIfBounds = new TypePattern[additionalInterfaceBounds.length];
+ for (int i = 0; i < resolvedIfBounds.length; i++) {
+ resolvedIfBounds[i] = additionalInterfaceBounds[i].resolveBindings(scope, emptyBindings, false, false);
+ }
+ additionalInterfaceBounds = resolvedIfBounds;
+ }
+ if ( upperBound == null && lowerBound == null && additionalInterfaceBounds == null) {
+ // no bounds to worry about...
+ ResolvedType rType = tvrType.resolve(scope.getWorld());
+ if (dim != 0) rType = ResolvedType.makeArray(rType, dim);
+ return new ExactTypePattern(rType,includeSubtypes,isVarArgs);
+ } else {
+ // we have to set bounds on the TypeVariable held by tvrType before resolving it
+ boolean canCreateExactTypePattern = true;
+ if (upperBound != null && upperBound.getExactType() == ResolvedType.MISSING) canCreateExactTypePattern = false;
+ if (lowerBound != null && lowerBound.getExactType() == ResolvedType.MISSING) canCreateExactTypePattern = false;
+ if (additionalInterfaceBounds != null) {
+ for (int i = 0; i < additionalInterfaceBounds.length; i++) {
+ if (additionalInterfaceBounds[i].getExactType() == ResolvedType.MISSING) canCreateExactTypePattern = false;
+ }
+ }
+ if (canCreateExactTypePattern) {
+ TypeVariable tv = tvrType.getTypeVariable();
+ if (upperBound != null) tv.setUpperBound(upperBound.getExactType());
+ if (lowerBound != null) tv.setLowerBound(lowerBound.getExactType());
+ if (additionalInterfaceBounds != null) {
+ UnresolvedType[] ifBounds = new UnresolvedType[additionalInterfaceBounds.length];
+ for (int i = 0; i < ifBounds.length; i++) {
+ ifBounds[i] = additionalInterfaceBounds[i].getExactType();
+ }
+ tv.setAdditionalInterfaceBounds(ifBounds);
+ }
+ ResolvedType rType = tvrType.resolve(scope.getWorld());
+ if (dim != 0) rType = ResolvedType.makeArray(rType, dim);
+ return new ExactTypePattern(rType,includeSubtypes,isVarArgs);
+ }
+ return this; // leave as wild type pattern then
+ }
+ }
+
+ /**
+ * When this method is called, we have resolved the base type to an exact type.
+ * We also have a set of type patterns for the parameters.
+ * Time to perform some basic checks:
+ * - can the base type be parameterized? (is it generic)
+ * - can the type parameter pattern list match the number of parameters on the base type
+ * - do all parameter patterns meet the bounds of the respective type variables
+ * If any of these checks fail, a warning message is issued and we return false.
+ * @return
+ */
+ private boolean verifyTypeParameters(ResolvedType baseType,IScope scope) {
+ ResolvedType genericType = baseType.getGenericType();
+ if (genericType == null) {
+ // issue message "does not match because baseType.getName() is not generic"
+ scope.message(MessageUtil.warn(
+ WeaverMessages.format(WeaverMessages.NOT_A_GENERIC_TYPE,genericType.getName()),
+ getSourceLocation()));
+ return false;
+ }
+ int minRequiredTypeParameters = typeParameters.size();
+ boolean foundEllipsis = false;
+ TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
+ for (int i = 0; i < typeParamPatterns.length; i++) {
+ if (typeParamPatterns[i] instanceof WildTypePattern) {
+ WildTypePattern wtp = (WildTypePattern) typeParamPatterns[i];
+ if (wtp.ellipsisCount > 0) {
+ foundEllipsis = true;
+ minRequiredTypeParameters--;
+ }
+ }
+ }
+ TypeVariable[] tvs = genericType.getTypeVariables();
+ if ((tvs.length < minRequiredTypeParameters) ||
+ (!foundEllipsis && minRequiredTypeParameters != tvs.length))
+ {
+ // issue message "does not match because wrong no of type params"
+ scope.message(MessageUtil.warn(
+ WeaverMessages.format(WeaverMessages.INCORRECT_NUMBER_OF_TYPE_ARGUMENTS,genericType.getName(),new Integer(tvs.length)),
+ getSourceLocation()));
+ return false;
+ }
+
+ // now check that each typeParameter pattern, if exact, matches the bounds
+ // of the type variable.
+ if (typeParameters.areAllExact()) {
+ for (int i = 0; i < tvs.length; i++) {
+ UnresolvedType ut = typeParamPatterns[i].getExactType();
+ if (!tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
+ // issue message that type parameter does not meet specification
+ String parameterName = ut.getName();
+ if (ut.isTypeVariableReference()) parameterName = ((TypeVariableReference)ut).getTypeVariable().getDisplayName();
+ scope.message(MessageUtil.warn(
+ WeaverMessages.format(
+ WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS,
+ parameterName,
+ new Integer(i+1),
+ tvs[i].getDisplayName(),
+ genericType.getName()),
+ getSourceLocation()));
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
public TypePattern resolveBindingsFromRTTI(boolean allowBinding, boolean requireExactType) {
if (isStar()) {
return TypePattern.ANY; //??? loses source location