/*
* Copyright 2003-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.refactoring.core.rename.renameLocal;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.groovy.search.ITypeRequestor;
import org.eclipse.jdt.groovy.search.TypeLookupResult;
import org.eclipse.jdt.internal.core.util.Util;
/**
* Checks to make sure that a rename request for a local variable is not shadowing an existing name
* @author Andrew Eisenberg
* @created Apr 1, 2010
*/
public class LocalVariableNameCheckerRequestor implements ITypeRequestor {
private final Variable variable;
private final int start;
private final int end;
private final String newName;
private boolean shadowing = false;
private boolean variableFound = false;
private IJavaElement foundEnclosingElement = null;
public LocalVariableNameCheckerRequestor(Variable variable, String newName) {
this.variable = variable;
this.newName = newName;
if (variable instanceof ASTNode) {
ASTNode v = (ASTNode) variable;
start = v.getStart();
end = v.getEnd();
} else {
start = end = -1;
}
}
public VisitStatus acceptASTNode(ASTNode node, TypeLookupResult result,
IJavaElement enclosingElement) {
// check to see if the enclosing element does not enclose the
// nodeToLookFor
if (!interestingElement(enclosingElement)) {
return VisitStatus.CANCEL_MEMBER;
}
// only start looking for shadows when we've hit the variable that we are renaming
if (!variableFound) {
if (node == variable) {
variableFound = true;
foundEnclosingElement = enclosingElement;
}
return VisitStatus.CONTINUE;
}
// ensure that we don't keep looking for shadows after we've left the enclosing element.
if (enclosingElement != foundEnclosingElement) {
return VisitStatus.STOP_VISIT;
}
if (node instanceof Variable) {
Variable other = (Variable) node;
if (other.getName().equals(newName)) {
if (! (other instanceof VariableExpression) || ((VariableExpression) other).getAccessedVariable() != variable) {
shadowing = true;
return VisitStatus.STOP_VISIT;
}
}
}
if (node instanceof ConstantExpression) {
ConstantExpression con = (ConstantExpression) node;
if (con.getText().equals(variable.getName()) && result.declaration != variable) {
shadowing = true;
return VisitStatus.STOP_VISIT;
}
}
return VisitStatus.CONTINUE;
}
public boolean isShadowing() {
return shadowing;
}
/**
* @param enclosingElement
* @return true iff enclosingElement's source location contains the source
* location of {@link #variable}
*/
private boolean interestingElement(IJavaElement enclosingElement) {
// the clinit is always interesting since the clinit contains static
// initializers
if (enclosingElement.getElementName().equals("<clinit>")) {
return true;
}
if (start >= 0 && end >= 0 && enclosingElement instanceof ISourceReference) {
try {
ISourceRange range = ((ISourceReference) enclosingElement).getSourceRange();
return range.getOffset() <= start && range.getOffset() + range.getLength() >= end;
} catch (JavaModelException e) {
Util.log(e);
}
}
return false;
}
}