001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.corext.codemanipulation;
011:
012: import java.util.Collection;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import org.eclipse.jface.text.Region;
017:
018: import org.eclipse.jdt.core.IJavaProject;
019: import org.eclipse.jdt.core.dom.AST;
020: import org.eclipse.jdt.core.dom.ASTNode;
021: import org.eclipse.jdt.core.dom.ArrayType;
022: import org.eclipse.jdt.core.dom.ClassInstanceCreation;
023: import org.eclipse.jdt.core.dom.CompilationUnit;
024: import org.eclipse.jdt.core.dom.Expression;
025: import org.eclipse.jdt.core.dom.FieldAccess;
026: import org.eclipse.jdt.core.dom.IBinding;
027: import org.eclipse.jdt.core.dom.IMethodBinding;
028: import org.eclipse.jdt.core.dom.ITypeBinding;
029: import org.eclipse.jdt.core.dom.IVariableBinding;
030: import org.eclipse.jdt.core.dom.ImportDeclaration;
031: import org.eclipse.jdt.core.dom.MarkerAnnotation;
032: import org.eclipse.jdt.core.dom.MemberRef;
033: import org.eclipse.jdt.core.dom.MethodDeclaration;
034: import org.eclipse.jdt.core.dom.MethodInvocation;
035: import org.eclipse.jdt.core.dom.MethodRef;
036: import org.eclipse.jdt.core.dom.Modifier;
037: import org.eclipse.jdt.core.dom.Name;
038: import org.eclipse.jdt.core.dom.NormalAnnotation;
039: import org.eclipse.jdt.core.dom.PackageDeclaration;
040: import org.eclipse.jdt.core.dom.QualifiedName;
041: import org.eclipse.jdt.core.dom.QualifiedType;
042: import org.eclipse.jdt.core.dom.SimpleName;
043: import org.eclipse.jdt.core.dom.SimpleType;
044: import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
045: import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
046: import org.eclipse.jdt.core.dom.TagElement;
047: import org.eclipse.jdt.core.dom.ThisExpression;
048: import org.eclipse.jdt.core.dom.TypeDeclaration;
049:
050: import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
051: import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
052: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
053:
054: public class ImportReferencesCollector extends GenericVisitor {
055:
056: public static void collect(ASTNode node, IJavaProject project,
057: Region rangeLimit, Collection resultingTypeImports,
058: Collection resultingStaticImports) {
059: CompilationUnit astRoot = (CompilationUnit) node.getRoot();
060: node.accept(new ImportReferencesCollector(project, astRoot,
061: rangeLimit, resultingTypeImports,
062: resultingStaticImports));
063: }
064:
065: private CompilationUnit fASTRoot;
066: private Region fSubRange;
067: private Collection/*<Name>*/fTypeImports;
068: private Collection/*<Name>*/fStaticImports;
069:
070: private ImportReferencesCollector(IJavaProject project,
071: CompilationUnit astRoot, Region rangeLimit,
072: Collection resultingTypeImports,
073: Collection resultingStaticImports) {
074: super (true);
075: fTypeImports = resultingTypeImports;
076: fStaticImports = resultingStaticImports;
077: fSubRange = rangeLimit;
078: if (project == null || !JavaModelUtil.is50OrHigher(project)) {
079: fStaticImports = null; // do not collect
080: }
081: fASTRoot = astRoot;
082: }
083:
084: public ImportReferencesCollector(IJavaProject project,
085: Region rangeLimit, Collection resultingTypeImports,
086: Collection resultingStaticImports) {
087: this (project, null, rangeLimit, resultingTypeImports,
088: resultingStaticImports);
089: }
090:
091: public CompilationUnit getASTRoot(ASTNode node) {
092: if (fASTRoot == null) {
093: fASTRoot = (CompilationUnit) node.getRoot();
094: }
095: return fASTRoot;
096: }
097:
098: private boolean isAffected(ASTNode node) {
099: if (fSubRange == null) {
100: return true;
101: }
102: int nodeStart = node.getStartPosition();
103: int offset = fSubRange.getOffset();
104: return nodeStart + node.getLength() > offset
105: && (offset + fSubRange.getLength()) > nodeStart;
106: }
107:
108: private void addReference(SimpleName name) {
109: if (isAffected(name)) {
110: fTypeImports.add(name);
111: }
112: }
113:
114: private void typeRefFound(Name node) {
115: if (node != null) {
116: while (node.isQualifiedName()) {
117: node = ((QualifiedName) node).getQualifier();
118: }
119: addReference((SimpleName) node);
120: }
121: }
122:
123: private void possibleTypeRefFound(Name node) {
124: while (node.isQualifiedName()) {
125: node = ((QualifiedName) node).getQualifier();
126: }
127: IBinding binding = node.resolveBinding();
128: if (binding == null || binding.getKind() == IBinding.TYPE) {
129: // if the binding is null, we cannot determine if
130: // we have a type binding or not, so we will assume
131: // we do.
132: addReference((SimpleName) node);
133: }
134: }
135:
136: private void possibleStaticImportFound(Name name) {
137: if (fStaticImports == null) {
138: return;
139: }
140:
141: while (name.isQualifiedName()) {
142: name = ((QualifiedName) name).getQualifier();
143: }
144: if (!isAffected(name)) {
145: return;
146: }
147:
148: IBinding binding = name.resolveBinding();
149: if (binding == null || binding instanceof ITypeBinding
150: || !Modifier.isStatic(binding.getModifiers())
151: || ((SimpleName) name).isDeclaration()) {
152: return;
153: }
154:
155: if (binding instanceof IVariableBinding) {
156: IVariableBinding varBinding = (IVariableBinding) binding;
157: if (varBinding.isField()) {
158: varBinding = varBinding.getVariableDeclaration();
159: ITypeBinding declaringClass = varBinding
160: .getDeclaringClass();
161: if (declaringClass != null && !declaringClass.isLocal()) {
162: if (new ScopeAnalyzer(getASTRoot(name))
163: .isDeclaredInScope(
164: varBinding,
165: (SimpleName) name,
166: ScopeAnalyzer.VARIABLES
167: | ScopeAnalyzer.CHECK_VISIBILITY))
168: return;
169: fStaticImports.add(name);
170: }
171: }
172: } else if (binding instanceof IMethodBinding) {
173: IMethodBinding methodBinding = ((IMethodBinding) binding)
174: .getMethodDeclaration();
175: ITypeBinding declaringClass = methodBinding
176: .getDeclaringClass();
177: if (declaringClass != null && !declaringClass.isLocal()) {
178: if (new ScopeAnalyzer(getASTRoot(name))
179: .isDeclaredInScope(
180: methodBinding,
181: (SimpleName) name,
182: ScopeAnalyzer.METHODS
183: | ScopeAnalyzer.CHECK_VISIBILITY))
184: return;
185: fStaticImports.add(name);
186: }
187: }
188:
189: }
190:
191: private void doVisitChildren(List elements) {
192: int nElements = elements.size();
193: for (int i = 0; i < nElements; i++) {
194: ((ASTNode) elements.get(i)).accept(this );
195: }
196: }
197:
198: private void doVisitNode(ASTNode node) {
199: if (node != null) {
200: node.accept(this );
201: }
202: }
203:
204: /* (non-Javadoc)
205: * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visitNode(org.eclipse.jdt.core.dom.ASTNode)
206: */
207: protected boolean visitNode(ASTNode node) {
208: return isAffected(node);
209: }
210:
211: /*
212: * @see ASTVisitor#visit(ArrayType)
213: */
214: public boolean visit(ArrayType node) {
215: doVisitNode(node.getElementType());
216: return false;
217: }
218:
219: /*
220: * @see ASTVisitor#visit(SimpleType)
221: */
222: public boolean visit(SimpleType node) {
223: typeRefFound(node.getName());
224: return false;
225: }
226:
227: /*
228: * @see ASTVisitor#visit(QualifiedType)
229: */
230: public boolean visit(QualifiedType node) {
231: // nothing to do here, let the qualifier be visited
232: return true;
233: }
234:
235: /*
236: * @see ASTVisitor#visit(QualifiedName)
237: */
238: public boolean visit(QualifiedName node) {
239: possibleTypeRefFound(node); // possible ref
240: possibleStaticImportFound(node);
241: return false;
242: }
243:
244: /*
245: * @see ASTVisitor#visit(ImportDeclaration)
246: */
247: public boolean visit(ImportDeclaration node) {
248: return false;
249: }
250:
251: /*
252: * @see ASTVisitor#visit(PackageDeclaration)
253: */
254: public boolean visit(PackageDeclaration node) {
255: if (node.getAST().apiLevel() >= AST.JLS3) {
256: doVisitChildren(node.annotations());
257: }
258: return false;
259: }
260:
261: /*
262: * @see ASTVisitor#visit(ThisExpression)
263: */
264: public boolean visit(ThisExpression node) {
265: typeRefFound(node.getQualifier());
266: return false;
267: }
268:
269: private void evalQualifyingExpression(Expression expr, Name selector) {
270: if (expr != null) {
271: if (expr instanceof Name) {
272: Name name = (Name) expr;
273: possibleTypeRefFound(name);
274: possibleStaticImportFound(name);
275: } else {
276: expr.accept(this );
277: }
278: } else if (selector != null) {
279: possibleStaticImportFound(selector);
280: }
281: }
282:
283: /*
284: * @see ASTVisitor#visit(ClassInstanceCreation)
285: */
286: public boolean visit(ClassInstanceCreation node) {
287: doVisitChildren(node.typeArguments());
288: doVisitNode(node.getType());
289: evalQualifyingExpression(node.getExpression(), null);
290: if (node.getAnonymousClassDeclaration() != null) {
291: node.getAnonymousClassDeclaration().accept(this );
292: }
293: doVisitChildren(node.arguments());
294: return false;
295: }
296:
297: /*
298: * @see ASTVisitor#endVisit(MethodInvocation)
299: */
300: public boolean visit(MethodInvocation node) {
301: evalQualifyingExpression(node.getExpression(), node.getName());
302: doVisitChildren(node.typeArguments());
303: doVisitChildren(node.arguments());
304: return false;
305: }
306:
307: /*
308: * @see ASTVisitor#visit(SuperConstructorInvocation)
309: */
310: public boolean visit(SuperConstructorInvocation node) {
311: if (!isAffected(node)) {
312: return false;
313: }
314:
315: evalQualifyingExpression(node.getExpression(), null);
316: doVisitChildren(node.typeArguments());
317: doVisitChildren(node.arguments());
318: return false;
319: }
320:
321: /*
322: * @see ASTVisitor#visit(FieldAccess)
323: */
324: public boolean visit(FieldAccess node) {
325: evalQualifyingExpression(node.getExpression(), node.getName());
326: return false;
327: }
328:
329: /*
330: * @see ASTVisitor#visit(SimpleName)
331: */
332: public boolean visit(SimpleName node) {
333: // if the call gets here, it can only be a variable reference
334: possibleStaticImportFound(node);
335: return false;
336: }
337:
338: /* (non-Javadoc)
339: * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
340: */
341: public boolean visit(MarkerAnnotation node) {
342: typeRefFound(node.getTypeName());
343: return false;
344: }
345:
346: /* (non-Javadoc)
347: * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
348: */
349: public boolean visit(NormalAnnotation node) {
350: typeRefFound(node.getTypeName());
351: doVisitChildren(node.values());
352: return false;
353: }
354:
355: /* (non-Javadoc)
356: * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
357: */
358: public boolean visit(SingleMemberAnnotation node) {
359: typeRefFound(node.getTypeName());
360: doVisitNode(node.getValue());
361: return false;
362: }
363:
364: /*
365: * @see ASTVisitor#visit(TypeDeclaration)
366: */
367: public boolean visit(TypeDeclaration node) {
368: if (!isAffected(node)) {
369: return false;
370: }
371: return true;
372: }
373:
374: /*
375: * @see ASTVisitor#visit(MethodDeclaration)
376: */
377: public boolean visit(MethodDeclaration node) {
378: if (!isAffected(node)) {
379: return false;
380: }
381: doVisitNode(node.getJavadoc());
382:
383: if (node.getAST().apiLevel() >= AST.JLS3) {
384: doVisitChildren(node.modifiers());
385: doVisitChildren(node.typeParameters());
386: }
387:
388: if (!node.isConstructor()) {
389: doVisitNode(node.getReturnType2());
390: }
391: doVisitChildren(node.parameters());
392: Iterator iter = node.thrownExceptions().iterator();
393: while (iter.hasNext()) {
394: typeRefFound((Name) iter.next());
395: }
396: doVisitNode(node.getBody());
397: return false;
398: }
399:
400: public boolean visit(TagElement node) {
401: String tagName = node.getTagName();
402: List list = node.fragments();
403: int idx = 0;
404: if (tagName != null && !list.isEmpty()) {
405: Object first = list.get(0);
406: if (first instanceof Name) {
407: if ("@throws".equals(tagName) || "@exception".equals(tagName)) { //$NON-NLS-1$//$NON-NLS-2$
408: typeRefFound((Name) first);
409: } else if ("@see".equals(tagName) || "@link".equals(tagName) || "@linkplain".equals(tagName)) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
410: Name name = (Name) first;
411: possibleTypeRefFound(name);
412: }
413: idx++;
414: }
415: }
416: for (int i = idx; i < list.size(); i++) {
417: doVisitNode((ASTNode) list.get(i));
418: }
419: return false;
420: }
421:
422: public boolean visit(MemberRef node) {
423: Name qualifier = node.getQualifier();
424: if (qualifier != null) {
425: typeRefFound(qualifier);
426: }
427: return false;
428: }
429:
430: public boolean visit(MethodRef node) {
431: Name qualifier = node.getQualifier();
432: if (qualifier != null) {
433: typeRefFound(qualifier);
434: }
435: List list = node.parameters();
436: if (list != null) {
437: doVisitChildren(list); // visit MethodRefParameter with Type
438: }
439: return false;
440: }
441: }
|