KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > crosscuts > ast > PatternTypeName


1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the compiler and core tools for the AspectJ(tm)
4  * programming language; see http://aspectj.org
5  *
6  * The contents of this file are subject to the Mozilla Public License
7  * Version 1.1 (the "License"); you may not use this file except in
8  * compliance with the License. You may obtain a copy of the License at
9  * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is AspectJ.
17  *
18  * The Initial Developer of the Original Code is Xerox Corporation. Portions
19  * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
20  * All Rights Reserved.
21  *
22  * Contributor(s):
23  */

24
25 package org.aspectj.compiler.crosscuts.ast;
26 import org.aspectj.compiler.base.ast.*;
27 import org.aspectj.compiler.base.cst.*;
28 import org.aspectj.compiler.crosscuts.joinpoints.*;
29
30 import org.aspectj.compiler.base.*;
31 import org.aspectj.util.*;
32
33 import org.aspectj.compiler.base.TypeManager;
34 import java.util.*;
35
36 /**
37  * @grammar typename
38  * @property NamePatterns names
39  * @property boolean includeSubTypes
40  * @property int dimensions
41  */

42
43 public class PatternTypeName extends GenTypeName {
44     /**
45      * These maps cache the result of matching with different types. This is an
46      * extremely important performance optimization. Removing this optimization
47      * can easily increase compile times by 20X.
48      */

49     Map matchCache = new HashMap();
50     Map instanceMatchCache = new HashMap();
51
52     public String JavaDoc toShortString() {
53         String JavaDoc ret = names.toShortString();
54         if (includeSubTypes)
55             ret += "+";
56         return ret;
57     }
58
59     private Formals getEnclosingFormals(ASTObject node) {
60         if (node == null)
61             return null;
62         if (node instanceof Formals)
63             return (Formals) node;
64         if (node instanceof AdviceDec)
65             return ((AdviceDec) node).getFormals();
66         if (node instanceof PointcutDec)
67             return ((PointcutDec) node).getFormals();
68         return getEnclosingFormals(node.getParent());
69     }
70
71     private FormalDec getEnclosingAfterFormal(ASTObject node) {
72         if (node == null)
73             return null;
74         if (node instanceof AdviceDec)
75             return ((AdviceDec) node).getExtraFormal();
76         return getEnclosingAfterFormal(node.getParent());
77     }
78
79     private Pcd getEnclosingPcd(ASTObject node) {
80         if (node == null)
81             return null;
82         if (node instanceof Pcd)
83             return (Pcd) node;
84         return getEnclosingPcd(node.getParent());
85     }
86
87     private Scope savedScope;
88
89     //INTRO from ScopeWalker
90

91     /* Specializing on three cases:
92        . STAR
93        . A single name that is a varref of a pointcut formal
94        . A single name that will be matched to a type
95        . otherwise, it's a starred pattern
96     
97        The specialization is used for:
98        . lint checking now
99        . performance optimization of matching later in the compiler
100      */

101     public ASTObject postScope(ScopeWalker walker) {
102         //System.out.println(this + ", " + walker.getScope());
103
if (savedScope != null)
104             return this;
105
106         savedScope = walker.getScope();
107
108         // if we have nothing but one star
109
if (names.size() == 1 && names.get(0).isStar() && dimensions == 0) {
110             return new AnyTypeName(getSourceLocation()).setSource(this);
111         }
112
113         // if we're a formal
114
if (names.size() == 1 && dimensions == 0) {
115             Formals formals = getEnclosingFormals(this);
116             String JavaDoc id = names.get(0).getSimpleName();
117             if (formals != null) {
118                 FormalDec formalDec = formals.findName(id);
119                 if (formalDec != null) {
120                     return makeVarTypeName(formalDec);
121                 } else {
122                     FormalDec afterFormal = getEnclosingAfterFormal(this);
123                     if (afterFormal != null && afterFormal.getId().equals(id)) {
124                         getCompiler().showError(
125                             this,
126                             "can't refer to '" + afterFormal.toShortString() + "' from this context");
127                         return makeSimpleTypeName(getTypeManager().TYPE_NOT_FOUND);
128                     }
129                 }
130             }
131         }
132
133         // if we're a primitive type name
134
if (names.size() == 1) {
135             String JavaDoc id = names.get(0).getSimpleName();
136             if (id != null) {
137                 Type primType = getTypeManager().findPrimitiveType(id);
138                 if (primType != null) {
139                     return makeSimpleTypeName(primType);
140                 }
141             }
142         }
143
144         return this;
145     }
146
147     private SimpleTypeName makeSimpleTypeName(Type t) {
148         for (int i = 0; i < dimensions; i++) {
149             t = t.getArrayType();
150         }
151         return new SimpleTypeName(getSourceLocation(), t, includeSubTypes);
152     }
153
154     /** returns true if any visible type name matches this pattern.
155      *
156      * Note that this doesn't care about subtyping, since we only care about existence.
157      *
158      * @see TypeManager#getAllVisibleTypeNames()
159      */

160     private boolean anyTypeMatches() {
161         // as a performance improvement, first check loaded types
162
for (Iterator i = getTypeManager().getLoadedTypes().iterator(); i.hasNext();) {
163             Type t = (Type) i.next();
164             if (this.matches(t.getNamePieces()))
165                 return true;
166         }
167
168         //System.out.println(this.toShortString() + " not in loaded");
169

170         for (Iterator i = getTypeManager().getAllVisibleTypeNames().iterator();
171             i.hasNext();
172             ) {
173             List pieces = (List) i.next();
174             if (this.matches(pieces))
175                 return true;
176         }
177         return false;
178     }
179
180     /*
181      *
182      * @see ASTObject#checkSpec()
183      */

184     public void checkSpec() {
185         Name cstName = names.makeName();
186
187         // first check for non-wildcarded names
188
if (cstName != null) {
189             //XXX we need the parent to be set so that accessibility checks in scopes
190
//XXX will treat the name as in my lexical scope
191
//XXX this breaks an important invariant that parents
192
//XXX take responsibility for their children
193
cstName.setParent(this);
194
195             Type t = cstName.resolveType(savedScope, false);
196             if (t.isMissing()) {
197                 getCompiler().showWarning(this, ErrorHandler.invalidAbsoluteTypeName);
198                 super.checkSpec();
199                 return;
200             }
201             SimpleTypeName s = makeSimpleTypeName(t);
202             this.replaceWith(s);
203             s.checkSpec();
204             return;
205         } else {
206             // check for wildcarded names matching anything
207
if (ErrorHandler.invalidWildcardTypeName.shouldDisplay(getCompiler())) {
208                 if (!anyTypeMatches()) {
209                     getCompiler().showWarning(this, ErrorHandler.invalidWildcardTypeName);
210                 }
211             }
212         }
213         super.checkSpec();
214     }
215
216     protected GenTypeName makeVarTypeName(FormalDec formalDec) {
217         formalDec.isBound = true;
218
219         if (includeSubTypes || getParent() instanceof GenTypeName) {
220             showError("formal binding can not be done as part of a GTN");
221             return this;
222         }
223
224         if (!getEnclosingPcd(this).allowsNameBinding()) {
225             showError("name binding is only allowed in target, this, and args PCDs");
226             return this;
227         }
228         return new VarTypeName(getSourceLocation(), formalDec);
229     }
230
231     public ASTObject postCopy(CopyWalker walker, ASTObject oldObject) {
232         savedScope = ((PatternTypeName) oldObject).savedScope;
233         return this;
234     }
235
236     public FuzzyBoolean matchesInstance(Type type) {
237         FuzzyBoolean ret = (FuzzyBoolean) instanceMatchCache.get(type);
238
239         if (ret != null)
240             return ret;
241
242         Set tests = new HashSet();
243         boolean isMatch = matches(null, type, false, tests);
244         if (!isMatch) {
245             ret = FuzzyBoolean.NO;
246         } else if (tests.size() == 0) {
247             ret = FuzzyBoolean.YES;
248         } else {
249             ret = FuzzyBoolean.MAYBE;
250         }
251
252         instanceMatchCache.put(type, ret);
253         
254         //System.out.println(type + " instance match " + ret);
255
return ret;
256     }
257
258     void addInstanceTests(Set instanceTests, Expr expr, JpPlan plan) {
259         if (instanceTests.size() == 0)
260             return;
261
262         instanceTests = Type.filterTopTypes(instanceTests);
263
264         Expr testExpr = null;
265         final AST ast = getAST();
266         for (Iterator i = instanceTests.iterator(); i.hasNext();) {
267             Type matchingType = (Type) i.next();
268             if (expr.getType().isSubtypeOf(matchingType))
269                 continue;
270             Expr instanceTest = ast.makeParen(ast.makeInstanceof(expr, matchingType));
271             if (testExpr == null)
272                 testExpr = instanceTest;
273             else
274                 testExpr = ast.makeBinop("||", testExpr, instanceTest);
275         }
276         if (testExpr != null)
277             plan.addExprTest(testExpr);
278     }
279
280     public JpPlan makePlan(JoinPoint jp, Expr expr) {
281         //System.out.println(">>>makePlan " + this);
282
//XXX bad structure
283
JpPlan plan = new JpPlan(jp);
284         // System.out.println(">>>>" + expr.getType());
285
if (expr.getType() == null) {
286             //System.out.println("bad expr: " + expr.unparse());
287
return JpPlan.NO_PLAN;
288         }
289         Set instanceTests = new HashSet();
290         if (matches(plan, expr.getType(), false, instanceTests)) {
291             //System.out.println(this + " matches " + expr.getType() + " tests " + instanceTests);
292
addInstanceTests(instanceTests, expr, plan);
293             return plan;
294         } else {
295             //System.out.println(" NO match " + instanceTests);
296
return JpPlan.NO_PLAN;
297         }
298     }
299
300     /**
301      * asType -- the type to match
302      * needsTest -- insert a test even if we DEFINATELY match
303      * always passed in false at the top
304      * instanceofTests -- an accumulator
305      */

306     boolean matches(
307         JpPlan plan,
308         Type asType,
309         boolean needsTest,
310         Set instanceofTests)
311    {
312         Type matchingType = matches(asType, true);
313         //System.out.println(asType + ", " + matchingType);
314
if (matchingType != null) {
315             if (needsTest) {
316                 instanceofTests.add(matchingType);
317             }
318             // bind???
319
return true;
320         }
321
322         // otherwise we need to walk all subtypes ;-(
323
boolean couldMatch = false;
324         Collection subTypes = asType.getDirectSubTypes();
325         //System.out.println(subTypes);
326

327         if (subTypes == null)
328             return false;
329
330         for (Iterator i = subTypes.iterator(); i.hasNext();) {
331             if (matches(plan, (Type) i.next(), true, instanceofTests))
332                 couldMatch = true;
333         }
334
335         return couldMatch;
336     }
337
338     public boolean matches(Type type) {
339         return matches(type, includeSubTypes) != null;
340     }
341
342     public Type matches(Type type, boolean includeSubTypes) {
343         //System.out.println("matches? " + type + ", " + names.toShortString());
344
if (basicMatch(type))
345             return type;
346
347         if (includeSubTypes) {
348             //System.out.println(type + " supers: " + type.getDirectSuperTypes());
349
for (Iterator i = type.getDirectSuperTypes().iterator(); i.hasNext();) {
350                 Type tryType = (Type) i.next();
351                 Type matchType = matches(tryType, includeSubTypes);
352                 if (matchType != null)
353                     return matchType;
354             }
355         }
356         //System.out.println(" false");
357
return null;
358     }
359
360     protected boolean basicMatch(Type type) {
361         Boolean JavaDoc cachedResult = (Boolean JavaDoc) matchCache.get(type);
362         if (cachedResult != null)
363             return cachedResult.booleanValue();
364
365         boolean ret = innerBasicMatch(type);
366         matchCache.put(type, ret ? Boolean.TRUE : Boolean.FALSE);
367         return ret;
368     }
369
370     private boolean innerBasicMatch(Type type) {
371         // first check that dimensions match
372
//System.out.println(dimensions, type.getArrayDimCount());
373
if (dimensions != type.getArrayDimCount()) {
374             if (dimensions == 0)
375                 type = getTypeManager().getObjectType();
376             else
377                 return false;
378         }
379
380         // by doing this match backwards we finesse some efficiency issues
381
List pieces = type.getBaseComponentType().getNamePieces();
382         //System.out.println(pieces);
383
if (!matches(pieces)) {
384             return false;
385         }
386         return true;
387     }
388
389     private boolean isEllipses(NamePattern name) {
390         return name instanceof EllipsesFakeNamePattern;
391     }
392
393     protected boolean matches(List pieces) {
394         return matches(pieces, pieces.size() - 1, names.size() - 1);
395     }
396
397     protected boolean matches(
398         List pieces,
399         int pieceIndex,
400         int nameIndex) {
401         if (nameIndex < 0) {
402             // we need to see if the last name matched is at the top level or not
403
pieceIndex += 1;
404             // we've matched to the "real" top level
405
if (pieceIndex == 0)
406                 return true;
407
408             // otherwise let's see if this is a legal unqualified name
409
// and that it binds to the correct type based on lexical scope
410
if (savedScope == null) {
411                 showError("no saved scope");
412             }
413
414             Type importType = savedScope.findType((String JavaDoc) pieces.get(pieceIndex), this);
415             if (importType == null) return false;
416             
417             List importPieces = importType.getNamePieces();
418             return importPieces.equals(pieces.subList(0, pieceIndex+1));
419         }
420
421         if (pieceIndex < 0)
422             return false;
423
424         NamePattern name = names.get(nameIndex);
425         if (isEllipses(name)) {
426             for (; pieceIndex >= 0; pieceIndex--) {
427                 // no need for ambiguity handling since we don't do binding
428
if (matches(pieces, pieceIndex, nameIndex - 1))
429                     return true;
430             }
431             return false;
432         } else {
433             if (name.matches((String JavaDoc) pieces.get(pieceIndex))) {
434                 return matches(pieces, pieceIndex - 1, nameIndex - 1);
435             } else {
436                 return false;
437             }
438         }
439     }
440
441     //BEGIN: Generated from @child and @property
442
protected NamePatterns names;
443     public NamePatterns getNames() {
444         return names;
445     }
446     public void setNames(NamePatterns _names) {
447         names = _names;
448     }
449
450     protected boolean includeSubTypes;
451     public boolean getIncludeSubTypes() {
452         return includeSubTypes;
453     }
454     public void setIncludeSubTypes(boolean _includeSubTypes) {
455         includeSubTypes = _includeSubTypes;
456     }
457
458     protected int dimensions;
459     public int getDimensions() {
460         return dimensions;
461     }
462     public void setDimensions(int _dimensions) {
463         dimensions = _dimensions;
464     }
465
466     public PatternTypeName(
467         SourceLocation location,
468         NamePatterns _names,
469         boolean _includeSubTypes,
470         int _dimensions) {
471         super(location);
472         setNames(_names);
473         setIncludeSubTypes(_includeSubTypes);
474         setDimensions(_dimensions);
475     }
476     protected PatternTypeName(SourceLocation source) {
477         super(source);
478     }
479
480     public ASTObject copyWalk(CopyWalker walker) {
481         PatternTypeName ret = new PatternTypeName(getSourceLocation());
482         ret.preCopy(walker, this);
483         ret.names = names;
484         ret.includeSubTypes = includeSubTypes;
485         ret.dimensions = dimensions;
486         return ret;
487     }
488
489     public String JavaDoc getDefaultDisplayName() {
490         return "PatternTypeName(names: "
491             + names
492             + ", "
493             + "includeSubTypes: "
494             + includeSubTypes
495             + ", "
496             + "dimensions: "
497             + dimensions
498             + ")";
499     }
500
501     //END: Generated from @child and @property
502

503 }
Popular Tags