/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.symboltable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.Scope;
public class OccurrenceFinder extends JavaParserVisitorAdapter {
// Maybe do some sort of State pattern thingy for when NameDeclaration
// is empty/not empty?
private final Set<NameDeclaration> declarations = new HashSet<>();
private final Set<NameDeclaration> additionalDeclarations = new HashSet<>();
public Object visit(ASTPrimaryExpression node, Object data) {
NameFinder nameFinder = new NameFinder(node);
declarations.clear();
additionalDeclarations.clear();
List<JavaNameOccurrence> names = nameFinder.getNames();
for (JavaNameOccurrence occ : names) {
Search search = new Search(occ);
if (declarations.isEmpty()) {
// doing the first name lookup
search.execute();
declarations.addAll(search.getResult());
if (declarations.isEmpty()) {
// we can't find it, so just give up
// when we decide to do full symbol resolution
// force this to either find a symbol or throw a
// SymbolNotFoundException
break;
}
} else {
for (NameDeclaration decl : declarations) {
// now we've got a scope we're starting with, so work from
// there
Scope startingScope = decl.getScope();
// in case the previous found declaration is a class
// reference
// for a class inside the same source file
// we need to search this class
// e.g. the list of name occurrence could come from
// outerClassRef.member. See also bug #1302
if (decl instanceof VariableNameDeclaration) {
String typeImage = ((VariableNameDeclaration) decl).getTypeImage();
ClassNameDeclaration clazzDeclaration = startingScope.getEnclosingScope(SourceFileScope.class)
.findClassNameDeclaration(typeImage);
if (clazzDeclaration != null) {
startingScope = clazzDeclaration.getScope();
}
}
search.execute(startingScope);
Set<NameDeclaration> result = search.getResult();
additionalDeclarations.addAll(result);
if (result.isEmpty()) {
// nothing found
// This seems to be a lack of type resolution here.
// Theoretically we have the previous declaration node
// and
// know from there the Type of
// the variable. The current occurrence (occ) should
// then be
// found in the declaration of
// this type. The type however may or may not be known
// to
// PMD (see aux classpath).
// we can't find it, so just give up
// when we decide to do full symbol resolution
// force this to either find a symbol or throw a
// SymbolNotFoundException
break;
}
}
declarations.addAll(additionalDeclarations);
}
}
return super.visit(node, data);
}
}