/** * 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); } }