All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.sourceforge.pmd.lang.plsql.symboltable.ScopeAndDeclarationFinder Maven / Gradle / Ivy
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.symboltable;
import java.util.ArrayDeque;
import java.util.Deque;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sourceforge.pmd.lang.plsql.ast.ASTBlock;
import net.sourceforge.pmd.lang.plsql.ast.ASTDeclarativeUnit;
import net.sourceforge.pmd.lang.plsql.ast.ASTForAllStatement;
import net.sourceforge.pmd.lang.plsql.ast.ASTForStatement;
import net.sourceforge.pmd.lang.plsql.ast.ASTID;
import net.sourceforge.pmd.lang.plsql.ast.ASTInput;
import net.sourceforge.pmd.lang.plsql.ast.ASTMethodDeclarator;
import net.sourceforge.pmd.lang.plsql.ast.ASTObjectDeclaration;
import net.sourceforge.pmd.lang.plsql.ast.ASTObjectNameDeclaration;
import net.sourceforge.pmd.lang.plsql.ast.ASTPackageBody;
import net.sourceforge.pmd.lang.plsql.ast.ASTPackageSpecification;
import net.sourceforge.pmd.lang.plsql.ast.ASTProgramUnit;
import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerTimingPointSection;
import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerUnit;
import net.sourceforge.pmd.lang.plsql.ast.ASTTypeMethod;
import net.sourceforge.pmd.lang.plsql.ast.ASTTypeSpecification;
import net.sourceforge.pmd.lang.plsql.ast.ASTVariableOrConstantDeclaratorId;
import net.sourceforge.pmd.lang.plsql.ast.InternalApiBridge;
import net.sourceforge.pmd.lang.plsql.ast.PLSQLNode;
import net.sourceforge.pmd.lang.plsql.ast.PlsqlVisitorBase;
import net.sourceforge.pmd.lang.symboltable.Scope;
/**
* Visitor for scope creation. Visits all nodes of an AST and creates scope
* objects for nodes representing syntactic entities which may contain
* declarations. For example, a block may contain variable definitions (which
* are declarations) and therefore needs a scope object where these declarations
* can be associated, whereas an expression can't contain declarations and
* therefore doesn't need a scope object. With the exception of global scopes,
* each scope object is linked to its parent scope, which is the scope object of
* the next embedding syntactic entity that has a scope.
*/
public class ScopeAndDeclarationFinder extends PlsqlVisitorBase {
private static final Logger LOG = LoggerFactory.getLogger(ScopeAndDeclarationFinder.class);
/**
* A stack of scopes reflecting the scope hierarchy when a node is visited.
* This is used to set the parents of the created scopes correctly.
*/
private Deque scopes = new ArrayDeque<>();
/**
* Sets the scope of a node and adjusts the scope stack accordingly. The
* scope on top of the stack is set as the parent of the given scope, which
* is then also stored on the scope stack.
*
* @param newScope
* the scope for the node.
* @param node
* the AST node for which the scope is to be set.
* @throws java.util.EmptyStackException
* if the scope stack is empty.
*/
private void addScope(Scope newScope, PLSQLNode node) {
newScope.setParent(scopes.peek());
scopes.push(newScope);
InternalApiBridge.setScope(node, newScope);
}
/**
* Creates a new local scope for an AST node. The scope on top of the stack
* is set as the parent of the new scope, which is then also stored on the
* scope stack.
*
* @param node
* the AST node for which the scope has to be created.
* @throws java.util.EmptyStackException
* if the scope stack is empty.
*/
private void createLocalScope(PLSQLNode node) {
addScope(new LocalScope(), node);
}
/**
* Creates a new method scope for an AST node. The scope on top of the stack
* is set as the parent of the new scope, which is then also stored on the
* scope stack.
*
* @param node
* the AST node for which the scope has to be created.
* @throws java.util.EmptyStackException
* if the scope stack is empty.
*/
private void createMethodScope(PLSQLNode node) {
addScope(new MethodScope(node), node);
}
/**
* Creates a new class scope for an AST node. The scope on top of the stack
* is set as the parent of the new scope, which is then also stored on the
* scope stack.
*
* @param node
* the AST node for which the scope has to be created.
* @throws java.util.EmptyStackException
* if the scope stack is empty.
*/
private void createClassScope(PLSQLNode node) {
if (node instanceof ASTDeclarativeUnit) {
addScope(new ClassScope(), node);
} else {
addScope(new ClassScope(node.getImage()), node);
}
}
/**
* Creates a new global scope for an AST node. The new scope is stored on
* the scope stack.
*
* @param node
* the AST node for which the scope has to be created.
*/
private void createSourceFileScope(ASTInput node) {
// When we do full symbol resolution, we'll need to add a truly
// top-level GlobalScope.
Scope scope;
// %TODO generate a SchemaScope, based on inferred or explicitly
// specified SchemaName
ASTObjectDeclaration n = null; // node.getPackageDeclaration();
if (n != null) {
scope = new SourceFileScope(n.getChild(0).getImage());
} else {
scope = new SourceFileScope();
}
scopes.push(scope);
InternalApiBridge.setScope(node, scope);
}
@Override
public Object visit(ASTInput node, Object data) {
createSourceFileScope(node);
cont(node);
return data;
}
@Override
public Object visit(ASTPackageSpecification node, Object data) {
createClassScope(node);
Scope s = ((PLSQLNode) node.getParent()).getScope();
s.addDeclaration(new ClassNameDeclaration(node));
cont(node);
return data;
}
@Override
public Object visit(ASTPackageBody node, Object data) {
createClassScope(node);
Scope s = ((PLSQLNode) node.getParent()).getScope();
s.addDeclaration(new ClassNameDeclaration(node));
cont(node);
return data;
}
@Override
public Object visit(ASTTypeSpecification node, Object data) {
createClassScope(node);
Scope s = ((PLSQLNode) node.getParent()).getScope();
s.addDeclaration(new ClassNameDeclaration(node));
cont(node);
return data;
}
@Override
public Object visit(ASTTriggerUnit node, Object data) {
createClassScope(node);
Scope s = ((PLSQLNode) node.getParent()).getScope();
s.addDeclaration(new ClassNameDeclaration(node));
cont(node);
return data;
}
/*
* @Override public Object visit(ASTCompoundTriggerBlock node, Object data)
* { createMethodScope(node); ASTMethodDeclarator md =
* node.getFirstChildOfType(ASTMethodDeclarator.class);
* node.getScope().getEnclosingClassScope().addDeclaration(new
* MethodNameDeclaration(md)); cont(node); return data; }
*/
@Override
public Object visit(ASTTriggerTimingPointSection node, Object data) {
createMethodScope(node);
// Treat a Timing Point Section like a packaged FUNCTION or PROCEDURE
node.getScope().getEnclosingScope(ClassScope.class).addDeclaration(new MethodNameDeclaration(node));
cont(node);
return data;
}
// @Override
// public Object visit(ASTEnumDeclaration node, Object data) {
// createClassScope(node);
// cont(node);
// return data;
// }
// @Override
// public Object visit(ASTAnnotationTypeDeclaration node, Object data) {
// createClassScope(node);
// cont(node);
// return data;
// }
@Override
public Object visit(ASTObjectDeclaration node, Object data) {
super.visit(node, data);
return data;
}
@Override
public Object visit(ASTBlock node, Object data) {
createLocalScope(node);
cont(node);
return data;
}
/*
* @Override public Object visit(ASTMethodDeclaration node, Object data) {
* createMethodScope(node); // // A method declaration my be- //
* ASTProgramUnit - a standalone or packaged FUNCTION or PROCEDURE //
* ASTTypeMethod - an OBJECT TYPE method // // The Method declarator is
* below the ASTProgramUnit / ASTTypeMethod /// List
* methodDeclarators =
* node.findDescendantsOfType(ASTMethodDeclarator.class); if
* (!methodDeclarators.isEmpty() ) { //Use first Declarator in the list
* ASTMethodDeclarator md = methodDeclarators.get(0);
* LOGGER.finest("ClassScope skipped for Schema-level method: methodName=" +
* node.getMethodName() + "; Image=" + node.getImage() );
*
* } //ASTMethodDeclarator md =
* node.getFirstChildOfType(ASTMethodDeclarator.class); // A PLSQL Method
* (FUNCTION|PROCEDURE) may be schema-level try {
* node.getScope().getEnclosingClassScope().addDeclaration(new
* MethodNameDeclaration(md)); } catch (Exception e) { //@TODO possibly add
* to a pseudo-ClassScope equivalent to the Schema name
* LOGGER.finest("ProgramUnit getEnclosingClassScope Exception string=\""+e.
* getMessage()+"\"");
* if("getEnclosingClassScope() called on SourceFileScope".equals(e.
* getMessage())) {
* LOGGER.finest("ClassScope skipped for Schema-level method: methodName=" +
* node.getMethodName() + "; Image=" + node.getImage() );
*
* //A File-level/Schema-level object may have a Schema-name explicitly
* specified in the declaration ASTObjectNameDeclaration on =
* md.getFirstChildOfType(ASTObjectNameDeclaration.class); if( 1 <
* on.getNumChildren()) { ASTID schemaName =
* on.getFirstChildOfType(ASTID.class);
* LOGGER.finest("SchemaName for Schema-level method: methodName=" +
* node.getMethodName() + "; Image=" + node.getImage() + "is " +
* schemaName.getImage() );
*
* } } } cont(node); return data; }
*/
private Object visitMethodLike(PLSQLNode node, Object data) {
createMethodScope(node);
final ASTMethodDeclarator md = node.firstChild(ASTMethodDeclarator.class);
// A PLSQL Method (FUNCTION|PROCEDURE) may be schema-level
try {
node.getScope().getEnclosingScope(ClassScope.class).addDeclaration(new MethodNameDeclaration(md));
} catch (Exception e) {
// @TODO possibly add to a pseudo-ClassScope equivalent to the
// Schema name
LOG.trace("ProgramUnit getEnclosingClassScope Exception string=\"{}\"", e.getMessage());
if ("getEnclosingClassScope() called on SourceFileScope".equals(e.getMessage())) {
LOG.trace("ClassScope skipped for Schema-level method: methodName={}; Image={}",
md.getImage(), node.getImage());
// A File-level/Schema-level object may have a Schema-name
// explicitly specified in the declaration
ASTObjectNameDeclaration on = md.firstChild(ASTObjectNameDeclaration.class);
if (1 < on.getNumChildren()) {
ASTID schemaName = on.firstChild(ASTID.class);
LOG.trace("SchemaName for Schema-level method: methodName={}; Image={} is {}",
md.getImage(), node.getImage(), schemaName.getImage());
}
}
}
cont(node);
return data;
}
@Override
public Object visit(ASTTypeMethod node, Object data) {
return visitMethodLike(node, data);
}
@Override
public Object visit(ASTProgramUnit node, Object data) {
return visitMethodLike(node, data);
}
// TODO - what about while loops and do loops?
@Override
public Object visit(ASTForStatement node, Object data) {
createLocalScope(node);
cont(node);
return data;
}
@Override
public Object visit(ASTForAllStatement node, Object data) {
createLocalScope(node);
cont(node);
return data;
}
@Override
public Object visit(ASTVariableOrConstantDeclaratorId node, Object data) {
VariableNameDeclaration decl = new VariableNameDeclaration(node);
node.getScope().addDeclaration(decl);
InternalApiBridge.setNameDeclaration(node, decl);
return super.visit(node, data);
}
// @Override
// public Object visit(ASTSwitchStatement node, Object data) {
// createLocalScope(node);
// cont(node);
// return data;
// }
private void cont(PLSQLNode node) {
super.visitPlsqlNode(node, null);
scopes.pop();
}
}