blob: ca95c05992dc4d52546632472f41e49b488bf74b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2009 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.core.runtime.CoreException;
import org.eclipse.jdt.core.IAnnotatable;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
import org.eclipse.jdt.internal.core.search.matching.MatchLocator.WrappedCoreException;
/**
* Specific visitor of field or method declaration which can identify and store
* the local and other elements of one or several matching nodes.
* <p>
* This visitor can also peek up local or anonymous type declaration and restart
* a new {@link MatchLocator} traverse on this type.
* </p>
*/
class MemberDeclarationVisitor extends ASTVisitor {
// Matches information
private final MatchLocator locator;
private final IJavaElement enclosingElement;
private final MatchingNodeSet nodeSet;
private final ASTNode[] matchingNodes;
private final ASTNode matchingNode;
// Local type storage
HashtableOfIntValues occurrencesCounts = new HashtableOfIntValues(); // key = class name (char[]), value = occurrenceCount (int)
int nodesCount = 0;
// Local and other elements storage
private Annotation annotation;
private LocalDeclaration localDeclaration;
IJavaElement localElement;
IJavaElement[] localElements, otherElements;
IJavaElement[][] allOtherElements;
int ptr = -1;
int[] ptrs;
public MemberDeclarationVisitor(IJavaElement element, ASTNode[] nodes, MatchingNodeSet set, MatchLocator locator) {
this.enclosingElement = element;
this.nodeSet = set;
this.locator = locator;
if (nodes == null) {
this.matchingNode = null;
this.matchingNodes = null;
} else {
this.nodesCount = nodes.length;
if (nodes.length == 1) {
this.matchingNode = nodes[0];
this.matchingNodes = null;
} else {
this.matchingNode = null;
this.matchingNodes = nodes;
this.localElements = new IJavaElement[this.nodesCount];
this.ptrs = new int[this.nodesCount];
this.allOtherElements = new IJavaElement[this.nodesCount][];
}
}
}
public void endVisit(Argument argument, BlockScope scope) {
this.localDeclaration = null;
}
public void endVisit(LocalDeclaration declaration, BlockScope scope) {
this.localDeclaration = null;
}
public void endVisit(MarkerAnnotation markerAnnotation, BlockScope unused) {
this.annotation = null;
}
public void endVisit(NormalAnnotation normalAnnotation, BlockScope unused) {
this.annotation = null;
}
public void endVisit(SingleMemberAnnotation singleMemberAnnotation, BlockScope unused) {
this.annotation = null;
}
IJavaElement getLocalElement(int idx) {
if (this.nodesCount == 1) {
return this.localElement;
}
if (this.localElements != null) {
return this.localElements[idx];
}
return null;
}
IJavaElement[] getOtherElements(int idx) {
if (this.nodesCount == 1) {
if (this.otherElements != null) {
int length = this.otherElements.length;
if (this.ptr < (length-1)) {
System.arraycopy(this.otherElements, 0, this.otherElements = new IJavaElement[this.ptr+1], 0, this.ptr+1);
}
}
return this.otherElements;
}
IJavaElement[] elements = this.allOtherElements == null ? null : this.allOtherElements[idx];
if (elements != null) {
int length = elements.length;
if (this.ptrs[idx] < (length-1)) {
System.arraycopy(elements, 0, elements = this.allOtherElements[idx] = new IJavaElement[this.ptrs[idx]+1], 0, this.ptrs[idx]+1);
}
}
return elements;
}
private int matchNode(ASTNode reference) {
if (this.matchingNode != null) {
if (this.matchingNode == reference) return 0;
} else {
int length = this.matchingNodes.length;
for (int i=0; i<length; i++) {
if (this.matchingNodes[i] == reference) { // == is intentional
return i;
}
}
}
return -1;
}
/*
* Store the handle for the reference of the given index (e.g. peek in #matchingNodes
* or #matchingNode).
* Note that for performance reason, matching node and associated handles are
* not stored in array when there's only one reference to identify.
*/
private void storeHandle(int idx) {
if (this.localDeclaration == null) return;
IJavaElement handle = this.locator.createHandle(this.localDeclaration, this.enclosingElement);
if (this.nodesCount == 1) {
if (this.localElement == null) {
if (this.annotation == null) {
this.localElement = handle;
} else {
IJavaElement annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) handle);
if (annotHandle == null) {
annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) this.enclosingElement);
}
this.localElement = annotHandle == null ? handle : annotHandle;
}
} else {
if (++this.ptr == 0) {
this.otherElements = new IJavaElement[10];
} else {
int length = this.otherElements.length;
if (this.ptr == length) {
System.arraycopy(this.otherElements, 0, this.otherElements = new IJavaElement[length+10], 0, length);
}
}
if (this.annotation == null) {
this.otherElements[this.ptr] = handle;
} else {
IJavaElement annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) handle);
if (annotHandle == null) {
annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) this.enclosingElement);
}
this.otherElements[this.ptr] = annotHandle == null ? handle : annotHandle;
}
}
} else {
if (this.localElements[idx] == null) {
if (this.annotation == null) {
this.localElements[idx] = handle;
} else {
IJavaElement annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) handle);
if (annotHandle == null) {
annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) this.enclosingElement);
}
this.localElements[idx] = annotHandle == null ? handle : annotHandle;
}
this.ptrs[idx] = -1;
} else {
int oPtr = ++this.ptrs[idx];
if (oPtr== 0) {
this.allOtherElements[idx] = new IJavaElement[10];
} else {
int length = this.allOtherElements[idx].length;
if (oPtr == length) {
System.arraycopy(this.allOtherElements[idx], 0, this.allOtherElements[idx] = new IJavaElement[length+10], 0, length);
}
}
if (this.annotation == null) {
this.allOtherElements[idx][oPtr] = handle;
} else {
IJavaElement annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) handle);
if (annotHandle == null) {
annotHandle = this.locator.createHandle(this.annotation, (IAnnotatable) this.enclosingElement);
}
this.allOtherElements[idx][oPtr] = annotHandle == null ? handle : annotHandle;
}
}
}
}
public boolean visit(Argument argument, BlockScope scope) {
this.localDeclaration = argument;
return true;
}
public boolean visit(LocalDeclaration declaration, BlockScope scope) {
this.localDeclaration = declaration;
return true;
}
public boolean visit(MarkerAnnotation markerAnnotation, BlockScope unused) {
this.annotation = markerAnnotation;
return true;
}
public boolean visit(NormalAnnotation normalAnnotation, BlockScope unused) {
this.annotation = normalAnnotation;
return true;
}
public boolean visit(QualifiedNameReference nameReference, BlockScope unused) {
if (this.nodesCount > 0){
int idx = matchNode(nameReference);
if (idx >= 0) {
storeHandle(idx);
}
}
return false;
}
public boolean visit(QualifiedTypeReference typeReference, BlockScope unused) {
if (this.nodesCount > 0){
int idx = matchNode(typeReference);
if (idx >= 0) {
storeHandle(idx);
}
}
return false;
}
public boolean visit(SingleMemberAnnotation singleMemberAnnotation, BlockScope unused) {
this.annotation = singleMemberAnnotation;
return true;
}
public boolean visit(SingleNameReference nameReference, BlockScope unused) {
if (this.nodesCount > 0){
int idx = matchNode(nameReference);
if (idx >= 0) {
storeHandle(idx);
}
}
return false;
}
public boolean visit(SingleTypeReference typeReference, BlockScope unused) {
if (this.nodesCount > 0){
int idx = matchNode(typeReference);
if (idx >= 0) {
storeHandle(idx);
}
}
return false;
}
public boolean visit(TypeDeclaration typeDeclaration, BlockScope unused) {
try {
char[] simpleName;
if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
simpleName = CharOperation.NO_CHAR;
} else {
simpleName = typeDeclaration.name;
}
int occurrenceCount = this.occurrencesCounts.get(simpleName);
if (occurrenceCount == HashtableOfIntValues.NO_VALUE) {
occurrenceCount = 1;
} else {
occurrenceCount = occurrenceCount + 1;
}
this.occurrencesCounts.put(simpleName, occurrenceCount);
if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
this.locator.reportMatching(typeDeclaration, this.enclosingElement, -1, this.nodeSet, occurrenceCount);
} else {
Integer level = (Integer) this.nodeSet.matchingNodes.removeKey(typeDeclaration);
this.locator.reportMatching(typeDeclaration, this.enclosingElement, level != null ? level.intValue() : -1, this.nodeSet, occurrenceCount);
}
return false; // don't visit members as this was done during reportMatching(...)
} catch (CoreException e) {
throw new WrappedCoreException(e);
}
}
}