blob: 07882438b9e37333fb98084f3a5deeb7e434d12e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.corext.codemanipulation;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.text.Region;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberRef;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.MethodRef;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
public class ImportReferencesCollector extends GenericVisitor {
public static void collect(ASTNode node, IJavaProject project, Region rangeLimit, Collection resultingTypeImports, Collection resultingStaticImports) {
CompilationUnit astRoot= (CompilationUnit) node.getRoot();
node.accept(new ImportReferencesCollector(project, astRoot, rangeLimit, resultingTypeImports, resultingStaticImports));
}
private CompilationUnit fASTRoot;
private Region fSubRange;
private Collection/*<Name>*/ fTypeImports;
private Collection/*<Name>*/ fStaticImports;
private ImportReferencesCollector(IJavaProject project, CompilationUnit astRoot, Region rangeLimit, Collection resultingTypeImports, Collection resultingStaticImports) {
super(true);
fTypeImports= resultingTypeImports;
fStaticImports= resultingStaticImports;
fSubRange= rangeLimit;
if (project == null || !JavaModelUtil.is50OrHigher(project)) {
fStaticImports= null; // do not collect
}
fASTRoot= astRoot;
}
public ImportReferencesCollector(IJavaProject project, Region rangeLimit, Collection resultingTypeImports, Collection resultingStaticImports) {
this(project, null, rangeLimit, resultingTypeImports, resultingStaticImports);
}
public CompilationUnit getASTRoot(ASTNode node) {
if (fASTRoot == null) {
fASTRoot= (CompilationUnit) node.getRoot();
}
return fASTRoot;
}
private boolean isAffected(ASTNode node) {
if (fSubRange == null) {
return true;
}
int nodeStart= node.getStartPosition();
int offset= fSubRange.getOffset();
return nodeStart + node.getLength() > offset && (offset + fSubRange.getLength()) > nodeStart;
}
private void addReference(SimpleName name) {
if (isAffected(name)) {
fTypeImports.add(name);
}
}
private void typeRefFound(Name node) {
if (node != null) {
while (node.isQualifiedName()) {
node= ((QualifiedName) node).getQualifier();
}
addReference((SimpleName) node);
}
}
private void possibleTypeRefFound(Name node) {
while (node.isQualifiedName()) {
node= ((QualifiedName) node).getQualifier();
}
IBinding binding= node.resolveBinding();
if (binding == null || binding.getKind() == IBinding.TYPE) {
// if the binding is null, we cannot determine if
// we have a type binding or not, so we will assume
// we do.
addReference((SimpleName) node);
}
}
private void possibleStaticImportFound(Name name) {
if (fStaticImports == null) {
return;
}
while (name.isQualifiedName()) {
name= ((QualifiedName) name).getQualifier();
}
if (!isAffected(name)) {
return;
}
IBinding binding= name.resolveBinding();
if (binding == null || binding instanceof ITypeBinding || !Modifier.isStatic(binding.getModifiers()) || ((SimpleName) name).isDeclaration()) {
return;
}
if (binding instanceof IVariableBinding) {
IVariableBinding varBinding= (IVariableBinding) binding;
if (varBinding.isField()) {
varBinding= varBinding.getVariableDeclaration();
ITypeBinding declaringClass= varBinding.getDeclaringClass();
if (declaringClass != null && !declaringClass.isLocal()) {
if (new ScopeAnalyzer(getASTRoot(name)).isDeclaredInScope(varBinding, (SimpleName)name, ScopeAnalyzer.VARIABLES))
return;
fStaticImports.add(name);
}
}
} else if (binding instanceof IMethodBinding) {
IMethodBinding methodBinding= ((IMethodBinding) binding).getMethodDeclaration();
ITypeBinding declaringClass= methodBinding.getDeclaringClass();
if (declaringClass != null && !declaringClass.isLocal()) {
if (new ScopeAnalyzer(getASTRoot(name)).isDeclaredInScope(methodBinding, (SimpleName)name, ScopeAnalyzer.METHODS))
return;
fStaticImports.add(name);
}
}
}
private void doVisitChildren(List elements) {
int nElements= elements.size();
for (int i= 0; i < nElements; i++) {
((ASTNode) elements.get(i)).accept(this);
}
}
private void doVisitNode(ASTNode node) {
if (node != null) {
node.accept(this);
}
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visitNode(org.eclipse.jdt.core.dom.ASTNode)
*/
protected boolean visitNode(ASTNode node) {
return isAffected(node);
}
/*
* @see ASTVisitor#visit(ArrayType)
*/
public boolean visit(ArrayType node) {
doVisitNode(node.getElementType());
return false;
}
/*
* @see ASTVisitor#visit(SimpleType)
*/
public boolean visit(SimpleType node) {
typeRefFound(node.getName());
return false;
}
/*
* @see ASTVisitor#visit(QualifiedType)
*/
public boolean visit(QualifiedType node) {
// nothing to do here, let the qualifier be visited
return true;
}
/*
* @see ASTVisitor#visit(QualifiedName)
*/
public boolean visit(QualifiedName node) {
possibleTypeRefFound(node); // possible ref
possibleStaticImportFound(node);
return false;
}
/*
* @see ASTVisitor#visit(ImportDeclaration)
*/
public boolean visit(ImportDeclaration node) {
return false;
}
/*
* @see ASTVisitor#visit(PackageDeclaration)
*/
public boolean visit(PackageDeclaration node) {
if (node.getAST().apiLevel() >= AST.JLS3) {
doVisitChildren(node.annotations());
}
return false;
}
/*
* @see ASTVisitor#visit(ThisExpression)
*/
public boolean visit(ThisExpression node) {
typeRefFound(node.getQualifier());
return false;
}
private void evalQualifyingExpression(Expression expr, Name selector) {
if (expr != null) {
if (expr instanceof Name) {
Name name= (Name) expr;
possibleTypeRefFound(name);
possibleStaticImportFound(name);
} else {
expr.accept(this);
}
} else if (selector != null) {
possibleStaticImportFound(selector);
}
}
/*
* @see ASTVisitor#visit(ClassInstanceCreation)
*/
public boolean visit(ClassInstanceCreation node) {
doVisitChildren(node.typeArguments());
doVisitNode(node.getType());
evalQualifyingExpression(node.getExpression(), null);
if (node.getAnonymousClassDeclaration() != null) {
node.getAnonymousClassDeclaration().accept(this);
}
doVisitChildren(node.arguments());
return false;
}
/*
* @see ASTVisitor#endVisit(MethodInvocation)
*/
public boolean visit(MethodInvocation node) {
evalQualifyingExpression(node.getExpression(), node.getName());
doVisitChildren(node.typeArguments());
doVisitChildren(node.arguments());
return false;
}
/*
* @see ASTVisitor#visit(SuperConstructorInvocation)
*/
public boolean visit(SuperConstructorInvocation node) {
if (!isAffected(node)) {
return false;
}
evalQualifyingExpression(node.getExpression(), null);
doVisitChildren(node.typeArguments());
doVisitChildren(node.arguments());
return false;
}
/*
* @see ASTVisitor#visit(FieldAccess)
*/
public boolean visit(FieldAccess node) {
evalQualifyingExpression(node.getExpression(), node.getName());
return false;
}
/*
* @see ASTVisitor#visit(SimpleName)
*/
public boolean visit(SimpleName node) {
// if the call gets here, it can only be a variable reference
possibleStaticImportFound(node);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
*/
public boolean visit(MarkerAnnotation node) {
typeRefFound(node.getTypeName());
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
*/
public boolean visit(NormalAnnotation node) {
typeRefFound(node.getTypeName());
doVisitChildren(node.values());
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
*/
public boolean visit(SingleMemberAnnotation node) {
typeRefFound(node.getTypeName());
doVisitNode(node.getValue());
return false;
}
/*
* @see ASTVisitor#visit(TypeDeclaration)
*/
public boolean visit(TypeDeclaration node) {
if (!isAffected(node)) {
return false;
}
return true;
}
/*
* @see ASTVisitor#visit(MethodDeclaration)
*/
public boolean visit(MethodDeclaration node) {
if (!isAffected(node)) {
return false;
}
doVisitNode(node.getJavadoc());
if (node.getAST().apiLevel() >= AST.JLS3) {
doVisitChildren(node.modifiers());
doVisitChildren(node.typeParameters());
}
if (!node.isConstructor()) {
doVisitNode(node.getReturnType2());
}
doVisitChildren(node.parameters());
Iterator iter=node.thrownExceptions().iterator();
while (iter.hasNext()) {
typeRefFound((Name) iter.next());
}
doVisitNode(node.getBody());
return false;
}
public boolean visit(TagElement node) {
String tagName= node.getTagName();
List list= node.fragments();
int idx= 0;
if (tagName != null && !list.isEmpty()) {
Object first= list.get(0);
if (first instanceof Name) {
if ("@throws".equals(tagName) || "@exception".equals(tagName)) { //$NON-NLS-1$//$NON-NLS-2$
typeRefFound((Name) first);
} else if ("@see".equals(tagName) || "@link".equals(tagName) || "@linkplain".equals(tagName)) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
Name name= (Name) first;
possibleTypeRefFound(name);
possibleStaticImportFound(name);
}
idx++;
}
}
for (int i= idx; i < list.size(); i++) {
doVisitNode((ASTNode) list.get(i));
}
return false;
}
public boolean visit(MemberRef node) {
Name qualifier= node.getQualifier();
if (qualifier != null) {
typeRefFound(qualifier);
} else {
SimpleName name= node.getName();
if (name != null) {
possibleStaticImportFound(name);
}
}
return false;
}
public boolean visit(MethodRef node) {
Name qualifier= node.getQualifier();
if (qualifier != null) {
typeRefFound(qualifier);
} else {
SimpleName name= node.getName();
if (name != null) {
possibleStaticImportFound(name);
}
}
List list= node.parameters();
if (list != null) {
doVisitChildren(list); // visit MethodRefParameter with Type
}
return false;
}
}