1
/* *******************************************************************
2
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
4
* This program and the accompanying materials are made available
5
* under the terms of the Eclipse Public License v1.0
6
* which accompanies this distribution and is available at
7
* http://www.eclipse.org/legal/epl-v10.html
10
* PARC initial implementation
11
* ******************************************************************/
13
package org.aspectj.weaver.patterns;
15
import java.io.DataOutputStream;
16
import java.io.IOException;
17
import java.lang.reflect.Modifier;
18
import java.util.Iterator;
21
import org.aspectj.bridge.MessageUtil;
22
import org.aspectj.util.FuzzyBoolean;
23
import org.aspectj.weaver.BCException;
24
import org.aspectj.weaver.ISourceContext;
25
import org.aspectj.weaver.IntMap;
26
import org.aspectj.weaver.ResolvedType;
27
import org.aspectj.weaver.TypeVariableReference;
28
import org.aspectj.weaver.UnresolvedType;
29
import org.aspectj.weaver.VersionedDataInputStream;
30
import org.aspectj.weaver.WeaverMessages;
31
import org.aspectj.weaver.World;
34
* On creation, type pattern only contains WildTypePattern nodes, not BindingType or ExactType.
37
* Then we call resolveBindings() during compilation During concretization of enclosing pointcuts, we call remapAdviceFormals
39
* @author Erik Hilsdale
42
public abstract class TypePattern extends PatternNode {
43
public static class MatchKind {
46
public MatchKind(String name) {
50
public String toString() {
55
public static final MatchKind STATIC = new MatchKind("STATIC");
56
public static final MatchKind DYNAMIC = new MatchKind("DYNAMIC");
58
public static final TypePattern ELLIPSIS = new EllipsisTypePattern();
59
public static final TypePattern ANY = new AnyTypePattern();
60
public static final TypePattern NO = new NoTypePattern();
62
protected boolean includeSubtypes;
63
protected boolean isVarArgs = false;
64
protected AnnotationTypePattern annotationPattern = AnnotationTypePattern.ANY;
65
protected TypePatternList typeParameters = TypePatternList.EMPTY;
67
protected TypePattern(boolean includeSubtypes, boolean isVarArgs, TypePatternList typeParams) {
68
this.includeSubtypes = includeSubtypes;
69
this.isVarArgs = isVarArgs;
70
this.typeParameters = (typeParams == null ? TypePatternList.EMPTY : typeParams);
73
protected TypePattern(boolean includeSubtypes, boolean isVarArgs) {
74
this(includeSubtypes, isVarArgs, null);
77
public AnnotationTypePattern getAnnotationPattern() {
78
return annotationPattern;
81
public boolean isVarArgs() {
85
public boolean isStarAnnotation() {
86
return annotationPattern == AnnotationTypePattern.ANY;
89
public boolean isArray() {
93
protected TypePattern(boolean includeSubtypes) {
94
this(includeSubtypes, false);
97
public void setAnnotationTypePattern(AnnotationTypePattern annPatt) {
98
this.annotationPattern = annPatt;
101
public void setTypeParameters(TypePatternList typeParams) {
102
this.typeParameters = typeParams;
105
public TypePatternList getTypeParameters() {
106
return this.typeParameters;
109
public void setIsVarArgs(boolean isVarArgs) {
110
this.isVarArgs = isVarArgs;
113
// answer conservatively...
114
protected boolean couldEverMatchSameTypesAs(TypePattern other) {
115
if (this.includeSubtypes || other.includeSubtypes)
117
if (this.annotationPattern != AnnotationTypePattern.ANY)
119
if (other.annotationPattern != AnnotationTypePattern.ANY)
124
// XXX non-final for Not, && and ||
125
public boolean matchesStatically(ResolvedType type) {
126
if (includeSubtypes) {
127
return matchesSubtypes(type);
129
return matchesExactly(type);
133
public abstract FuzzyBoolean matchesInstanceof(ResolvedType type);
135
public final FuzzyBoolean matches(ResolvedType type, MatchKind kind) {
136
// FuzzyBoolean typeMatch = null;
137
// ??? This is part of gracefully handling missing references
138
if (type.isMissing())
139
return FuzzyBoolean.NO;
141
if (kind == STATIC) {
142
// typeMatch = FuzzyBoolean.fromBoolean(matchesStatically(type));
143
// return typeMatch.and(annotationPattern.matches(type));
144
return FuzzyBoolean.fromBoolean(matchesStatically(type));
145
} else if (kind == DYNAMIC) {
146
// System.err.println("matching: " + this + " with " + type);
147
// typeMatch = matchesInstanceof(type);
148
// System.err.println(" got: " + ret);
149
// return typeMatch.and(annotationPattern.matches(type));
150
return matchesInstanceof(type);
152
throw new IllegalArgumentException("kind must be DYNAMIC or STATIC");
156
protected abstract boolean matchesExactly(ResolvedType type);
158
protected abstract boolean matchesExactly(ResolvedType type, ResolvedType annotatedType);
160
protected boolean matchesSubtypes(ResolvedType type) {
161
// System.out.println("matching: " + this + " to " + type);
162
if (matchesExactly(type)) {
167
Iterator typesIterator = null;
168
if (type.isTypeVariableReference()) {
169
typesIterator = ((TypeVariableReference) type).getTypeVariable().getFirstBound().resolve(type.getWorld())
170
.getDirectSupertypes();
173
if (type.isRawType()) {
174
type = type.getGenericType();
176
typesIterator = type.getDirectSupertypes();
179
for (Iterator i = typesIterator; i.hasNext();) {
180
ResolvedType superType = (ResolvedType) i.next();
181
if (matchesSubtypes(superType, type)) {
188
protected boolean matchesSubtypes(ResolvedType superType, ResolvedType annotatedType) {
189
// System.out.println("matching2: " + this + " to " + superType);
190
if (matchesExactly(superType, annotatedType)) {
191
// System.out.println(" true");
194
// If an ITD is applied, it will be put onto the generic type, not the parameterized or raw form
195
if (superType.isParameterizedType() || superType.isRawType()) {
196
superType = superType.getGenericType();
198
// FuzzyBoolean ret = FuzzyBoolean.NO; // ??? -eh
199
for (Iterator i = superType.getDirectSupertypes(); i.hasNext();) {
200
ResolvedType superSuperType = (ResolvedType) i.next();
201
if (matchesSubtypes(superSuperType, annotatedType))
207
public UnresolvedType resolveExactType(IScope scope, Bindings bindings) {
208
TypePattern p = resolveBindings(scope, bindings, false, true);
209
if (!(p instanceof ExactTypePattern))
210
return ResolvedType.MISSING;
211
return ((ExactTypePattern) p).getType();
214
public UnresolvedType getExactType() {
215
if (this instanceof ExactTypePattern)
216
return ((ExactTypePattern) this).getType();
218
return ResolvedType.MISSING;
221
protected TypePattern notExactType(IScope s) {
222
s.getMessageHandler().handleMessage(
223
MessageUtil.error(WeaverMessages.format(WeaverMessages.EXACT_TYPE_PATTERN_REQD), getSourceLocation()));
227
// public boolean assertExactType(IMessageHandler m) {
228
// if (this instanceof ExactTypePattern) return true;
230
// //XXX should try harder to avoid multiple errors for one problem
231
// m.handleMessage(MessageUtil.error("exact type pattern required", getSourceLocation()));
236
* This can modify in place, or return a new TypePattern if the type changes.
238
public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
239
annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
243
public void resolve(World world) {
244
annotationPattern.resolve(world);
248
* return a version of this type pattern in which all type variable references have been replaced by their corresponding entry
251
public abstract TypePattern parameterizeWith(Map typeVariableMap, World w);
253
public void postRead(ResolvedType enclosingType) {
256
public boolean isStar() {
261
* This is called during concretization of pointcuts, it is used by BindingTypePattern to return a new BindingTypePattern with a
262
* formal index appropiate for the advice, rather than for the lexical declaration, i.e. this handles transforamtions through
266
* pointcut foo(String name): args(name);
267
* --> This makes a BindingTypePattern(0) pointing to the 0th formal
269
* before(Foo f, String n): this(f) && foo(n) { ... }
270
* --> when resolveReferences is called on the args from the above, it
271
* will return a BindingTypePattern(1)
273
* before(Foo f): this(f) && foo(*) { ... }
274
* --> when resolveReferences is called on the args from the above, it
275
* will return an ExactTypePattern(String)
278
public TypePattern remapAdviceFormals(IntMap bindings) {
282
public static final byte WILD = 1;
283
public static final byte EXACT = 2;
284
public static final byte BINDING = 3;
285
public static final byte ELLIPSIS_KEY = 4;
286
public static final byte ANY_KEY = 5;
287
public static final byte NOT = 6;
288
public static final byte OR = 7;
289
public static final byte AND = 8;
290
public static final byte NO_KEY = 9;
291
public static final byte ANY_WITH_ANNO = 10;
292
public static final byte HAS_MEMBER = 11;
294
public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
295
byte key = s.readByte();
298
return WildTypePattern.read(s, context);
300
return ExactTypePattern.read(s, context);
302
return BindingTypePattern.read(s, context);
310
return NotTypePattern.read(s, context);
312
return OrTypePattern.read(s, context);
314
return AndTypePattern.read(s, context);
316
return AnyWithAnnotationTypePattern.read(s, context);
318
return HasMemberTypePattern.read(s, context);
320
throw new BCException("unknown TypePattern kind: " + key);
323
public boolean isIncludeSubtypes() {
324
return includeSubtypes;
329
class EllipsisTypePattern extends TypePattern {
332
* Constructor for EllipsisTypePattern.
334
* @param includeSubtypes
336
public EllipsisTypePattern() {
337
super(false, false, new TypePatternList());
343
* @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
345
protected boolean couldEverMatchSameTypesAs(TypePattern other) {
350
* @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType)
352
protected boolean matchesExactly(ResolvedType type) {
356
protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
361
* @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType)
363
public FuzzyBoolean matchesInstanceof(ResolvedType type) {
364
return FuzzyBoolean.NO;
368
* @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream)
370
public void write(DataOutputStream s) throws IOException {
371
s.writeByte(ELLIPSIS_KEY);
374
public String toString() {
381
* @see java.lang.Object#equals(java.lang.Object)
383
public boolean equals(Object obj) {
384
return (obj instanceof EllipsisTypePattern);
390
* @see java.lang.Object#hashCode()
392
public int hashCode() {
396
public Object accept(PatternNodeVisitor visitor, Object data) {
397
return visitor.visit(this, data);
400
public TypePattern parameterizeWith(Map typeVariableMap, World w) {
406
class AnyTypePattern extends TypePattern {
409
* Constructor for EllipsisTypePattern.
411
* @param includeSubtypes
413
public AnyTypePattern() {
414
super(false, false, new TypePatternList());
420
* @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
422
protected boolean couldEverMatchSameTypesAs(TypePattern other) {
427
* @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType)
429
protected boolean matchesExactly(ResolvedType type) {
433
protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
438
* @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType)
440
public FuzzyBoolean matchesInstanceof(ResolvedType type) {
441
return FuzzyBoolean.YES;
445
* @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream)
447
public void write(DataOutputStream s) throws IOException {
448
s.writeByte(ANY_KEY);
452
* @see org.aspectj.weaver.patterns.TypePattern#matches(IType, MatchKind)
454
// public FuzzyBoolean matches(IType type, MatchKind kind) {
455
// return FuzzyBoolean.YES;
458
* @see org.aspectj.weaver.patterns.TypePattern#matchesSubtypes(IType)
460
protected boolean matchesSubtypes(ResolvedType type) {
464
public boolean isStar() {
468
public String toString() {
472
public boolean equals(Object obj) {
473
return (obj instanceof AnyTypePattern);
476
public int hashCode() {
480
public Object accept(PatternNodeVisitor visitor, Object data) {
481
return visitor.visit(this, data);
484
public TypePattern parameterizeWith(Map arg0, World w) {
490
* This type represents a type pattern of '*' but with an annotation specified, e.g. '@Color *'
492
class AnyWithAnnotationTypePattern extends TypePattern {
494
public AnyWithAnnotationTypePattern(AnnotationTypePattern atp) {
496
annotationPattern = atp;
499
public Object accept(PatternNodeVisitor visitor, Object data) {
500
return visitor.visit(this, data);
503
protected boolean couldEverMatchSameTypesAs(TypePattern other) {
507
protected boolean matchesExactly(ResolvedType type) {
508
annotationPattern.resolve(type.getWorld());
510
if (type.temporaryAnnotationTypes != null) {
511
b = annotationPattern.matches(type, type.temporaryAnnotationTypes).alwaysTrue();
513
b = annotationPattern.matches(type).alwaysTrue();
518
protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
519
annotationPattern.resolve(type.getWorld());
520
return annotationPattern.matches(annotatedType).alwaysTrue();
523
public FuzzyBoolean matchesInstanceof(ResolvedType type) {
524
if (Modifier.isFinal(type.getModifiers())) {
525
return FuzzyBoolean.fromBoolean(matchesExactly(type));
527
return FuzzyBoolean.MAYBE;
530
public TypePattern parameterizeWith(Map typeVariableMap, World w) {
531
AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(this.annotationPattern.parameterizeWith(
532
typeVariableMap, w));
533
ret.copyLocationFrom(this);
537
public void write(DataOutputStream s) throws IOException {
538
s.writeByte(TypePattern.ANY_WITH_ANNO);
539
annotationPattern.write(s);
543
public static TypePattern read(VersionedDataInputStream s, ISourceContext c) throws IOException {
544
AnnotationTypePattern annPatt = AnnotationTypePattern.read(s, c);
545
AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annPatt);
546
ret.readLocation(c, s);
550
// public FuzzyBoolean matches(IType type, MatchKind kind) {
551
// return FuzzyBoolean.YES;
554
protected boolean matchesSubtypes(ResolvedType type) {
558
public boolean isStar() {
562
public String toString() {
563
return annotationPattern + " *";
566
public boolean equals(Object obj) {
567
if (!(obj instanceof AnyWithAnnotationTypePattern))
569
AnyWithAnnotationTypePattern awatp = (AnyWithAnnotationTypePattern) obj;
570
return (annotationPattern.equals(awatp.annotationPattern));
573
public int hashCode() {
574
return annotationPattern.hashCode();
578
class NoTypePattern extends TypePattern {
580
public NoTypePattern() {
581
super(false, false, new TypePatternList());
587
* @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
589
protected boolean couldEverMatchSameTypesAs(TypePattern other) {
594
* @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType)
596
protected boolean matchesExactly(ResolvedType type) {
600
protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
605
* @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType)
607
public FuzzyBoolean matchesInstanceof(ResolvedType type) {
608
return FuzzyBoolean.NO;
612
* @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream)
614
public void write(DataOutputStream s) throws IOException {
619
* @see org.aspectj.weaver.patterns.TypePattern#matches(IType, MatchKind)
621
// public FuzzyBoolean matches(IType type, MatchKind kind) {
622
// return FuzzyBoolean.YES;
625
* @see org.aspectj.weaver.patterns.TypePattern#matchesSubtypes(IType)
627
protected boolean matchesSubtypes(ResolvedType type) {
631
public boolean isStar() {
635
public String toString() {
637
}// FIXME AV - bad! toString() cannot be parsed back (not idempotent)
642
* @see java.lang.Object#equals(java.lang.Object)
644
public boolean equals(Object obj) {
645
return (obj instanceof NoTypePattern);
651
* @see java.lang.Object#hashCode()
653
public int hashCode() {
657
public Object accept(PatternNodeVisitor visitor, Object data) {
658
return visitor.visit(this, data);
661
public TypePattern parameterizeWith(Map arg0, World w) {