View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.symboltable;
5   
6   
7   import java.util.Collections;
8   import java.util.HashMap;
9   import java.util.HashSet;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Set;
13  
14  import net.sourceforge.pmd.lang.ast.Node;
15  import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
16  import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
17  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
18  import net.sourceforge.pmd.lang.symboltable.Scope;
19  
20  /**
21   * This scope is the outer most scope of a Java file.
22   * A Source File can contain one ore more classes.
23   */
24  public class SourceFileScope extends AbstractJavaScope {
25  
26      private String packageImage;
27      private TypeSet types;
28  
29      public SourceFileScope() {
30          this("");
31      }
32  
33      public SourceFileScope(String packageImage) {
34          this.packageImage = packageImage;
35      }
36  
37      /**
38       * Configures the type resolution for the symbol table.
39       * @param classLoader the class loader to use to find additional classes
40       * @param imports the import declarations
41       */
42      public void configureImports(ClassLoader classLoader, List<ASTImportDeclaration> imports) {
43          this.types = new TypeSet(classLoader);
44          types.setASTCompilationUnitPackage(packageImage);
45          for (ASTImportDeclaration i : imports) {
46              if (i.isImportOnDemand()) {
47                  types.addImport(i.getImportedName() + ".*");
48              } else {
49                  types.addImport(i.getImportedName());
50              }
51          }
52      }
53  
54      public Set<String> getExplicitImports() {
55          return types != null ? types.getExplicitImports() : Collections.<String> emptySet();
56      }
57  
58      /**
59       * Whether an auxclasspath has been configured or not.
60       * This can be used to enable/disable more detailed symbol table analysis and type resolution
61       * can be used - or to fall back to more simple implementation.
62       * @return <code>true</code> if the auxclasspath is configured and types can be resolved reliably.
63       * @see #resolveType(String)
64       */
65      public boolean hasAuxclasspath() {
66          return types.hasAuxclasspath();
67      }
68  
69      /**
70       * Tries to resolve a class by name.
71       * @param name the name of the class
72       * @return the class or <code>null</code> if no class could be found
73       */
74      public Class<?> resolveType(String name) {
75          try {
76              return types.findClass(name);
77          } catch (ClassNotFoundException e) {
78              return null;
79          }
80      }
81  
82      public String getPackageName() {
83          return packageImage;
84      }
85  
86      /**
87       * {@inheritDoc}
88       * @throws IllegalArgumentException if declaration is not a {@link ClassNameDeclaration}
89       */
90      @Override
91      public void addDeclaration(NameDeclaration declaration) {
92          if (!(declaration instanceof ClassNameDeclaration)) {
93              throw new IllegalArgumentException("A SourceFileScope can only contain classes.");
94          }
95          super.addDeclaration(declaration);
96      }
97  
98      /**
99       * Convenience method that casts the declarations to {@link ClassNameDeclaration}s.
100      * @see #getDeclarations()
101      * @return all class name declarations
102      */
103     public Map<ClassNameDeclaration, List<NameOccurrence>> getClassDeclarations() {
104         return getDeclarations(ClassNameDeclaration.class);
105     }
106 
107     public String toString() {
108         return "SourceFileScope: " + glomNames(getClassDeclarations().keySet());
109     }
110 
111     public ClassNameDeclaration findClassNameDeclaration(String name) {
112         ImageFinderFunction finder = new ImageFinderFunction(name);
113         Applier.apply(finder, getClassDeclarations().keySet().iterator());
114         return (ClassNameDeclaration)finder.getDecl();
115     }
116 
117     protected Set<NameDeclaration> findVariableHere(JavaNameOccurrence occ) {
118         Set<NameDeclaration> result = new HashSet<>();
119         ImageFinderFunction finder = new ImageFinderFunction(occ.getImage());
120         Applier.apply(finder, getDeclarations().keySet().iterator());
121         if (finder.getDecl() != null) {
122             result.add(finder.getDecl());
123         }
124         return result;
125     }
126 
127     /**
128      * Returns a set of all types defined within this source file.
129      * This includes all top-level types and nested types.
130      * @return set of all types in this source file.
131      */
132     public Map<String, Node> getQualifiedTypeNames() {
133         return getSubTypes(null, this);
134     }
135 
136     private Map<String, Node> getSubTypes(String qualifyingName, Scope subType) {
137         Map<String, Node> types = new HashMap<>();
138         for (ClassNameDeclaration c : subType.getDeclarations(ClassNameDeclaration.class).keySet()) {
139             String typeName = c.getName();
140             if (qualifyingName != null) {
141                 typeName = qualifyingName + "." + typeName;
142             }
143             types.put(typeName, c.getNode());
144             types.putAll(getSubTypes(typeName, c.getScope()));
145         }
146         return types;
147     }
148 }