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