View Javadoc

1   /***
2    *
3    * Copyright 2004 James Strachan
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   *
17   **/
18  package org.codehaus.groovy.syntax;
19  
20  import org.codehaus.groovy.ast.ClassHelper;
21  import org.codehaus.groovy.ast.ClassNode;
22  import org.codehaus.groovy.ast.ModuleNode;
23  import org.codehaus.groovy.control.SourceUnit;
24  
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  /***
31   * A common base class of AST helper methods which can be shared across the classic and new parsers
32   *
33   * @author Jochen Theodorou
34   * @author James Strachan
35   * @author Bob McWhirter
36   * @author Sam Pullara
37   * @author Chris Poirier
38   * @version $Revision: 1.10 $
39   */
40  public class ASTHelper {
41  
42      private static final String[] EMPTY_STRING_ARRAY = new String[0];
43  
44      /*** The SourceUnit controlling us */
45      private SourceUnit controller;
46  
47      /*** Our ClassLoader, which provides information on external types */
48      private ClassLoader classLoader;
49  
50      /*** Our imports, simple name => fully qualified name */
51      private Map imports;
52      protected ModuleNode output;
53  
54      /**</package-summary/html">The package name in which the module sits *//package-summary.html">em>* The package name in which the module sits */
55      privateong> String packageName;   //
56  
57      // TODO should this really be static???
58      protected static HashMap resolutions = new HashMap();  // cleared on build(), to be safe
59  
60      private static String NOT_RESOLVED = new String();
61  
62      /*** temporarily store the class names that the current modulenode contains */
63      private List newClasses = new ArrayList();
64  
65      public ASTHelper(SourceUnit controller, ClassLoader classLoader) {
66          this();
67          this.controller = controller;
68          this.classLoader = classLoader;
69      }
70  
71      public ASTHelper() {
72          imports = new HashMap();
73      }
74  
75      public String getPackageName() {
76          return</strong> packageName;
77      }
78  
79      publicong> void setPackageName(String packageName) {
80          this.packageName = packageName;
81          if (packageName!=null && packageName.length()>0){
82              packageName+='.';
83          }
84          output.setPackageName(packageName);
85      }
86  
87  
88      /***
89       * Returns our class loader (as supplied on construction).
90       */
91      public ClassLoader getClassLoader() {
92          return classLoader;
93      }
94  
95      public void setClassLoader(ClassLoader classLoader) {
96          this.classLoader = classLoader;
97      }
98  
99      public SourceUnit getController() {
100         return controller;
101     }
102 
103     public void setController(SourceUnit controller) {
104         this.controller = controller;
105     }
106     
107     /***
108      * Returns a fully qualified name for any given potential type
109      * name.  Returns null if no qualified name could be determined.
110      */
111 /*    protected String resolveName(String name, boolean safe) {
112         //
113         // Use our cache of resolutions, if possible
114 
115         String resolution = (String) resolutions.get(name);
116         if (NOT_RESOLVED.equals(resolution)) {
117             return (safe ? name : null);
118         }
119         else if (resolution != null) {
120             return (String) resolution;
121         }
122 
123         try {
124             getClassLoader().loadClass(name);
125             resolutions.put(name,name);
126             return name;
127         } catch (ClassNotFoundException cnfe){
128             if (cnfe.getCause() instanceof MultipleCompilationErrorsException) {
129                 MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) cnfe.getCause();
130                 controller.getErrorCollector().addCollectorContents(mcee.getErrorCollector());
131                 resolutions.put(name,name);
132                 return name;
133             }
134         } catch (NoClassDefFoundError ncdfe) {
135             //fall through
136         }
137 
138         do {
139             //
140             // If the type name contains a ".", it's probably fully
141             // qualified, and we don't take it to verification here.
142 
143             if (name.indexOf(".") >= 0) {
144                 resolution = name;
145                 break;                                            // <<< FLOW CONTROL <<<<<<<<<
146             }
147 
148 
149             //
150             // Otherwise, we'll need the scalar type for checking, and
151             // the postfix for reassembly.
152 
153             String scalar = name, postfix = "";
154             while (scalar.endsWith("[]")) {
155                 scalar = scalar.substring(0, scalar.length() - 2);
156                 postfix += "[]";
157             }
158 
159 
160             //
161             // Primitive types are all valid...
162 
163             if (Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE)) {
164                 resolution = name;
165                 break;                                            // <<< FLOW CONTROL <<<<<<<<<
166             }
167 
168 
169             //
170             // Next, check our imports and return the qualified name,
171             // if available.
172 
173             if (this.imports.containsKey(scalar)) {
174                 resolution = ((String) this.imports.get(scalar)) + postfix;
175                 break;                                            // <<< FLOW CONTROL <<<<<<<<<
176             }
177 
178 
179             //
180             // Next, see if our class loader can resolve it in the current package.
181 
182             if (packageName != null && packageName.length() > 0) {
183                 try {
184                     getClassLoader().loadClass(dot(packageName, scalar));
185                     resolution = dot(packageName, name);
186 
187                     break;                                        // <<< FLOW CONTROL <<<<<<<<<
188                 } catch (ClassNotFoundException cnfe){
189                     if (cnfe.getCause() instanceof CompilationFailedException) {
190                         resolution = dot(packageName, name);
191                         break;
192                     }
193                 } catch (NoClassDefFoundError ncdfe) {
194                     //fall through
195                 }
196             }
197 
198             // search the package imports path
199             List packageImports = output.getImportPackages();
200             for (int i = 0; i < packageImports.size(); i++) {
201                 String pack = (String) packageImports.get(i);
202                 String clsName = pack + name;
203                 try {
204                     getClassLoader().loadClass(clsName);
205                     resolution = clsName;
206                     break;
207                 } catch (ClassNotFoundException cnfe){
208                     if (cnfe.getCause() instanceof CompilationFailedException) {
209                         resolution = clsName;
210                         break;
211                     }
212                 } catch (NoClassDefFoundError ncdfe) {
213                     //fall through
214                 }
215             }
216             if (resolution != null) {
217                 break;
218             }
219 
220             //
221             // Last chance, check the default imports.
222 
223             for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
224                 String qualified = DEFAULT_IMPORTS[i] + scalar;
225                 try {
226                     getClassLoader().loadClass(qualified);
227 
228                     resolution = qualified + postfix;
229                     break;                                        // <<< FLOW CONTROL <<<<<<<<<
230                 } catch (ClassNotFoundException cnfe){
231                     if (cnfe.getCause() instanceof CompilationFailedException) {
232                         resolution = qualified + postfix;
233                         break;
234                     }
235                 } catch (NoClassDefFoundError ncdfee) {
236                     // fall through
237                 }
238             }
239 
240         }
241         while (false);
242 
243 
244         //
245         // Cache the solution and return it
246 
247         if (resolution == null) {
248             resolutions.put(name, NOT_RESOLVED);
249             return (safe ? name : null);
250         }
251         else {
252             resolutions.put(name, resolution);
253             return resolution;
254         }
255     }
256 */
257     
258     /***
259      * Returns two names joined by a dot.  If the base name is
260      * empty, returns the name unchanged.
261      */
262     public static String dot(String base, String name) {
263         if (base != null && base.length() > 0) {
264             return base + "." + name;
265         }
266 
267         return name;
268     }
269 
270     protected void makeModule() {
271         this.newClasses.clear();
272         this.output = new ModuleNode(controller);
273         resolutions.clear();
274     }
275 
276     /***
277      * A synonym for <code>dot( base, "" )</code>.
278      */
279     protected String dot(String base) {
280         return dot(base, "");
281     }
282 
283     /*protected String resolveNewClassOrName(String name, boolean safe) {
284         if (this.newClasses.contains(name)) {
285             return dot(packageName, name);
286         }
287         else {
288             return resolveName(name, safe);
289         }
290     }*/
291 
292     protected void addNewClassName(String name) {
293         this.newClasses.add(name);
294     }
295 
296     protected void importClass(ClassNode type, String name, String as) {
297         if (as==null) as=name;
298 
299         output.addImport(as, type); 
300         imports.put(as, type);
301     }
302 
303     protected void importPackageWithStar(String importPackage) {
304         String[] classes = output.addImportPackage( dot(importPackage) );
305         for( int i = 0; i < classes.length; i++ )
306         {
307             imports.put( classes[i], dot(importPackage, classes[i]) );
308         }
309     }
310 }