blob: b0d0635a0fb8b6052fdbdbd2d829ab9a8ac1703e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* 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://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
/**
* A parser that locates ast nodes that match a given search pattern.
*/
public class MatchLocatorParser extends Parser {
MatchingNodeSet nodeSet;
PatternLocator patternLocator;
private ASTVisitor localDeclarationVisitor;
public static MatchLocatorParser createParser(ProblemReporter problemReporter, MatchLocator locator) {
if ((locator.matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0)
return new ImportMatchLocatorParser(problemReporter, locator);
return new MatchLocatorParser(problemReporter, locator);
}
/**
* An ast visitor that visits local type declarations.
*/
public class NoClassNoMethodDeclarationVisitor extends ASTVisitor {
public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
return (constructorDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
}
public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
return (fieldDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type;
}
public boolean visit(Initializer initializer, MethodScope scope) {
return (initializer.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
}
public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
return (methodDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
}
}
public class MethodButNoClassDeclarationVisitor extends NoClassNoMethodDeclarationVisitor {
public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
patternLocator.match(localTypeDeclaration, nodeSet);
return true;
}
}
public class ClassButNoMethodDeclarationVisitor extends ASTVisitor {
public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
patternLocator.match(constructorDeclaration, nodeSet);
return (constructorDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
}
public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
patternLocator.match(fieldDeclaration, nodeSet);
return (fieldDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type;
}
public boolean visit(Initializer initializer, MethodScope scope) {
patternLocator.match(initializer, nodeSet);
return (initializer.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
}
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
patternLocator.match(memberTypeDeclaration, nodeSet);
return true;
}
public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
patternLocator.match(methodDeclaration, nodeSet);
return (methodDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
}
}
public class ClassAndMethodDeclarationVisitor extends ClassButNoMethodDeclarationVisitor {
public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
patternLocator.match(localTypeDeclaration, nodeSet);
return true;
}
}
protected MatchLocatorParser(ProblemReporter problemReporter, MatchLocator locator) {
super(problemReporter, true);
this.reportOnlyOneSyntaxError = true;
this.patternLocator = locator.patternLocator;
if ((locator.matchContainer & PatternLocator.CLASS_CONTAINER) != 0) {
this.localDeclarationVisitor = (locator.matchContainer & PatternLocator.METHOD_CONTAINER) != 0
? new ClassAndMethodDeclarationVisitor()
: new ClassButNoMethodDeclarationVisitor();
} else {
this.localDeclarationVisitor = (locator.matchContainer & PatternLocator.METHOD_CONTAINER) != 0
? new MethodButNoClassDeclarationVisitor()
: new NoClassNoMethodDeclarationVisitor();
}
}
public void checkComment() {
super.checkComment();
if (this.javadocParser.checkDocComment && this.javadoc != null) {
// Search for pattern locator matches in javadoc comment parameters @param tags
JavadocSingleNameReference[] paramReferences = this.javadoc.paramReferences;
int length = paramReferences == null ? 0 : paramReferences.length;
for (int i = 0; i < length; i++) {
this.patternLocator.match(paramReferences[i], this.nodeSet);
}
// Search for pattern locator matches in javadoc comment type parameters @param tags
JavadocSingleTypeReference[] paramTypeParameters = this.javadoc.paramTypeParameters;
length = paramTypeParameters == null ? 0 : paramTypeParameters.length;
for (int i = 0; i < length; i++) {
this.patternLocator.match(paramTypeParameters[i], this.nodeSet);
}
// Search for pattern locator matches in javadoc comment @throws/@exception tags
TypeReference[] thrownExceptions = this.javadoc.exceptionReferences;
length = thrownExceptions == null ? 0 : thrownExceptions.length;
for (int i = 0; i < length; i++) {
this.patternLocator.match(thrownExceptions[i], this.nodeSet);
}
// Search for pattern locator matches in javadoc comment @see tags
Expression[] references = this.javadoc.seeReferences;
length = references == null ? 0 : references.length;
for (int i = 0; i < length; i++) {
Expression reference = references[i];
if (reference instanceof TypeReference) {
TypeReference typeRef = (TypeReference) reference;
this.patternLocator.match(typeRef, this.nodeSet);
} else if (reference instanceof JavadocFieldReference) {
JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
this.patternLocator.match(fieldRef, this.nodeSet);
if (fieldRef.receiver instanceof TypeReference && !fieldRef.receiver.isThis()) {
TypeReference typeRef = (TypeReference) fieldRef.receiver;
this.patternLocator.match(typeRef, this.nodeSet);
}
} else if (reference instanceof JavadocMessageSend) {
JavadocMessageSend messageSend = (JavadocMessageSend) reference;
this.patternLocator.match(messageSend, this.nodeSet);
if (messageSend.receiver instanceof TypeReference && !messageSend.receiver.isThis()) {
TypeReference typeRef = (TypeReference) messageSend.receiver;
this.patternLocator.match(typeRef, this.nodeSet);
}
if (messageSend.arguments != null) {
for (int a=0,al=messageSend.arguments.length; a<al; a++) {
JavadocArgumentExpression argument = (JavadocArgumentExpression) messageSend.arguments[a];
if (argument.argument != null && argument.argument.type != null) {
this.patternLocator.match(argument.argument.type, this.nodeSet);
}
}
}
} else if (reference instanceof JavadocAllocationExpression) {
JavadocAllocationExpression constructor = (JavadocAllocationExpression) reference;
this.patternLocator.match(constructor, this.nodeSet);
if (constructor.type != null && !constructor.type.isThis()) {
this.patternLocator.match(constructor.type, this.nodeSet);
}
if (constructor.arguments != null) {
for (int a=0,al=constructor.arguments.length; a<al; a++) {
this.patternLocator.match(constructor.arguments[a], this.nodeSet);
JavadocArgumentExpression argument = (JavadocArgumentExpression) constructor.arguments[a];
if (argument.argument != null && argument.argument.type != null) {
this.patternLocator.match(argument.argument.type, this.nodeSet);
}
}
}
}
}
}
}
protected void classInstanceCreation(boolean alwaysQualified) {
super.classInstanceCreation(alwaysQualified);
this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeAnnotationAsModifier() {
super.consumeAnnotationAsModifier();
Expression expression = this.expressionStack[this.expressionPtr];
if (expression instanceof Annotation) {
this.patternLocator.match(((Annotation)expression).type, this.nodeSet);
}
}
protected void consumeAssignment() {
super.consumeAssignment();
this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() {
super.consumeClassInstanceCreationExpressionWithTypeArguments();
this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeClassInstanceCreationExpressionWithTypeArguments() {
super.consumeClassInstanceCreationExpressionWithTypeArguments();
this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
super.consumeExplicitConstructorInvocation(flag, recFlag);
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
protected void consumeExplicitConstructorInvocationWithTypeArguments(int flag, int recFlag) {
super.consumeExplicitConstructorInvocationWithTypeArguments(flag, recFlag);
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
protected void consumeFieldAccess(boolean isSuperAccess) {
super.consumeFieldAccess(isSuperAccess);
// this is always a Reference
this.patternLocator.match((Reference) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeInternalCompilationUnit() {
// InternalCompilationUnit ::= PackageDeclaration
// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports
// InternalCompilationUnit ::= ImportDeclarations ReduceImports
}
protected void consumeInternalCompilationUnitWithTypes() {
// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports TypeDeclarations
// InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
// InternalCompilationUnit ::= TypeDeclarations
// InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
// consume type declarations
int length;
if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
this.compilationUnit.types = new TypeDeclaration[length];
this.astPtr -= length;
System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types, 0, length);
}
}
protected void consumeLocalVariableDeclaration() {
super.consumeLocalVariableDeclaration();
// this is always a LocalDeclaration
this.patternLocator.match((LocalDeclaration) this.astStack[this.astPtr], this.nodeSet);
}
protected void consumeMethodInvocationName() {
super.consumeMethodInvocationName();
// this is always a MessageSend
this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeMethodInvocationNameWithTypeArguments() {
super.consumeMethodInvocationNameWithTypeArguments();
// this is always a MessageSend
this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeMethodInvocationPrimary() {
super.consumeMethodInvocationPrimary();
// this is always a MessageSend
this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeMethodInvocationPrimaryWithTypeArguments() {
super.consumeMethodInvocationPrimaryWithTypeArguments();
// this is always a MessageSend
this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeMethodInvocationSuper() {
super.consumeMethodInvocationSuper();
// this is always a MessageSend
this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumeMethodInvocationSuperWithTypeArguments() {
super.consumeMethodInvocationSuperWithTypeArguments();
// this is always a MessageSend
this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected void consumePrimaryNoNewArray() {
// pop parenthesis positions (and don't update expression positions
// (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=23329)
intPtr--;
intPtr--;
}
protected void consumePrimaryNoNewArrayWithName() {
// PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN
pushOnExpressionStack(getUnspecifiedReferenceOptimized());
// pop parenthesis positions (and don't update expression positions
// (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=23329)
intPtr--;
intPtr--;
}
protected void consumeTypeArgument() {
super.consumeTypeArgument();
patternLocator.match((TypeReference)genericsStack[genericsPtr], nodeSet);
}
protected void consumeTypeParameterHeader() {
super.consumeTypeParameterHeader();
patternLocator.match((TypeParameter)genericsStack[genericsPtr], nodeSet);
}
protected void consumeUnaryExpression(int op, boolean post) {
super.consumeUnaryExpression(op, post);
this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
}
protected TypeReference copyDims(TypeReference typeRef, int dim) {
TypeReference result = super.copyDims(typeRef, dim);
if (this.nodeSet.removePossibleMatch(typeRef) != null)
this.nodeSet.addPossibleMatch(result);
else if (this.nodeSet.removeTrustedMatch(typeRef) != null)
this.nodeSet.addTrustedMatch(result, true);
return result;
}
protected TypeReference getTypeReference(int dim) {
TypeReference typeRef = super.getTypeReference(dim);
this.patternLocator.match(typeRef, this.nodeSet); // NB: Don't check container since type reference can happen anywhere
return typeRef;
}
protected NameReference getUnspecifiedReference() {
NameReference nameRef = super.getUnspecifiedReference();
this.patternLocator.match(nameRef, this.nodeSet); // NB: Don't check container since unspecified reference can happen anywhere
return nameRef;
}
protected NameReference getUnspecifiedReferenceOptimized() {
NameReference nameRef = super.getUnspecifiedReferenceOptimized();
this.patternLocator.match(nameRef, this.nodeSet); // NB: Don't check container since unspecified reference can happen anywhere
return nameRef;
}
/**
* Parses the method bodies in the given compilation unit
* @param unit CompilationUnitDeclaration
*/
public void parseBodies(CompilationUnitDeclaration unit) {
TypeDeclaration[] types = unit.types;
if (types == null) return;
for (int i = 0; i < types.length; i++) {
TypeDeclaration type = types[i];
this.patternLocator.match(type, this.nodeSet);
this.parseBodies(type, unit);
}
}
/**
* Parses the member bodies in the given type.
* @param type TypeDeclaration
* @param unit CompilationUnitDeclaration
*/
protected void parseBodies(TypeDeclaration type, CompilationUnitDeclaration unit) {
FieldDeclaration[] fields = type.fields;
if (fields != null) {
for (int i = 0; i < fields.length; i++) {
FieldDeclaration field = fields[i];
if (field instanceof Initializer)
this.parse((Initializer) field, type, unit);
field.traverse(localDeclarationVisitor, null);
}
}
AbstractMethodDeclaration[] methods = type.methods;
if (methods != null) {
for (int i = 0; i < methods.length; i++) {
AbstractMethodDeclaration method = methods[i];
if (method.sourceStart >= type.bodyStart) { // if not synthetic
if (method instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration) method;
this.parse(methodDeclaration, unit);
methodDeclaration.traverse(localDeclarationVisitor, (ClassScope) null);
} else if (method instanceof ConstructorDeclaration) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) method;
this.parse(constructorDeclaration, unit);
constructorDeclaration.traverse(localDeclarationVisitor, (ClassScope) null);
}
} else if (method.isDefaultConstructor()) {
method.parseStatements(this, unit);
}
}
}
TypeDeclaration[] memberTypes = type.memberTypes;
if (memberTypes != null) {
for (int i = 0; i < memberTypes.length; i++) {
TypeDeclaration memberType = memberTypes[i];
this.parseBodies(memberType, unit);
memberType.traverse(localDeclarationVisitor, (ClassScope) null);
}
}
}
}
class ImportMatchLocatorParser extends MatchLocatorParser {
protected ImportMatchLocatorParser(ProblemReporter problemReporter, MatchLocator locator) {
super(problemReporter, locator);
}
protected void consumeStaticImportOnDemandDeclarationName() {
super.consumeStaticImportOnDemandDeclarationName();
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
protected void consumeSingleStaticImportDeclarationName() {
super.consumeSingleStaticImportDeclarationName();
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
protected void consumeSingleTypeImportDeclarationName() {
super.consumeSingleTypeImportDeclarationName();
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
protected void consumeTypeImportOnDemandDeclarationName() {
super.consumeTypeImportOnDemandDeclarationName();
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
}