View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.symboltable;
    5
    6   import net.sourceforge.pmd.ast.*;
    7
    8   import java.util.List;
    9   import java.util.Stack;
    10
    11  /***
    12   * Visitor for scope creation.
    13   * Visits all nodes of an AST and creates scope objects for nodes representing
    14   * syntactic entities which may contain declarations. For example, a block
    15   * may contain variable definitions (which are declarations) and
    16   * therefore needs a scope object where these declarations can be associated,
    17   * whereas an expression can't contain declarations and therefore doesn't need
    18   * a scope object.
    19   * With the exception of global scopes, each scope object is linked to its
    20   * parent scope, which is the scope object of the next embedding syntactic
    21   * entity that has a scope.
    22   */
    23  public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
    24
    25      /***
    26       * A stack of scopes reflecting the scope hierarchy when a node is visited.
    27       * This is used to set the parents of the created scopes correctly.
    28       */
    29      private Stack scopes = new Stack();
    30
    31      /***
    32       * Sets the scope of a node and adjustes the scope stack accordingly.
    33       * The scope on top of the stack is set as the parent of the given scope,
    34       * which is then also stored on the scope stack.
    35       *
    36       * @param newScope the scope for the node.
    37       * @param node     the AST node for which the scope is to be set.
    38       * @throws java.util.EmptyStackException if the scope stack is empty.
    39       */
    40      private void addScope(Scope newScope, SimpleNode node) {
    41          newScope.setParent((Scope) scopes.peek());
    42          scopes.push(newScope);
    43          node.setScope(newScope);
    44      }
    45
    46      /***
    47       * Creates a new local scope for an AST node.
    48       * The scope on top of the stack is set as the parent of the new scope,
    49       * which is then also stored on the scope stack.
    50       *
    51       * @param node the AST node for which the scope has to be created.
    52       * @throws java.util.EmptyStackException if the scope stack is empty.
    53       */
    54      private void createLocalScope(SimpleNode node) {
    55          addScope(new LocalScope(), node);
    56      }
    57
    58      /***
    59       * Creates a new method scope for an AST node.
    60       * The scope on top of the stack is set as the parent of the new scope,
    61       * which is then also stored on the scope stack.
    62       *
    63       * @param node the AST node for which the scope has to be created.
    64       * @throws java.util.EmptyStackException if the scope stack is empty.
    65       */
    66      private void createMethodScope(SimpleNode node) {
    67          addScope(new MethodScope(node), node);
    68      }
    69
    70      /***
    71       * Creates a new class scope for an AST node.
    72       * The scope on top of the stack is set as the parent of the new scope,
    73       * which is then also stored on the scope stack.
    74       *
    75       * @param node the AST node for which the scope has to be created.
    76       * @throws java.util.EmptyStackException if the scope stack is empty.
    77       */
    78      private void createClassScope(SimpleNode node) {
    79          if (node instanceof ASTClassOrInterfaceBodyDeclaration) {
    80              addScope(new ClassScope(), node);
    81          } else {
    82              addScope(new ClassScope(node.getImage()), node);
    83          }
    84      }
    85
    86      /***
    87       * Creates a new global scope for an AST node.
    88       * The new scope is stored on the scope stack.
    89       *
    90       * @param node the AST node for which the scope has to be created.
    91       */
    92      private void createSourceFileScope(SimpleNode node) {
    93          // When we do full symbol resolution, we'll need to add a truly top-level GlobalScope.
    94          Scope scope;
    95          List packages = node.findChildrenOfType(ASTPackageDeclaration.class);
    96          if</strong> (!packages.isEmpty()) {
    97              Node n = (Node) packages/get(0)/package-summary.html">Node n = (Node) packages.get(0);
    98              scope = new SourceFileScope(((SimpleNode) n.jjtGetChild(0)).getImage());
    99          } else {
    100             scope = new SourceFileScope();
    101         }
    102         scopes.push(scope);
    103         node.setScope(scope);
    104     }
    105
    106     public Object visit(ASTCompilationUnit node, Object data) {
    107         createSourceFileScope(node);
    108         cont(node);
    109         return data;
    110     }
    111
    112     public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
    113         createClassScope(node);
    114         Scope s = ((SimpleNode) node.jjtGetParent()).getScope();
    115         s.addDeclaration(new ClassNameDeclaration(node));
    116         cont(node);
    117         return data;
    118     }
    119
    120     public Object visit(ASTEnumDeclaration node, Object data) {
    121         createClassScope(node);
    122         cont(node);
    123         return data;
    124     }
    125
    126     public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
    127         if (node.isAnonymousInnerClass() || node.isEnumChild()) {
    128             createClassScope(node);
    129             cont(node);
    130         } else {
    131             super.visit(node, data);
    132         }
    133         return data;
    134     }
    135
    136     public Object visit(ASTBlock node, Object data) {
    137         createLocalScope(node);
    138         cont(node);
    139         return data;
    140     }
    141
    142     public Object visit(ASTCatchStatement node, Object data) {
    143         createLocalScope(node);
    144         cont(node);
    145         return data;
    146     }
    147
    148     public Object visit(ASTFinallyStatement node, Object data) {
    149         createLocalScope(node);
    150         cont(node);
    151         return data;
    152     }
    153
    154     public Object visit(ASTConstructorDeclaration node, Object data) {
    155         createMethodScope(node);
    156         cont(node);
    157         return data;
    158     }
    159
    160     public Object visit(ASTMethodDeclaration node, Object data) {
    161         createMethodScope(node);
    162         ASTMethodDeclarator md = (ASTMethodDeclarator) node.getFirstChildOfType(ASTMethodDeclarator.class);
    163         node.getScope().getEnclosingClassScope().addDeclaration(new MethodNameDeclaration(md));
    164         cont(node);
    165         return data;
    166     }
    167
    168     public Object visit(ASTTryStatement node, Object data) {
    169         createLocalScope(node);
    170         cont(node);
    171         return data;
    172     }
    173
    174     // TODO - what about while loops and do loops?
    175     public Object visit(ASTForStatement node, Object data) {
    176         createLocalScope(node);
    177         cont(node);
    178         return data;
    179     }
    180
    181     public Object visit(ASTIfStatement node, Object data) {
    182         createLocalScope(node);
    183         cont(node);
    184         return data;
    185     }
    186
    187     public Object visit(ASTVariableDeclaratorId node, Object data) {
    188         VariableNameDeclaration decl = new VariableNameDeclaration(node);
    189         node.getScope().addDeclaration(decl);
    190         node.setNameDeclaration(decl);
    191         return super.visit(node, data);
    192     }
    193
    194     public Object visit(ASTSwitchStatement node, Object data) {
    195         createLocalScope(node);
    196         cont(node);
    197         return data;
    198     }
    199
    200     private void cont(SimpleJavaNode node) {
    201         super.visit(node, null);
    202         scopes.pop();
    203     }
    204 }