1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.core.manipulation;
15 
16 import java.util.Collection;
17 import java.util.Iterator;
18 import java.util.List;
19 
20 import org.eclipse.jface.text.Region;
21 
22 import org.eclipse.jdt.core.IJavaProject;
23 import org.eclipse.jdt.core.dom.AST;
24 import org.eclipse.jdt.core.dom.ASTNode;
25 import org.eclipse.jdt.core.dom.AnnotatableType;
26 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
27 import org.eclipse.jdt.core.dom.CompilationUnit;
28 import org.eclipse.jdt.core.dom.ContinueStatement;
29 import org.eclipse.jdt.core.dom.CreationReference;
30 import org.eclipse.jdt.core.dom.Expression;
31 import org.eclipse.jdt.core.dom.ExpressionMethodReference;
32 import org.eclipse.jdt.core.dom.FieldAccess;
33 import org.eclipse.jdt.core.dom.IBinding;
34 import org.eclipse.jdt.core.dom.IMethodBinding;
35 import org.eclipse.jdt.core.dom.ITypeBinding;
36 import org.eclipse.jdt.core.dom.IVariableBinding;
37 import org.eclipse.jdt.core.dom.ImportDeclaration;
38 import org.eclipse.jdt.core.dom.LabeledStatement;
39 import org.eclipse.jdt.core.dom.MarkerAnnotation;
40 import org.eclipse.jdt.core.dom.MemberRef;
41 import org.eclipse.jdt.core.dom.MethodDeclaration;
42 import org.eclipse.jdt.core.dom.MethodInvocation;
43 import org.eclipse.jdt.core.dom.MethodRef;
44 import org.eclipse.jdt.core.dom.MethodRefParameter;
45 import org.eclipse.jdt.core.dom.Modifier;
46 import org.eclipse.jdt.core.dom.Name;
47 import org.eclipse.jdt.core.dom.NameQualifiedType;
48 import org.eclipse.jdt.core.dom.NormalAnnotation;
49 import org.eclipse.jdt.core.dom.PackageDeclaration;
50 import org.eclipse.jdt.core.dom.ProvidesDirective;
51 import org.eclipse.jdt.core.dom.QualifiedName;
52 import org.eclipse.jdt.core.dom.QualifiedType;
53 import org.eclipse.jdt.core.dom.SimpleName;
54 import org.eclipse.jdt.core.dom.SimpleType;
55 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
56 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
57 import org.eclipse.jdt.core.dom.SuperFieldAccess;
58 import org.eclipse.jdt.core.dom.SuperMethodReference;
59 import org.eclipse.jdt.core.dom.TagElement;
60 import org.eclipse.jdt.core.dom.ThisExpression;
61 import org.eclipse.jdt.core.dom.TypeDeclaration;
62 import org.eclipse.jdt.core.dom.TypeMethodReference;
63 import org.eclipse.jdt.core.dom.UsesDirective;
64 import org.eclipse.jdt.core.dom.YieldStatement;
65 
66 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
67 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
68 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
69 
70 import org.eclipse.jdt.internal.ui.util.ASTHelper;
71 
72 
73 /**
74  * @since 1.10
75  */
76 public class ImportReferencesCollector extends GenericVisitor {
77 
78 	/**
79 	 * Collect import statements from an AST node.
80 	 *
81 	 * @param node The AST node
82 	 * @param project The Java project
83 	 * @param rangeLimit The range within the source file
84 	 * @param resultingTypeImports The collected import references
85 	 * @param resultingStaticImports The collected static imports
86 	 */
collect(ASTNode node, IJavaProject project, Region rangeLimit, Collection<SimpleName> resultingTypeImports, Collection<SimpleName> resultingStaticImports)87 	public static void collect(ASTNode node, IJavaProject project, Region rangeLimit, Collection<SimpleName> resultingTypeImports, Collection<SimpleName> resultingStaticImports) {
88 		collect(node, project, rangeLimit, false, resultingTypeImports, resultingStaticImports);
89 	}
90 
91 	/**
92 	 * Collect import statements from an AST node.
93 	 *
94 	 * @param node The AST node
95 	 * @param project The Java project
96 	 * @param rangeLimit The range within the source file
97 	 * @param skipMethodBodies If set, do not visit method bodies
98 	 * @param resultingTypeImports  The collected import references
99 	 * @param resultingStaticImports The collected static imports
100 	 */
collect(ASTNode node, IJavaProject project, Region rangeLimit, boolean skipMethodBodies, Collection<SimpleName> resultingTypeImports, Collection<SimpleName> resultingStaticImports)101 	public static void collect(ASTNode node, IJavaProject project, Region rangeLimit, boolean skipMethodBodies, Collection<SimpleName> resultingTypeImports, Collection<SimpleName> resultingStaticImports) {
102 		ASTNode root= node.getRoot();
103 		CompilationUnit astRoot= root instanceof CompilationUnit ? (CompilationUnit) root : null;
104 		node.accept(new ImportReferencesCollector(project, astRoot, rangeLimit, skipMethodBodies, resultingTypeImports, resultingStaticImports));
105 	}
106 
107 	private CompilationUnit fASTRoot;
108 	private Region fSubRange;
109 	private Collection<SimpleName> fTypeImports;
110 	private Collection<SimpleName> fStaticImports;
111 	private boolean fSkipMethodBodies;
112 
ImportReferencesCollector(IJavaProject project, CompilationUnit astRoot, Region rangeLimit, boolean skipMethodBodies, Collection<SimpleName> resultingTypeImports, Collection<SimpleName> resultingStaticImports)113 	private ImportReferencesCollector(IJavaProject project, CompilationUnit astRoot, Region rangeLimit, boolean skipMethodBodies, Collection<SimpleName> resultingTypeImports, Collection<SimpleName> resultingStaticImports) {
114 		super(processJavadocComments(astRoot));
115 		fTypeImports= resultingTypeImports;
116 		fStaticImports= resultingStaticImports;
117 		fSubRange= rangeLimit;
118 		if (project == null || !JavaModelUtil.is50OrHigher(project)) {
119 			fStaticImports= null; // do not collect
120 		}
121 		fASTRoot= astRoot; // can be null
122 		fSkipMethodBodies= skipMethodBodies;
123 	}
124 
processJavadocComments(CompilationUnit astRoot)125 	private static boolean processJavadocComments(CompilationUnit astRoot) {
126 		 // don't visit Javadoc for 'package-info' (bug 216432)
127 		if (astRoot != null && astRoot.getTypeRoot() != null) {
128 			return !JavaModelUtil.PACKAGE_INFO_JAVA.equals(astRoot.getTypeRoot().getElementName());
129 		}
130 		return true;
131 	}
132 
isAffected(ASTNode node)133 	private boolean isAffected(ASTNode node) {
134 		if (fSubRange == null) {
135 			return true;
136 		}
137 		int nodeStart= node.getStartPosition();
138 		int offset= fSubRange.getOffset();
139 		return nodeStart + node.getLength() > offset && offset + fSubRange.getLength() >  nodeStart;
140 	}
141 
142 
addReference(SimpleName name)143 	private void addReference(SimpleName name) {
144 		if (isAffected(name)) {
145 			fTypeImports.add(name);
146 		}
147 	}
148 
typeRefFound(Name node)149 	private void typeRefFound(Name node) {
150 		if (node != null) {
151 			while (node.isQualifiedName()) {
152 				node= ((QualifiedName) node).getQualifier();
153 			}
154 			addReference((SimpleName) node);
155 		}
156 	}
157 
possibleTypeRefFound(Name node)158 	private void possibleTypeRefFound(Name node) {
159 		while (node.isQualifiedName()) {
160 			node= ((QualifiedName) node).getQualifier();
161 		}
162 		IBinding binding= node.resolveBinding();
163 		if (binding == null || binding.getKind() == IBinding.TYPE) {
164 			// if the binding is null, we cannot determine if
165 			// we have a type binding or not, so we will assume
166 			// we do.
167 			addReference((SimpleName) node);
168 		}
169 	}
170 
possibleStaticImportFound(Name name)171 	private void possibleStaticImportFound(Name name) {
172 		if (fStaticImports == null || fASTRoot == null) {
173 			return;
174 		}
175 
176 		while (name.isQualifiedName()) {
177 			name= ((QualifiedName) name).getQualifier();
178 		}
179 		if (!isAffected(name)) {
180 			return;
181 		}
182 
183 		IBinding binding= name.resolveBinding();
184 		SimpleName simpleName= (SimpleName)name;
185 		if (binding == null) {
186 			// This may be a currently unresolvable reference to a static member.
187 			fStaticImports.add(simpleName);
188 		} else if (binding instanceof ITypeBinding || !Modifier.isStatic(binding.getModifiers()) || simpleName.isDeclaration()) {
189 			return;
190 		} else if (binding instanceof IVariableBinding) {
191 			IVariableBinding varBinding= (IVariableBinding) binding;
192 			if (varBinding.isField()) {
193 				varBinding= varBinding.getVariableDeclaration();
194 				ITypeBinding declaringClass= varBinding.getDeclaringClass();
195 				if (declaringClass != null && !declaringClass.isLocal()) {
196 					if (new ScopeAnalyzer(fASTRoot).isDeclaredInScope(varBinding, simpleName, ScopeAnalyzer.VARIABLES | ScopeAnalyzer.CHECK_VISIBILITY))
197 							return;
198 					fStaticImports.add(simpleName);
199 				}
200 			}
201 		} else if (binding instanceof IMethodBinding) {
202 			IMethodBinding methodBinding= ((IMethodBinding) binding).getMethodDeclaration();
203 			ITypeBinding declaringClass= methodBinding.getDeclaringClass();
204 			if (declaringClass != null && !declaringClass.isLocal()) {
205 				if (new ScopeAnalyzer(fASTRoot).isDeclaredInScope(methodBinding, simpleName, ScopeAnalyzer.METHODS | ScopeAnalyzer.CHECK_VISIBILITY))
206 					return;
207 				fStaticImports.add(simpleName);
208 			}
209 		}
210 
211 	}
212 
doVisitChildren(List<? extends ASTNode> elements)213 	private void doVisitChildren(List<? extends ASTNode> elements) {
214 		int nElements= elements.size();
215 		for (int i= 0; i < nElements; i++) {
216 			((ASTNode) elements.get(i)).accept(this);
217 		}
218 	}
219 
doVisitNode(ASTNode node)220 	private void doVisitNode(ASTNode node) {
221 		if (node != null) {
222 			node.accept(this);
223 		}
224 	}
225 
226 	@Override
visitNode(ASTNode node)227 	protected boolean visitNode(ASTNode node) {
228 		return isAffected(node);
229 	}
230 
231 	/*
232 	 * @see ASTVisitor#visit(SimpleType)
233 	 */
234 	@Override
visit(SimpleType node)235 	public boolean visit(SimpleType node) {
236 		if (node.getAST().apiLevel() < AST.JLS10 || !node.isVar()) {
237 			typeRefFound(node.getName());
238 		}
239 		visitAnnotations(node);
240 		return false;
241 	}
242 
243 	/*
244 	 * @see ASTVisitor#visit(NameQualifiedType)
245 	 */
246 	@Override
visit(NameQualifiedType node)247 	public boolean visit(NameQualifiedType node) {
248 		possibleTypeRefFound(node.getQualifier());
249 		visitAnnotations(node);
250 		return false;
251 	}
252 
253 	/*
254 	 * @see ASTVisitor#visit(QualifiedType)
255 	 */
256 	@Override
visit(QualifiedType node)257 	public boolean visit(QualifiedType node) {
258 		doVisitNode(node.getQualifier());
259 		visitAnnotations(node);
260 		return false;
261 	}
262 
visitAnnotations(AnnotatableType node)263 	private void visitAnnotations(AnnotatableType node) {
264 		if (node.getAST().apiLevel() >= AST.JLS8) {
265 			doVisitChildren(node.annotations());
266 		}
267 	}
268 
269 	/*
270 	 * @see ASTVisitor#visit(QualifiedName)
271 	 */
272 	@Override
visit(QualifiedName node)273 	public boolean visit(QualifiedName node) {
274 		possibleTypeRefFound(node); // possible ref
275 		possibleStaticImportFound(node);
276 		return false;
277 	}
278 
279 	/*
280 	 * @see ASTVisitor#visit(ImportDeclaration)
281 	 */
282 	@Override
visit(ImportDeclaration node)283 	public boolean visit(ImportDeclaration node) {
284 		return false;
285 	}
286 
287 	/*
288 	 * @see ASTVisitor#visit(PackageDeclaration)
289 	 */
290 	@Override
visit(PackageDeclaration node)291 	public boolean visit(PackageDeclaration node) {
292 		doVisitNode(node.getJavadoc());
293 		doVisitChildren(node.annotations());
294 		return false;
295 	}
296 
297 	@Override
visit(LabeledStatement node)298 	public boolean visit(LabeledStatement node) {
299 		doVisitNode(node.getBody());
300 		return false;
301 	}
302 
303 	@Override
visit(ContinueStatement node)304 	public boolean visit(ContinueStatement node) {
305 		return false;
306 	}
307 
308 	@Override
visit(YieldStatement node)309 	public boolean visit(YieldStatement node) {
310 		if (ASTHelper.isYieldNodeSupportedInAST(node.getAST())) {
311 			evalQualifyingExpression(node.getExpression(), null);
312 		}
313 		return false;
314 	}
315 
316 	/*
317 	 * @see ASTVisitor#visit(ThisExpression)
318 	 */
319 	@Override
visit(ThisExpression node)320 	public boolean visit(ThisExpression node) {
321 		typeRefFound(node.getQualifier());
322 		return false;
323 	}
324 
325 	@Override
visit(SuperFieldAccess node)326 	public boolean visit(SuperFieldAccess node) {
327 		typeRefFound(node.getQualifier());
328 		return false;
329 	}
330 
evalQualifyingExpression(Expression expr, Name selector)331 	private void evalQualifyingExpression(Expression expr, Name selector) {
332 		if (expr != null) {
333 			if (expr instanceof Name) {
334 				Name name= (Name) expr;
335 				possibleTypeRefFound(name);
336 				possibleStaticImportFound(name);
337 			} else {
338 				expr.accept(this);
339 			}
340 		} else if (selector != null) {
341 			possibleStaticImportFound(selector);
342 		}
343 	}
344 
345 	/*
346 	 * @see ASTVisitor#visit(ClassInstanceCreation)
347 	 */
348 	@Override
visit(ClassInstanceCreation node)349 	public boolean visit(ClassInstanceCreation node) {
350 		doVisitChildren(node.typeArguments());
351 		doVisitNode(node.getType());
352 		evalQualifyingExpression(node.getExpression(), null);
353 		if (node.getAnonymousClassDeclaration() != null) {
354 			node.getAnonymousClassDeclaration().accept(this);
355 		}
356 		doVisitChildren(node.arguments());
357 		return false;
358 	}
359 
360 	/*
361 	 * @see ASTVisitor#endVisit(MethodInvocation)
362 	 */
363 	@Override
visit(MethodInvocation node)364 	public boolean visit(MethodInvocation node) {
365 		evalQualifyingExpression(node.getExpression(), node.getName());
366 		doVisitChildren(node.typeArguments());
367 		doVisitChildren(node.arguments());
368 		return false;
369 	}
370 
371 	@Override
visit(CreationReference node)372 	public boolean visit(CreationReference node) {
373 		doVisitNode(node.getType());
374 		doVisitChildren(node.typeArguments());
375 		return false;
376 	}
377 
378 	@Override
visit(ExpressionMethodReference node)379 	public boolean visit(ExpressionMethodReference node) {
380 		evalQualifyingExpression(node.getExpression(), node.getName());
381 		doVisitChildren(node.typeArguments());
382 		return false;
383 	}
384 
385 	@Override
visit(SuperMethodReference node)386 	public boolean visit(SuperMethodReference node) {
387 		doVisitNode(node.getQualifier());
388 		doVisitChildren(node.typeArguments());
389 		return false;
390 	}
391 
392 	@Override
visit(TypeMethodReference node)393 	public boolean visit(TypeMethodReference node) {
394 		doVisitNode(node.getType());
395 		doVisitChildren(node.typeArguments());
396 		return false;
397 	}
398 
399 	@Override
visit(UsesDirective node)400 	public boolean visit(UsesDirective node) {
401 		possibleTypeRefFound(node.getName());
402 		return false;
403 	}
404 
405 	@Override
visit(ProvidesDirective node)406 	public boolean visit(ProvidesDirective node) {
407 		possibleTypeRefFound(node.getName());
408 		for (Object impl : node.implementations()) {
409 			possibleTypeRefFound((Name) impl);
410 		}
411 		return false;
412 	}
413 
414 	/*
415 	 * @see ASTVisitor#visit(SuperConstructorInvocation)
416 	 */
417 	@Override
visit(SuperConstructorInvocation node)418 	public boolean visit(SuperConstructorInvocation node) {
419 		if (!isAffected(node)) {
420 			return false;
421 		}
422 
423 		evalQualifyingExpression(node.getExpression(), null);
424 		doVisitChildren(node.typeArguments());
425 		doVisitChildren(node.arguments());
426 		return false;
427 	}
428 
429 	/*
430 	 * @see ASTVisitor#visit(FieldAccess)
431 	 */
432 	@Override
visit(FieldAccess node)433 	public boolean visit(FieldAccess node) {
434 		evalQualifyingExpression(node.getExpression(), node.getName());
435 		return false;
436 	}
437 
438 	/*
439 	 * @see ASTVisitor#visit(SimpleName)
440 	 */
441 	@Override
visit(SimpleName node)442 	public boolean visit(SimpleName node) {
443 		// if the call gets here, it can only be a variable reference
444 		possibleStaticImportFound(node);
445 		return false;
446 	}
447 
448 	@Override
visit(MarkerAnnotation node)449 	public boolean visit(MarkerAnnotation node) {
450 		typeRefFound(node.getTypeName());
451 		return false;
452 	}
453 
454 	@Override
visit(NormalAnnotation node)455 	public boolean visit(NormalAnnotation node) {
456 		typeRefFound(node.getTypeName());
457 		doVisitChildren(node.values());
458 		return false;
459 	}
460 
461 	@Override
visit(SingleMemberAnnotation node)462 	public boolean visit(SingleMemberAnnotation node) {
463 		typeRefFound(node.getTypeName());
464 		doVisitNode(node.getValue());
465 		return false;
466 	}
467 
468 	/*
469 	 * @see ASTVisitor#visit(TypeDeclaration)
470 	 */
471 	@Override
visit(TypeDeclaration node)472 	public boolean visit(TypeDeclaration node) {
473 		if (!isAffected(node)) {
474 			return false;
475 		}
476 		return true;
477 	}
478 
479 	/*
480 	 * @see ASTVisitor#visit(MethodDeclaration)
481 	 */
482 	@Override
visit(MethodDeclaration node)483 	public boolean visit(MethodDeclaration node) {
484 		if (!isAffected(node)) {
485 			return false;
486 		}
487 		doVisitNode(node.getJavadoc());
488 
489 		doVisitChildren(node.modifiers());
490 		doVisitChildren(node.typeParameters());
491 
492 		if (!node.isConstructor()) {
493 			doVisitNode(node.getReturnType2());
494 		}
495 		// name not visited
496 
497 		int apiLevel= node.getAST().apiLevel();
498 		if (apiLevel >= AST.JLS8) {
499 			doVisitNode(node.getReceiverType());
500 		}
501 		// receiverQualifier not visited:
502 		//   Enclosing class names cannot be shadowed by an import (qualification is always redundant).
503 		doVisitChildren(node.parameters());
504 		if (apiLevel >= AST.JLS8) {
505 			doVisitChildren(node.extraDimensions());
506 			doVisitChildren(node.thrownExceptionTypes());
507 		} else {
508 			Iterator<Name> iter= getThrownExceptions(node).iterator();
509 			while (iter.hasNext()) {
510 				typeRefFound(iter.next());
511 			}
512 		}
513 		if (!fSkipMethodBodies) {
514 			doVisitNode(node.getBody());
515 		}
516 		return false;
517 	}
518 
519 	/**
520 	 * @param decl method declaration
521 	 * @return thrown exception names
522 	 * @deprecated to avoid deprecation warnings
523 	 */
524 	@Deprecated
getThrownExceptions(MethodDeclaration decl)525 	private static List<Name> getThrownExceptions(MethodDeclaration decl) {
526 		return decl.thrownExceptions();
527 	}
528 
529 	@Override
visit(TagElement node)530 	public boolean visit(TagElement node) {
531 		String tagName= node.getTagName();
532 		List<? extends ASTNode> list= node.fragments();
533 		int idx= 0;
534 		if (tagName != null && !list.isEmpty()) {
535 			Object first= list.get(0);
536 			if (first instanceof Name) {
537 				if ("@throws".equals(tagName) || "@exception".equals(tagName)) {  //$NON-NLS-1$//$NON-NLS-2$
538 					typeRefFound((Name) first);
539 				} else if ("@see".equals(tagName) || "@link".equals(tagName) || "@linkplain".equals(tagName)) {  //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
540 					Name name= (Name) first;
541 					possibleTypeRefFound(name);
542 				}
543 				idx++;
544 			}
545 		}
546 		for (int i= idx; i < list.size(); i++) {
547 			doVisitNode(list.get(i));
548 		}
549 		return false;
550 	}
551 
552 	@Override
visit(MemberRef node)553 	public boolean visit(MemberRef node) {
554 		Name qualifier= node.getQualifier();
555 		if (qualifier != null) {
556 			typeRefFound(qualifier);
557 		}
558 		return false;
559 	}
560 
561 	@Override
visit(MethodRef node)562 	public boolean visit(MethodRef node) {
563 		Name qualifier= node.getQualifier();
564 		if (qualifier != null) {
565 			typeRefFound(qualifier);
566 		}
567 		List<MethodRefParameter> list= node.parameters();
568 		if (list != null) {
569 			doVisitChildren(list); // visit MethodRefParameter with Type
570 		}
571 		return false;
572 	}
573 
574 	@Override
visit(MethodRefParameter node)575 	public boolean visit(MethodRefParameter node) {
576 		doVisitNode(node.getType());
577 		return false;
578 	}
579 }
580