/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.plsql.symboltable; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import net.sourceforge.pmd.lang.plsql.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.plsql.ast.PLSQLParserVisitorAdapter; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; import net.sourceforge.pmd.lang.symboltable.Scope; public class OccurrenceFinder extends PLSQLParserVisitorAdapter { private static final Logger LOGGER = Logger.getLogger(OccurrenceFinder.class.getName()); @Override public Object visit(ASTPrimaryExpression node, Object data) { NameFinder nameFinder = new NameFinder(node); // Maybe do some sort of State pattern thingy for when NameDeclaration // is empty/not empty Set<NameDeclaration> declarations = new HashSet<>(); List<PLSQLNameOccurrence> names = nameFinder.getNames(); for (PLSQLNameOccurrence 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 { Set<NameDeclaration> additionalDeclarations = new HashSet<>(); for (NameDeclaration decl : declarations) { // now we've got a scope we're starting with, so work from // there Scope scope = decl.getScope(); if (null == scope) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("NameOccurrence has no Scope:" + decl.getClass().getCanonicalName() + "=>" + decl.getImage()); } break; } search.execute(scope); Set<NameDeclaration> found = search.getResult(); additionalDeclarations.addAll(found); if (found.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); } }