001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.search.matching;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.ast.*;
014: import org.eclipse.jdt.internal.compiler.lookup.*;
015: import org.eclipse.jdt.internal.compiler.parser.Parser;
016: import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
017:
018: /**
019: * A parser that locates ast nodes that match a given search pattern.
020: */
021: public class MatchLocatorParser extends Parser {
022:
023: MatchingNodeSet nodeSet;
024: PatternLocator patternLocator;
025: private ASTVisitor localDeclarationVisitor;
026:
027: public static MatchLocatorParser createParser(
028: ProblemReporter problemReporter, MatchLocator locator) {
029: if ((locator.matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0)
030: return new ImportMatchLocatorParser(problemReporter,
031: locator);
032: return new MatchLocatorParser(problemReporter, locator);
033: }
034:
035: /**
036: * An ast visitor that visits local type declarations.
037: */
038: public class NoClassNoMethodDeclarationVisitor extends ASTVisitor {
039: public boolean visit(
040: ConstructorDeclaration constructorDeclaration,
041: ClassScope scope) {
042: return (constructorDeclaration.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type
043: }
044:
045: public boolean visit(FieldDeclaration fieldDeclaration,
046: MethodScope scope) {
047: return (fieldDeclaration.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type;
048: }
049:
050: public boolean visit(Initializer initializer, MethodScope scope) {
051: return (initializer.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type
052: }
053:
054: public boolean visit(MethodDeclaration methodDeclaration,
055: ClassScope scope) {
056: return (methodDeclaration.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type
057: }
058: }
059:
060: public class MethodButNoClassDeclarationVisitor extends
061: NoClassNoMethodDeclarationVisitor {
062: public boolean visit(TypeDeclaration localTypeDeclaration,
063: BlockScope scope) {
064: patternLocator.match(localTypeDeclaration, nodeSet);
065: return true;
066: }
067: }
068:
069: public class ClassButNoMethodDeclarationVisitor extends ASTVisitor {
070: public boolean visit(
071: ConstructorDeclaration constructorDeclaration,
072: ClassScope scope) {
073: patternLocator.match(constructorDeclaration, nodeSet);
074: return (constructorDeclaration.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type
075: }
076:
077: public boolean visit(FieldDeclaration fieldDeclaration,
078: MethodScope scope) {
079: patternLocator.match(fieldDeclaration, nodeSet);
080: return (fieldDeclaration.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type;
081: }
082:
083: public boolean visit(Initializer initializer, MethodScope scope) {
084: patternLocator.match(initializer, nodeSet);
085: return (initializer.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type
086: }
087:
088: public boolean visit(TypeDeclaration memberTypeDeclaration,
089: ClassScope scope) {
090: patternLocator.match(memberTypeDeclaration, nodeSet);
091: return true;
092: }
093:
094: public boolean visit(MethodDeclaration methodDeclaration,
095: ClassScope scope) {
096: patternLocator.match(methodDeclaration, nodeSet);
097: return (methodDeclaration.bits & ASTNode.HasLocalType) != 0; // continue only if it has local type
098: }
099:
100: public boolean visit(
101: AnnotationMethodDeclaration methodDeclaration,
102: ClassScope scope) {
103: patternLocator.match(methodDeclaration, nodeSet);
104: return false; // no local type for annotation type members
105: }
106: }
107:
108: public class ClassAndMethodDeclarationVisitor extends
109: ClassButNoMethodDeclarationVisitor {
110: public boolean visit(TypeDeclaration localTypeDeclaration,
111: BlockScope scope) {
112: patternLocator.match(localTypeDeclaration, nodeSet);
113: return true;
114: }
115: }
116:
117: protected MatchLocatorParser(ProblemReporter problemReporter,
118: MatchLocator locator) {
119: super (problemReporter, true);
120: this .reportOnlyOneSyntaxError = true;
121: this .patternLocator = locator.patternLocator;
122: if ((locator.matchContainer & PatternLocator.CLASS_CONTAINER) != 0) {
123: this .localDeclarationVisitor = (locator.matchContainer & PatternLocator.METHOD_CONTAINER) != 0 ? new ClassAndMethodDeclarationVisitor()
124: : new ClassButNoMethodDeclarationVisitor();
125: } else {
126: this .localDeclarationVisitor = (locator.matchContainer & PatternLocator.METHOD_CONTAINER) != 0 ? new MethodButNoClassDeclarationVisitor()
127: : new NoClassNoMethodDeclarationVisitor();
128: }
129: }
130:
131: public void checkComment() {
132: super .checkComment();
133: if (this .javadocParser.checkDocComment && this .javadoc != null) {
134:
135: // Search for pattern locator matches in javadoc comment parameters @param tags
136: JavadocSingleNameReference[] paramReferences = this .javadoc.paramReferences;
137: if (paramReferences != null) {
138: for (int i = 0, length = paramReferences.length; i < length; i++) {
139: this .patternLocator.match(paramReferences[i],
140: this .nodeSet);
141: }
142: }
143:
144: // Search for pattern locator matches in javadoc comment type parameters @param tags
145: JavadocSingleTypeReference[] paramTypeParameters = this .javadoc.paramTypeParameters;
146: if (paramTypeParameters != null) {
147: for (int i = 0, length = paramTypeParameters.length; i < length; i++) {
148: this .patternLocator.match(paramTypeParameters[i],
149: this .nodeSet);
150: }
151: }
152:
153: // Search for pattern locator matches in javadoc comment @throws/@exception tags
154: TypeReference[] thrownExceptions = this .javadoc.exceptionReferences;
155: if (thrownExceptions != null) {
156: for (int i = 0, length = thrownExceptions.length; i < length; i++) {
157: this .patternLocator.match(thrownExceptions[i],
158: this .nodeSet);
159: }
160: }
161:
162: // Search for pattern locator matches in javadoc comment @see tags
163: Expression[] references = this .javadoc.seeReferences;
164: if (references != null) {
165: for (int i = 0, length = references.length; i < length; i++) {
166: Expression reference = references[i];
167: if (reference instanceof TypeReference) {
168: TypeReference typeRef = (TypeReference) reference;
169: this .patternLocator
170: .match(typeRef, this .nodeSet);
171: } else if (reference instanceof JavadocFieldReference) {
172: JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
173: this .patternLocator.match(fieldRef,
174: this .nodeSet);
175: if (fieldRef.receiver instanceof TypeReference
176: && !fieldRef.receiver.isThis()) {
177: TypeReference typeRef = (TypeReference) fieldRef.receiver;
178: this .patternLocator.match(typeRef,
179: this .nodeSet);
180: }
181: } else if (reference instanceof JavadocMessageSend) {
182: JavadocMessageSend messageSend = (JavadocMessageSend) reference;
183: this .patternLocator.match(messageSend,
184: this .nodeSet);
185: if (messageSend.receiver instanceof TypeReference
186: && !messageSend.receiver.isThis()) {
187: TypeReference typeRef = (TypeReference) messageSend.receiver;
188: this .patternLocator.match(typeRef,
189: this .nodeSet);
190: }
191: if (messageSend.arguments != null) {
192: for (int a = 0, al = messageSend.arguments.length; a < al; a++) {
193: JavadocArgumentExpression argument = (JavadocArgumentExpression) messageSend.arguments[a];
194: if (argument.argument != null
195: && argument.argument.type != null) {
196: this .patternLocator.match(
197: argument.argument.type,
198: this .nodeSet);
199: }
200: }
201: }
202: } else if (reference instanceof JavadocAllocationExpression) {
203: JavadocAllocationExpression constructor = (JavadocAllocationExpression) reference;
204: this .patternLocator.match(constructor,
205: this .nodeSet);
206: if (constructor.type != null
207: && !constructor.type.isThis()) {
208: this .patternLocator.match(constructor.type,
209: this .nodeSet);
210: }
211: if (constructor.arguments != null) {
212: for (int a = 0, al = constructor.arguments.length; a < al; a++) {
213: this .patternLocator.match(
214: constructor.arguments[a],
215: this .nodeSet);
216: JavadocArgumentExpression argument = (JavadocArgumentExpression) constructor.arguments[a];
217: if (argument.argument != null
218: && argument.argument.type != null) {
219: this .patternLocator.match(
220: argument.argument.type,
221: this .nodeSet);
222: }
223: }
224: }
225: }
226: }
227: }
228: }
229: }
230:
231: protected void classInstanceCreation(boolean alwaysQualified) {
232: super .classInstanceCreation(alwaysQualified);
233: this .patternLocator.match(
234: this .expressionStack[this .expressionPtr], this .nodeSet);
235: }
236:
237: protected void consumeAssignment() {
238: super .consumeAssignment();
239: this .patternLocator.match(
240: this .expressionStack[this .expressionPtr], this .nodeSet);
241: }
242:
243: protected void consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() {
244: super .consumeClassInstanceCreationExpressionWithTypeArguments();
245: this .patternLocator.match(
246: this .expressionStack[this .expressionPtr], this .nodeSet);
247: }
248:
249: protected void consumeClassInstanceCreationExpressionWithTypeArguments() {
250: super .consumeClassInstanceCreationExpressionWithTypeArguments();
251: this .patternLocator.match(
252: this .expressionStack[this .expressionPtr], this .nodeSet);
253: }
254:
255: protected void consumeExplicitConstructorInvocation(int flag,
256: int recFlag) {
257: super .consumeExplicitConstructorInvocation(flag, recFlag);
258: this .patternLocator.match(this .astStack[this .astPtr],
259: this .nodeSet);
260: }
261:
262: protected void consumeExplicitConstructorInvocationWithTypeArguments(
263: int flag, int recFlag) {
264: super .consumeExplicitConstructorInvocationWithTypeArguments(
265: flag, recFlag);
266: this .patternLocator.match(this .astStack[this .astPtr],
267: this .nodeSet);
268: }
269:
270: protected void consumeFieldAccess(boolean isSuperAccess) {
271: super .consumeFieldAccess(isSuperAccess);
272:
273: // this is always a Reference
274: this .patternLocator.match(
275: (Reference) this .expressionStack[this .expressionPtr],
276: this .nodeSet);
277: }
278:
279: protected void consumeFormalParameter(boolean isVarArgs) {
280: super .consumeFormalParameter(isVarArgs);
281:
282: // this is always a LocalDeclaration
283: this .patternLocator.match(
284: (LocalDeclaration) this .astStack[this .astPtr],
285: this .nodeSet);
286: }
287:
288: protected void consumeLocalVariableDeclaration() {
289: super .consumeLocalVariableDeclaration();
290:
291: // this is always a LocalDeclaration
292: this .patternLocator.match(
293: (LocalDeclaration) this .astStack[this .astPtr],
294: this .nodeSet);
295: }
296:
297: protected void consumeMarkerAnnotation() {
298: super .consumeMarkerAnnotation();
299: // this is always an Annotation
300: Annotation annotation = (Annotation) expressionStack[expressionPtr];
301: this .patternLocator.match(annotation, nodeSet);
302: }
303:
304: protected void consumeMemberValuePair() {
305: super .consumeMemberValuePair();
306:
307: // this is always a MemberValuePair
308: this .patternLocator.match(
309: (MemberValuePair) this .astStack[this .astPtr],
310: this .nodeSet);
311: }
312:
313: protected void consumeMethodInvocationName() {
314: super .consumeMethodInvocationName();
315:
316: // this is always a MessageSend
317: this .patternLocator.match(
318: (MessageSend) this .expressionStack[this .expressionPtr],
319: this .nodeSet);
320: }
321:
322: protected void consumeMethodInvocationNameWithTypeArguments() {
323: super .consumeMethodInvocationNameWithTypeArguments();
324:
325: // this is always a MessageSend
326: this .patternLocator.match(
327: (MessageSend) this .expressionStack[this .expressionPtr],
328: this .nodeSet);
329: }
330:
331: protected void consumeMethodInvocationPrimary() {
332: super .consumeMethodInvocationPrimary();
333:
334: // this is always a MessageSend
335: this .patternLocator.match(
336: (MessageSend) this .expressionStack[this .expressionPtr],
337: this .nodeSet);
338: }
339:
340: protected void consumeMethodInvocationPrimaryWithTypeArguments() {
341: super .consumeMethodInvocationPrimaryWithTypeArguments();
342:
343: // this is always a MessageSend
344: this .patternLocator.match(
345: (MessageSend) this .expressionStack[this .expressionPtr],
346: this .nodeSet);
347: }
348:
349: protected void consumeMethodInvocationSuper() {
350: super .consumeMethodInvocationSuper();
351:
352: // this is always a MessageSend
353: this .patternLocator.match(
354: (MessageSend) this .expressionStack[this .expressionPtr],
355: this .nodeSet);
356: }
357:
358: protected void consumeMethodInvocationSuperWithTypeArguments() {
359: super .consumeMethodInvocationSuperWithTypeArguments();
360:
361: // this is always a MessageSend
362: this .patternLocator.match(
363: (MessageSend) this .expressionStack[this .expressionPtr],
364: this .nodeSet);
365: }
366:
367: protected void consumeNormalAnnotation() {
368: super .consumeNormalAnnotation();
369: // this is always an Annotation
370: Annotation annotation = (Annotation) expressionStack[expressionPtr];
371: this .patternLocator.match(annotation, nodeSet);
372: }
373:
374: protected void consumePrimaryNoNewArray() {
375: // pop parenthesis positions (and don't update expression positions
376: // (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=23329)
377: intPtr--;
378: intPtr--;
379: }
380:
381: protected void consumePrimaryNoNewArrayWithName() {
382: // PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN
383: pushOnExpressionStack(getUnspecifiedReferenceOptimized());
384: // pop parenthesis positions (and don't update expression positions
385: // (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=23329)
386: intPtr--;
387: intPtr--;
388: }
389:
390: protected void consumeSingleMemberAnnotation() {
391: super .consumeSingleMemberAnnotation();
392: // this is always an Annotation
393: Annotation annotation = (Annotation) expressionStack[expressionPtr];
394: this .patternLocator.match(annotation, nodeSet);
395: }
396:
397: protected void consumeTypeArgument() {
398: super .consumeTypeArgument();
399: patternLocator.match(
400: (TypeReference) genericsStack[genericsPtr], nodeSet);
401: }
402:
403: protected void consumeTypeParameterHeader() {
404: super .consumeTypeParameterHeader();
405: patternLocator.match(
406: (TypeParameter) genericsStack[genericsPtr], nodeSet);
407: }
408:
409: protected void consumeUnaryExpression(int op, boolean post) {
410: super .consumeUnaryExpression(op, post);
411: this .patternLocator.match(
412: this .expressionStack[this .expressionPtr], this .nodeSet);
413: }
414:
415: protected TypeReference copyDims(TypeReference typeRef, int dim) {
416: TypeReference result = super .copyDims(typeRef, dim);
417: if (this .nodeSet.removePossibleMatch(typeRef) != null)
418: this .nodeSet.addPossibleMatch(result);
419: else if (this .nodeSet.removeTrustedMatch(typeRef) != null)
420: this .nodeSet.addTrustedMatch(result, true);
421: return result;
422: }
423:
424: protected TypeReference getTypeReference(int dim) {
425: TypeReference typeRef = super .getTypeReference(dim);
426: this .patternLocator.match(typeRef, this .nodeSet); // NB: Don't check container since type reference can happen anywhere
427: return typeRef;
428: }
429:
430: protected NameReference getUnspecifiedReference() {
431: NameReference nameRef = super .getUnspecifiedReference();
432: this .patternLocator.match(nameRef, this .nodeSet); // NB: Don't check container since unspecified reference can happen anywhere
433: return nameRef;
434: }
435:
436: protected NameReference getUnspecifiedReferenceOptimized() {
437: NameReference nameRef = super
438: .getUnspecifiedReferenceOptimized();
439: this .patternLocator.match(nameRef, this .nodeSet); // NB: Don't check container since unspecified reference can happen anywhere
440: return nameRef;
441: }
442:
443: /**
444: * Parses the method bodies in the given compilation unit
445: * @param unit CompilationUnitDeclaration
446: */
447: public void parseBodies(CompilationUnitDeclaration unit) {
448: TypeDeclaration[] types = unit.types;
449: if (types == null)
450: return;
451:
452: for (int i = 0; i < types.length; i++) {
453: TypeDeclaration type = types[i];
454: this .patternLocator.match(type, this .nodeSet);
455: this .parseBodies(type, unit);
456: }
457: }
458:
459: /**
460: * Parses the member bodies in the given type.
461: * @param type TypeDeclaration
462: * @param unit CompilationUnitDeclaration
463: */
464: protected void parseBodies(TypeDeclaration type,
465: CompilationUnitDeclaration unit) {
466: FieldDeclaration[] fields = type.fields;
467: if (fields != null) {
468: for (int i = 0; i < fields.length; i++) {
469: FieldDeclaration field = fields[i];
470: if (field instanceof Initializer)
471: this .parse((Initializer) field, type, unit);
472: field.traverse(localDeclarationVisitor, null);
473: }
474: }
475:
476: AbstractMethodDeclaration[] methods = type.methods;
477: if (methods != null) {
478: for (int i = 0; i < methods.length; i++) {
479: AbstractMethodDeclaration method = methods[i];
480: if (method.sourceStart >= type.bodyStart) { // if not synthetic
481: if (method instanceof MethodDeclaration) {
482: MethodDeclaration methodDeclaration = (MethodDeclaration) method;
483: this .parse(methodDeclaration, unit);
484: methodDeclaration.traverse(
485: localDeclarationVisitor,
486: (ClassScope) null);
487: } else if (method instanceof ConstructorDeclaration) {
488: ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) method;
489: this .parse(constructorDeclaration, unit);
490: constructorDeclaration.traverse(
491: localDeclarationVisitor,
492: (ClassScope) null);
493: }
494: } else if (method.isDefaultConstructor()) {
495: method.parseStatements(this , unit);
496: }
497: }
498: }
499:
500: TypeDeclaration[] memberTypes = type.memberTypes;
501: if (memberTypes != null) {
502: for (int i = 0; i < memberTypes.length; i++) {
503: TypeDeclaration memberType = memberTypes[i];
504: this .parseBodies(memberType, unit);
505: memberType.traverse(localDeclarationVisitor,
506: (ClassScope) null);
507: }
508: }
509: }
510: }
|