Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/puppycrawl/tools/checkstyle/checks/usage/transmogrify/TableMaker.java


1   
2   // Transmogrify License
3   // 
4   // Copyright (c) 2001, ThoughtWorks, Inc.
5   // All rights reserved.
6   // Redistribution and use in source and binary forms, with or without
7   // modification, are permitted provided that the following conditions
8   // are met:
9   // - Redistributions of source code must retain the above copyright notice,
10  //   this list of conditions and the following disclaimer.
11  // - Redistributions in binary form must reproduce the above copyright
12  // notice, this list of conditions and the following disclaimer in the
13  // documentation and/or other materials provided with the distribution.
14  // Neither the name of the ThoughtWorks, Inc. nor the names of its
15  // contributors may be used to endorse or promote products derived from this
16  // software without specific prior written permission.
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  
29  package com.puppycrawl.tools.checkstyle.checks.usage.transmogrify;
30  
31  import java.io.File;
32  import java.util.Enumeration;
33  import java.util.Vector;
34  
35  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36  
37  
38  
39  
40  /**
41   * this is the class that does the work of the "walking" step --
42   * going through the SymTabAST and constructing the definitions and
43   * references.  The SymTabAST is constructed in a DOMish fashion, i.e.
44   * each node knows about its first child and its next sibling.  The
45   * DFS search is carried out by two functions -- walkTree, which
46   * deals with a single SymTabAST node, and walkSibilngs, which deals with
47   * all the siblings of an SymTabAST node.
48   */
49  
50  public class TableMaker {
51    private SymbolTable symbolTable;
52    private SymTabAST _tree;
53    private File currentFile;
54    private Vector imports = new Vector();
55  
56    /**
57     * Constructor for the TableMaker class
58     *
59     * @param tree is the<code>SymTabAST</code> from which to
60     * build the <code>TableMaker</code>. It is the tree which wil be walked
61     * in order to build definitions and references.
62     */
63    public TableMaker(SymTabAST tree)
64    {
65      _tree = tree;
66    }
67  
68    /**
69     * returns the <code> SymTabAST </code> which is the
70     * SymTabAST generated from the parsed Java Source files.
71     *
72     * @return <code>SymTabAST</code>
73     */
74    public SymTabAST getTree() {
75      return _tree;
76    }
77  
78    /**
79     * returns the <code>SymbolTable</code> that has been constructed by
80     * this <code>TableMaker</code>
81     *
82     * @return <code>SymbolTable</code>
83     * @throws <code>SymbolTableException</code>
84     */
85    public SymbolTable getTable() throws SymbolTableException {
86      if (symbolTable == null) {
87        symbolTable = new SymbolTable( _tree );
88  
89        createDefinitions();
90  
91        resolveReferences();
92      }
93  
94      return symbolTable;
95    }
96  
97    /**
98     * walks the tree and finishes creating definitions.
99     *
100    * @return <code>void</code>
101    * @throws <code>SymbolTableException</code>
102    * @see #walkTree()
103    * @see #finishCreatingDefinitions()
104    */
105   private void createDefinitions() throws SymbolTableException {
106     walkTree();
107     finishCreatingDefinitions();
108   }
109 
110   /**
111    * finishes up creating definitions process
112    * starts at the base of the Table
113    *
114    * @return <code>void</code>
115    * @throws <code>SymbolTableException</code>
116    * @see net.sourceforge.transmogrify.symtab.SymbolTable
117    * @see #finishCreatingDefinition(Definition)
118    */
119   private void finishCreatingDefinitions() throws SymbolTableException {
120     finishCreatingDefinition(symbolTable.getBaseScope());
121   }
122 
123   /**
124    * begins at the base of the Table and starts finishing definition creation.
125    *
126    * @param def <code>Definition</code> needs to be completed
127    * @return <code>void</code>
128    * @throws <code>SymbolTableException</code>
129    * @see ClassFinisher
130    * @see VariableFinisher
131    * @see MethodFinisher
132    * @see CatchFinisher
133    */
134   private void finishCreatingDefinition(Definition def) throws SymbolTableException {
135 
136     if (def instanceof AnonymousInnerClass) {
137       AnonymousInnerClass innerClass = (AnonymousInnerClass)def;
138       innerClass.finishMakingDefinition();
139     }
140     else if (def instanceof ClassDef) {
141       new ClassFinisher((ClassDef)def).finish();
142     }
143     else if ( def instanceof VariableDef ) {
144       new VariableFinisher( (VariableDef)def ).finish();
145     }
146     else if (def instanceof DefaultConstructor) {}
147     else if ( def instanceof MethodDef ) {
148       new MethodFinisher( (MethodDef)def ).finish();
149     }
150     else if (def instanceof BlockDef) {
151       SymTabAST firstChild = (SymTabAST)def.getTreeNode().getFirstChild();
152       //handle Checkstyle grammar
153       if (firstChild.getType() == TokenTypes.LPAREN) {
154           firstChild = (SymTabAST) firstChild.getNextSibling();
155       }
156       if (firstChild.getType() == TokenTypes.PARAMETER_DEF) {
157         // this is a catch block
158         new CatchFinisher((BlockDef)def).finish();
159       }
160     }
161 
162     if ( def instanceof Scope ) {
163       finishCreatingChildren((Scope)def);
164     }
165   }
166 
167 
168   /**
169    * iterates through all the definitions in the <code> Scope </code>
170    * finishes creating each <code>Scope</code>.
171    *
172    * @param scope <code> Scope </code> where defininitions will be finished.
173    * @return <code>void</code>
174    * @throws <code>SymbolTableException</code>
175    * @see net.sourceforge.transmogrify.symtab.Scope
176    * @see #finishCreatingDefinition(Definition)
177    */
178   private void finishCreatingChildren( Scope scope ) throws SymbolTableException {
179     Enumeration definitions = scope.getDefinitions();
180     while ( definitions.hasMoreElements() ) {
181       Definition child = (Definition)(definitions.nextElement());
182       finishCreatingDefinition(child);
183     }
184   }
185 
186   /**
187    * resolves <code>SymbolTable</code> using <code>Resolver</code>
188    *
189    * @return <code>void</code>
190    * @see net.sourceforge.transmogrify.symtab.Resolver
191    * @see net.sourceforge.transmogrify.symtab.SymbolTable
192    */
193   private void resolveReferences() {
194     new Resolver( symbolTable ).resolve();
195   }
196 
197   /**
198    * starts walking the <code> SymTabAST </code>
199    *
200    * @return <code>void</code>
201    * @see #walkSiblings(SymTabAST,boolean)
202    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
203    */
204   public void walkTree() {
205     walkSiblings((SymTabAST)_tree.getFirstChild(), false);
206   }
207 
208   /**
209    * processes a single SymTabAST node based on its type and passes of its
210    * children for further processing where appropriate.
211    *
212    * @param tree the <code>SymTabAST</code> node to process
213    * @param makeAnonymousScopes sets to <code>false</code> after walking Class,
214    *                            Methods and Try otherwise sets to <code>true</code>
215    * @return <code>void</code>
216    * @see #walkSiblings(SymTabAST, boolean)
217    * @see #processAnonymousInnerClass(SymTabAST, SymTabAST)
218    * @see #processBlock(SymTabAST, boolean)
219    * @see #processClass(SymTabAST)
220    * @see #processConstructorDef(SymTabAST)
221    * @see #processElse(SymTabAST)
222    * @see #processFile(SymTabAST)
223    * @see #processFinally(SymTabAST)
224    * @see #processFor(SymTabAST)
225    * @see #processImplicitPackage(SymTabAST)
226    * @see #processImport(SymTabAST)
227    * @see #processLabel(SymTabAST)
228    * @see #processMethodDef(SymTabAST)
229    * @see #processPackage(SymTabAST)
230    * @see #processTry(SymTabAST)
231    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
232    * @see net.sourceforge.transmogrify.symtab.antlr.JavaTokenTypes
233    */
234   public void walkTree(SymTabAST tree, boolean makeAnonymousScopes) {
235 
236     if (tree != null) {
237 
238       ((SymTabAST)tree).setScope( symbolTable.getCurrentScope() );
239 
240       switch(tree.getType()) {
241       case 0:
242         processFile(tree);
243         if ( tree.getFirstChild().getType() != TokenTypes.PACKAGE_DEF ) {
244           processImplicitPackage( ((SymTabAST)tree).getFile() );
245         }
246 
247         walkSiblings((SymTabAST)tree.getFirstChild(), false);
248 
249         // pop package scope
250         symbolTable.popScope();
251         clearImports();
252         break;
253 
254       case TokenTypes.LITERAL_NEW:
255         SymTabAST symtabTree = (SymTabAST)tree;
256         SymTabAST objblock
257           = symtabTree.findFirstToken(TokenTypes.OBJBLOCK);
258         if (objblock != null) {
259           SymTabAST classExtended
260             = symtabTree.findFirstToken(TokenTypes.IDENT);
261 
262           processAnonymousInnerClass(objblock, classExtended);
263         }
264         break;
265 
266       case TokenTypes.SLIST:
267         if (makeAnonymousScopes) {
268           processBlock(tree, true);
269         }
270         else {
271           walkSiblings((SymTabAST)tree.getFirstChild(), true);
272         }
273         break;
274 
275       case TokenTypes.CTOR_DEF:
276         processConstructorDef(tree);
277         break;
278 
279       case TokenTypes.METHOD_DEF:
280         processMethodDef(tree);
281         break;
282 
283       case TokenTypes.LITERAL_FINALLY:
284         processFinally(tree);
285         break;
286 
287       case TokenTypes.LITERAL_TRY:
288         processTry(tree);
289         break;
290 
291       case TokenTypes.VARIABLE_DEF:
292         processVariableDef(tree);
293         break;
294 
295       case TokenTypes.PACKAGE_DEF:
296         processPackage(tree);
297         break;
298 
299       case TokenTypes.LABELED_STAT:
300         processLabel(tree);
301         break;
302 
303       case TokenTypes.IMPORT:
304         processImport(tree);
305         break;
306 
307       case TokenTypes.CLASS_DEF:
308       case TokenTypes.INTERFACE_DEF:
309         processClass(tree);
310         break;
311 
312       case TokenTypes.LITERAL_FOR:
313         processFor(tree);
314         break;
315 
316       case TokenTypes.LITERAL_IF:
317         processIf(tree);
318         break;
319       
320       case TokenTypes.LITERAL_ASSERT:
321         processAssert(tree);
322         break;
323 
324       case TokenTypes.LITERAL_CATCH:
325       case TokenTypes.LITERAL_WHILE:
326       case TokenTypes.LITERAL_SWITCH:
327       case TokenTypes.LITERAL_DO:
328       case TokenTypes.LITERAL_SYNCHRONIZED:
329       case TokenTypes.STATIC_INIT:
330       case TokenTypes.INSTANCE_INIT:
331         processBlock(tree, false);
332         break;
333 
334       default:
335         walkSiblings((SymTabAST)tree.getFirstChild(), false);
336       }
337     }
338   }
339 
340   /**
341  * @param tree
342  */
343 public void processAssert(SymTabAST tree) {
344     BlockDef block = makeBlock((SymTabAST)tree);
345 
346     SymTabAST expr = tree.findFirstToken(TokenTypes.EXPR);
347     SymTabAST message = (SymTabAST)expr.getNextSibling();
348     while ((message != null) && (message.getType() != TokenTypes.EXPR)) {
349         message = (SymTabAST) message.getNextSibling();
350     }
351 
352 
353     symbolTable.pushScope( block );
354     walkTree(expr, false);
355     if (message != null) {  
356         walkTree(message, false);
357     }
358     symbolTable.popScope();   
359 }
360 
361 /**
362    * processes the given <code>SymTabAST</code> and each of its siblings
363    *
364    * @param tree <code>SymTabAST</code> node to process
365    * @param makeAnonymousScopes
366    *
367    * @return <code>void</code>
368    * @see #walkTree(SymTabAST, boolean)
369    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
370    */
371   public void walkSiblings(SymTabAST tree, boolean makeAnonymousScopes) {
372     while(tree != null) {
373       walkTree(tree, makeAnonymousScopes);
374       tree = (SymTabAST)tree.getNextSibling();
375     }
376   }
377 
378   /**
379    * processes the given <code>SymTabAST</code> as a package defintion
380    *
381    * @param tree the <code>SymTabAST</code> to process
382    * @return <code>void</code>
383    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
384    * @see net.sourceforge.transmogrify.symtab.PackageDef
385    * @see net.sourceforge.transmogrify.symtab.SymbolTable
386    */
387   public void processPackage(SymTabAST tree) {
388     SymTabAST firstChild = (SymTabAST)tree.getFirstChild();
389 
390     String name = ASTUtil.constructDottedName(firstChild);
391     firstChild.ignoreChildren();
392 
393     PackageDef pkg = symbolTable.getPackage(name);
394 
395     if (pkg == null) {
396       pkg = createPackage( (SymTabAST)(tree.getFirstChild()) );
397     }
398 
399     symbolTable.pushScope(pkg);
400   }
401 
402   /**
403    * processes a java class that use default no package
404    *
405    * @param file <code>File</code> object of the java class
406    * @return <code>void</code>
407    * @see net.sourceforge.transmogrify.symtab.PackageDef
408    * @see net.sourceforge.transmogrify.symtab.SymbolTable
409    */
410   public void processImplicitPackage( File file ) {
411     String name = file.getParent();
412     if (name == null) {
413         name = "";
414     }
415     PackageDef pkg = symbolTable.getPackage( name );
416 
417     if ( pkg == null ) {
418       pkg = new PackageDef( name, symbolTable.getBaseScope(), null );
419       symbolTable.definePackage( pkg, symbolTable.getBaseScope() );
420     }
421 
422     symbolTable.pushScope( pkg );
423   }
424 
425   /**
426    * gets the package represented by the tree.  The method
427    * analyzes the tree, constructs an appropriate package name
428    * and fetches it from the internal package list. If the package does not
429    * exist it is created.
430    *
431    * @param tree <code>SymTabAST</code> to consider
432    *
433    * @return <code>PackageDef</code> the resulting package definition
434    * @see #getPackage(Scope, SymTabAST)
435    */
436   private PackageDef createPackage( SymTabAST tree ) {
437     PackageDef result = null;
438 
439     if (tree.getType() == TokenTypes.DOT) {
440       // find the package result of left child
441       SymTabAST leftChild = (SymTabAST)tree.getFirstChild();
442       SymTabAST rightChild = (SymTabAST)leftChild.getNextSibling();
443 
444       PackageDef context = createPackage(leftChild);
445       result = getPackage( context, rightChild );
446     }
447     else {
448       result = getPackage(symbolTable.getBaseScope(), tree);
449     }
450 
451     return result;
452   }
453 
454   /**
455    * gets the package determined by the tree and parent package def.
456    * The method analyzes the tree and parent scope and retrieves the
457    * appropriate package definition from the internal package list.
458    * If the package does not exist it is created.
459    *
460    * @param tree <code>SymTabAST</code> to consider
461    * @param parent the parent package definition
462    *
463    * @return PackageDef the resulting package definition
464    * @see net.sourceforge.transmogrify.symtab.PackageDef
465    * @see net.sourceforge.transmogrify.symtab.SymbolTable
466    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
467    */
468   private PackageDef getPackage(Scope parent, SymTabAST tree ) {
469     String name = tree.getText();
470     PackageDef result = null;
471     if (!(parent instanceof BaseScope)) {
472       result = symbolTable.getPackage(parent.getQualifiedName() + "." + name);
473     }
474     else {
475       result = symbolTable.getPackage(name);
476     }
477 
478     if (result == null) {
479       result = new PackageDef(tree.getText(), parent, tree);
480       symbolTable.definePackage(result, parent);
481     }
482 
483     return result;
484   }
485 
486   /**
487    * process the given <code>SymTabAST</code> as a file definition
488    *
489    * @param tree the <code>SymTabAST</code> to process
490    * @return <code>void</code>
491    * @see #setCurrentFile(String)
492    */
493   public void processFile(SymTabAST tree) {
494     setCurrentFile(tree.getText());
495   }
496 
497   /**
498    * adds the given <code>SymTabAST</code> to <code>imports</code> member
499    *
500    * @param tree the <code>SymTabAST</code> to process
501    * @return <code>void</code>
502    */
503   public void processImport(SymTabAST tree) {
504     imports.add( tree );
505   }
506 
507   /**
508    * clears the <code>imports</code> member
509    * @return <code>void</code>
510    */
511   private void clearImports() {
512     imports.clear();
513   }
514 
515   /**
516    * process the given SymTabAST as a label definition
517    *
518    * @param tree the SymTabAST to process
519    * @return <code>void</code>
520    * @see com.trwx.symtab.antlr.SymTabAST
521    * @see net.sourceforge.transmogrify.symtab.LabelDef
522    * @see #walkTree(SymTabAST, boolean)
523    */
524   public void processLabel(SymTabAST tree) {
525     String name = tree.findFirstToken(TokenTypes.IDENT).getText();
526     LabelDef label = new LabelDef( name, symbolTable.getCurrentScope(),
527            (SymTabAST)tree );
528     symbolTable.defineLabel( label );
529 
530     walkTree((SymTabAST)tree.getFirstChild().getNextSibling(), false);
531   }
532 
533   /**
534    * process the given <code>SymTabAST</code> as a class definition
535    *
536    * @param tree the <code>SymTabAST</code> to process
537    * @return <code>void</code>
538    * @see #makeClass(String, SymTabAST)
539    * @see #walkSiblings(SymTabAST, boolean)
540    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
541    */
542   public void processClass(SymTabAST tree) {
543     String name = tree.findFirstToken(TokenTypes.IDENT).getText();
544 
545     makeClass(name, tree);
546     final SymTabAST objblock =
547         (SymTabAST)tree.findFirstToken(TokenTypes.OBJBLOCK);
548     SymTabAST start = (SymTabAST)objblock.getFirstChild();
549     if (start != null) {
550         //skip LPAREN
551         if (start.getType() == TokenTypes.LPAREN) {
552             start = (SymTabAST)start.getNextSibling();
553         }
554         walkSiblings(start, false);
555     }
556     
557     symbolTable.popScope();
558   }
559 
560   /**
561    * creates <code>ClassDef</code> for the current class node and add it to the
562    * symbol table
563    * @param name name of the class
564    * @param tree current node to be processed
565    * @return <code>void</code>
566    * @see net.sourceforge.transmogrify.symtab.ClassDef
567    * @see net.sourceforge.transmogrify.symtab.SymbolTable
568    */
569   public void makeClass(String name, SymTabAST tree) {
570     ClassDef def = new ClassDef(name, symbolTable.getCurrentScope(), tree);
571     def.addUnprocessedImports(imports);
572     symbolTable.defineClass(def);
573     symbolTable.pushScope(def);
574   }
575 
576   /**
577    * processes anonymous inner class encountered in the tree
578    * @param objblock the anonymous block
579    * @param classExtended
580    * @return <code>void</code>
581    * @see net.sourceforge.transmogrify.symtab.AnonymousInnerClass
582    * @see net.sourceforge.transmogrify.symtab.SymbolTable
583    */
584   public void processAnonymousInnerClass(SymTabAST objblock,
585                                          SymTabAST classExtended) {
586     ClassDef def = new AnonymousInnerClass(objblock,
587                                            classExtended,
588                                            symbolTable.getCurrentScope());
589     symbolTable.defineClass(def);
590     symbolTable.pushScope(def);
591     walkSiblings((SymTabAST)objblock.getFirstChild(), false);
592     symbolTable.popScope();
593   }
594 
595   /**
596    * process the given SymTabAST as a variable definition
597    *
598    * @param tree the SymTabAST to process
599    * @return <code>void</code>
600    * @see net.sourceforge.transmogrify.symtab.VariableDef
601    * @see net.sourceforge.transmogrify.symtab.SymbolTable
602    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
603    * @see #makeVariableDef(SymTabAST, Scope)
604    * @see #walkTree(SymTabAST, boolean)
605    */
606   private void processVariableDef(SymTabAST tree) {
607     VariableDef def = makeVariableDef( tree, symbolTable.getCurrentScope() );
608     symbolTable.defineVariable(def);
609     SymTabAST assignmentNode
610       = ((SymTabAST)tree).findFirstToken(TokenTypes.ASSIGN);
611     if (assignmentNode != null) {
612       walkTree((SymTabAST)assignmentNode.getFirstChild(), false);
613     }
614   }
615 
616   /**
617    * creates <code>VariableDef</code> based on the current tree node and scope
618    * @param tree the current tree node
619    * @param scope the current scope
620    * @return <code>VariableDef</code>
621    * @see net.sourceforge.transmogrify.symtab.VariableDef
622    */
623   public VariableDef makeVariableDef(SymTabAST tree, Scope scope) {
624     String name = tree.findFirstToken(TokenTypes.IDENT).getText();
625     VariableDef result = new VariableDef(name, scope, tree);
626 
627     return result;
628   }
629 
630   /**
631    * process the given SymTabAST as a try block
632    *
633    * @param tree the SymTabAST to process
634    * @return <code>void</code>
635    * @see #makeBlock(SymTabAST)
636    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
637    * @see #walkTree(SymTabAST, boolean)
638    * @see #walkSiblings(SymTabAST, boolean)
639    */
640   public void processTry(SymTabAST tree){
641     BlockDef block = makeBlock(tree);
642 
643     SymTabAST slist = tree.findFirstToken(TokenTypes.SLIST);
644     SymTabAST everythingElse = (SymTabAST)slist.getNextSibling();
645 
646     symbolTable.pushScope( block );
647     walkTree( slist, false );
648     symbolTable.popScope();
649 
650     walkSiblings( everythingElse, false );
651   }
652 
653   /**
654    * process the given SymTabAST as a finally block
655    *
656    * @param tree the SymTabAST to process
657    * @return <code>void</code>
658    * @see #makeBlock(SymTabAST)
659    * @see #walkTree(SymTabAST, boolean)
660    */
661   public void processFinally(SymTabAST tree){
662     BlockDef block = makeBlock(tree);
663 
664     SymTabAST slist = tree.findFirstToken(TokenTypes.SLIST);
665     SymTabAST tryBlock = tree.findFirstToken(TokenTypes.LITERAL_TRY);
666 
667     symbolTable.pushScope( block );
668     walkTree( slist, false );
669     symbolTable.popScope();
670 
671     walkTree( tryBlock, false );
672   }
673 
674 
675   /**
676    * process the given SymTabAST as a method definition
677    *
678    * @param tree the SymTabAST to process
679    * @return <code>void</code>
680    * @see net.sourceforge.transmogrify.symtab.MethodDef
681    * @see net.sourceforge.transmogrify.symtab.SymbolTable
682    * @see #walkTree(SymTabAST, boolean)
683    */
684   public void processMethodDef(SymTabAST tree) {
685     String name = tree.findFirstToken(TokenTypes.IDENT).getText();
686     MethodDef method = new MethodDef(name, symbolTable.getCurrentScope(),
687                                      tree);
688     symbolTable.defineMethod( method );
689 
690     symbolTable.pushScope( method );
691     walkTree(tree.findFirstToken(TokenTypes.SLIST), false);
692     symbolTable.popScope();
693   }
694 
695   /**
696    * process the given SymTabAST as a constructor definition
697    *
698    * @param tree the SymTabAST to process
699    * @return <code>void</code>
700    * @see net.sourceforge.transmogrify.symtab.MethodDef
701    * @see net.sourceforge.transmogrify.symtab.SymbolTable
702    * @see #walkTree(SymTabAST, boolean)
703    */
704   public void processConstructorDef(SymTabAST tree) {
705     String name = tree.findFirstToken(TokenTypes.IDENT).getText();
706     MethodDef constructor = new MethodDef(name, symbolTable.getCurrentScope(),
707                                           tree);
708     symbolTable.defineMethod( constructor );
709 
710     symbolTable.pushScope( constructor );
711     walkTree(tree.findFirstToken(TokenTypes.SLIST), false);
712     symbolTable.popScope();
713   }
714 
715   /**
716    * process the given SymTabAST as a for block
717    *
718    * @param tree the SymTabAST to process
719    * @return <code>void</code>
720    * @see #makeBlock(SymTabAST)
721    * @see #walkTree(SymTabAST, boolean)
722    */
723   public void processFor(SymTabAST tree) {
724     BlockDef block = makeBlock((SymTabAST)tree);
725 
726     symbolTable.pushScope( block );
727     walkTree(tree.findFirstToken(TokenTypes.FOR_INIT), false);
728     walkTree(tree.findFirstToken(TokenTypes.FOR_CONDITION), false);
729 
730     SymTabAST forIter = tree.findFirstToken(TokenTypes.FOR_ITERATOR);
731     walkTree(forIter, false);
732 
733     SymTabAST body = (SymTabAST)forIter.getNextSibling();
734     //handle Checkstyle grammar
735     if (body.getType() == TokenTypes.RPAREN) {
736         body = (SymTabAST) body.getNextSibling();
737     }
738     walkTree(body, false);
739     symbolTable.popScope();
740   }
741 
742   /**
743    * process the given SymTabAST as an if block
744    *
745    * @param tree the SymTabAST to process
746    * @return <code>void</code>
747    * @see #makeBlock(SymTabAST)
748    * @see #walkTree(SymTabAST, boolean)
749    * @see #processElse(SymTabAST)
750    */
751   public void processIf(SymTabAST tree) {
752     BlockDef block = makeBlock((SymTabAST)tree);
753 
754     SymTabAST expr = tree.findFirstToken(TokenTypes.EXPR);
755     SymTabAST ifBranch = (SymTabAST)expr.getNextSibling();
756     // handle Checkstyle grammar
757     if (ifBranch.getType() == TokenTypes.RPAREN) {
758         ifBranch = (SymTabAST) ifBranch.getNextSibling();
759     }
760     SymTabAST elseBranch = (SymTabAST)ifBranch.getNextSibling();
761     // handle Checkstyle grammar
762     if ((elseBranch != null) && (elseBranch.getType() == TokenTypes.SEMI)) {
763             elseBranch = (SymTabAST) elseBranch.getNextSibling();
764     }
765     if ((elseBranch != null) && (elseBranch.getType() == TokenTypes.LITERAL_ELSE)) {
766         elseBranch = (SymTabAST) elseBranch.getFirstChild();
767     }
768 
769     symbolTable.pushScope( block );
770     walkTree(expr, false);
771     walkTree(ifBranch, false);
772     symbolTable.popScope();
773 
774     processElse(elseBranch);
775   }
776 
777   /**
778    * process the given SymTabAST as an else block
779    *
780    * @param tree the SymTabAST to process
781    * @return <code>void</code>
782    * @see #processIf(SymTabAST)
783    * @see #makeElseBlock(SymTabAST)
784    */
785   public void processElse(SymTabAST tree) {
786     if (tree != null) {
787       if (tree.getType() == TokenTypes.LITERAL_IF) {
788         processIf(tree);
789       }
790       else {
791         makeElseBlock(tree);
792       }
793     }
794   }
795 
796   /**
797    * defines an anonymous block to enclose the scope of an else block
798    *
799    * @param tree the SymTabAST to process
800    * @return <code>void</code>
801    * @see #makeBlock(SymTabAST)
802    * @see #walkTree(SymTabAST, boolean)
803    */
804   public void makeElseBlock(SymTabAST tree) {
805     if (tree.getType() == TokenTypes.SLIST) {
806       BlockDef block = makeBlock((SymTabAST)tree);
807       symbolTable.pushScope( block );
808       walkTree(tree, false);
809       symbolTable.popScope();
810     }
811     else {
812       walkTree(tree, false);
813     }
814   }
815 
816   /**
817    * processes the current tree node as BlockDef
818    * @param tree current tree node
819    * @param makeAnonymousScopes
820    * @return <code>void</code>
821    */
822   public void processBlock(SymTabAST tree, boolean makeAnonymousScopes) {
823     BlockDef block = makeBlock((SymTabAST)tree);
824     symbolTable.pushScope(block);
825     //handle Checkstyle grammar
826     SymTabAST child = (SymTabAST)tree.getFirstChild();
827     if ((child != null) && (child.getType() == TokenTypes.LPAREN)) {
828         child = (SymTabAST) child.getNextSibling();
829     }
830     walkSiblings((SymTabAST)child, makeAnonymousScopes);
831     symbolTable.popScope();
832   }
833 
834   /**
835    * set the current file to the named file
836    *
837    * @param fileName the name of the file
838    * @return <code>void</code>
839    */
840   public void setCurrentFile(String fileName) {
841     currentFile = new File(fileName);
842     symbolTable.setCurrentFile(currentFile);
843   }
844 
845 
846   /**
847    * creates a new <code> BlockDef </code> in the SymbolTable
848    *
849    * @param tree is a <code> SymTabAST </code> whose root begins the new block
850    * @return <code> BlockDef </code>
851    * @see net.sourceforge.transmogrify.symtab.BlockDef
852    * @see net.sourceforge.transmogrify.symtab.SymbolTable
853    */
854   private BlockDef makeBlock( SymTabAST tree ) {
855     BlockDef block = new BlockDef( symbolTable.getCurrentScope(), tree );
856     symbolTable.defineBlock( block );
857     return block;
858   }
859 
860   /**
861    * returns the <code>SymTabAST</code> that contains the parameter classDef's
862    * extends nodes
863    *
864    * @param classDef is a <code> ClassDef </code> whose extends nodes we want
865    * @return <code> SymTabAST </code>
866    */
867   public static SymTabAST getExtendsNode(ClassDef classDef) {
868     SymTabAST result = null;
869     SymTabAST extendsClause = null;
870 
871     SymTabAST classDefTreeNode = classDef.getTreeNode();
872     extendsClause =
873       classDefTreeNode.findFirstToken(TokenTypes.EXTENDS_CLAUSE);
874 
875     if (extendsClause != null) {
876       result = (SymTabAST)(extendsClause.getFirstChild());
877     }
878 
879     return result;
880   }
881 
882   /**
883    * Superclass for different kind of XXXFinisher subclass
884    * @see CatchFinisher
885    * @see ClassFinisher
886    * @see DefinitionFinisher
887    * @see MethodFinisher
888    * @see VariableFinisher
889    */
890   class DefinitionFinisher {
891 
892     protected SymTabAST _node = null;
893 
894     /**
895     * Constructor. It finishes the definition passed to it
896     *
897     */
898     public DefinitionFinisher( Definition def ) {
899       _node = def.getTreeNode();
900     }
901 
902     public void finish() throws SymbolTableException {}
903 
904     /**
905      * gets the classDef that represents the type of the given definition
906      *
907      *
908      * @param def the definition whose type to find
909      * @param typeNode the TokenTypes.TYPE node associated with the def
910      *
911      * @return the resulting class definition
912      */
913     protected IClass getType( Definition def, SymTabAST typeNode ) {
914       IClass result = null;
915 
916       SymTabAST typeClassNode = null;
917       boolean isArray = false;
918 
919       if ( typeNode.getFirstChild().getType()
920            == TokenTypes.ARRAY_DECLARATOR ) {
921         isArray = true;
922         typeClassNode = (SymTabAST)typeNode.getFirstChild().getFirstChild();
923       }
924       else {
925         typeClassNode = (SymTabAST)typeNode.getFirstChild();
926       }
927 
928       Scope lookupScope = null;
929 
930       if (def instanceof Scope) {
931          lookupScope = (Scope)def;
932       }
933       else {
934          lookupScope = def.getParentScope();
935       }
936 
937       Resolver resolver = new Resolver(symbolTable);
938       IClass typeClass = resolver.resolveClass(typeClassNode, lookupScope, null, false);
939 
940       if ( isArray ) {
941         result = new ArrayDef( typeClass );
942       }
943       else {
944         result = typeClass;
945       }
946 
947       return result;
948     }
949 
950   }
951 
952   class ClassFinisher extends DefinitionFinisher {
953 
954     private ClassDef _def = null;
955 
956     /**
957     * Constructor. Creates a ClassFinisher from a <code> Definition </code>
958     *
959     * @param def is a <code> Definition </code>
960     */
961     public ClassFinisher( Definition def ) {
962       super( def );
963       _def = (ClassDef)def;
964     }
965 
966     /**
967     * Completes all tasks required for finishing a ClassDef
968     * Including adding imports, setting super classes and adding
969     * interfaces.
970     * @return <code>void</code>
971     * @throws <code>SymbolTableException</code>
972     * @see #addImports()
973     * @see #setSuperclass()
974     * @see #addInterfaces()
975     */
976     public void finish() throws SymbolTableException {
977       if ( _node != null ) {
978         addImports();
979         setSuperclass();
980         addInterfaces();
981       }
982     }
983 
984     /**
985     * Adds all packages and classes that are imported by this class
986     * to the class for later reference
987     */
988     private void addImports() throws ClassImportException {
989       IPackage java = new ExternalPackage("java", null);
990       IPackage lang = new ExternalPackage("lang", java);
991       java.addDefinition(lang);
992       _def.importPackage(lang);
993 
994       Vector unprocessedImports = _def.getUnprocessedImports();
995       for ( int i = 0; i < unprocessedImports.size(); i++ ) {
996         SymTabAST importNode = (SymTabAST)unprocessedImports.get(i);
997         SymTabAST imported = (SymTabAST)importNode.getFirstChild();
998         SymTabAST lastPart = (SymTabAST)imported.getFirstChild().getNextSibling();
999 
1000        DotIterator it = new DotIterator(imported);
1001        SymTabAST current = null;
1002        String className = null;
1003        IClass importedClass = null;
1004
1005        // attempt at each token to find the class
1006        //   first in source
1007        //   then on classpath
1008        //
1009        // if there are more tokens left
1010        //   continue until you hit the last token
1011        //   if it's a star
1012        //     import all inner classes
1013        //   else
1014        //     import the explicitly named inner class
1015        // else import the class
1016        //
1017        // if no classes were found, import the package
1018
1019        while(it.hasNext()) {
1020          current = it.nextNode();
1021          if (className == null) {
1022            className = current.getText();
1023          }
1024          else {
1025            if (!current.getText().equals("*")) {
1026              className += "." + current.getText();
1027            }
1028            else {
1029              break;
1030            }
1031          }
1032          importedClass = findOrLoadClass(className, importedClass);
1033
1034          if (importedClass != null) {
1035            break;
1036          }
1037        }
1038
1039        if (it.hasNext()) {
1040          boolean isImported = false;
1041          while(it.hasNext()) {
1042            current = it.nextNode();
1043            if (current.getText().equals("*")) {
1044              importInnerClasses(importedClass);
1045              isImported = true;
1046            }
1047            else {
1048              className += "$" + current.getText();
1049              importedClass = findOrLoadClass(className, importedClass);
1050            }
1051          }
1052          if (!isImported) {
1053            _def.importClass(importedClass);
1054          }
1055        }
1056        else {
1057          if (importedClass != null) {
1058            _def.importClass(importedClass);
1059          }
1060          else {
1061            if (current != null && current.getText().equals("*")) {
1062              IPackage pkg = symbolTable.getPackage(className);
1063              if (pkg == null) {
1064                pkg = getPackage(className);
1065              }
1066              _def.importPackage(pkg);
1067            }
1068            else {
1069              //TODO: can we safely ignore this?
1070              //throw new ClassImportException(className);
1071              ;
1072            }
1073          }
1074        }
1075
1076        // now set definitions where appropriate
1077        imported.ignoreChildren();
1078        if ((lastPart.getType() == TokenTypes.IDENT)
1079            //TODO: guard added for class not loaded
1080            //This is OK for single file processing, but not
1081            //multiple files.
1082            && (importedClass != null)
1083            )
1084        {
1085          lastPart.setDefinition(importedClass, null, true);
1086          lastPart.setMeaningfulness(true);
1087        }
1088      }
1089    }
1090
1091    /**
1092     * creates <code>ExternalPackage</code>
1093     * @param packageName name of the package
1094     * @return <code>ExternalPackage</code>
1095     * @see net.sourceforge.transmogrify.symtab.ExternalPackage
1096     */
1097    private ExternalPackage getPackage(String packageName) {
1098      return new ExternalPackage(packageName, null);
1099    }
1100
1101    /**
1102     * stores the inner classes in the approriate ClassDef
1103     * @param outerClass
1104     * @return <code>void</code>
1105     */
1106    private void importInnerClasses(IClass outerClass) {
1107      IClass[] innerClasses = outerClass.getInnerClasses();
1108
1109      for (int i = 0; i < innerClasses.length; i++) {
1110        _def.importClass(innerClasses[i]);
1111      }
1112    }
1113
1114    /**
1115     * creates <code>ExternalClass</code> based on a java class
1116     * @param className class to be loaded
1117     * @return <code>IClass</code>
1118     * @see net.sourceforge.transmogrify.symtab.ExternalClass
1119     */
1120    private IClass loadClass(String className) {
1121      IClass result = null;
1122
1123      try {
1124        Class javaClass
1125          = ClassManager.getClassLoader().loadClass(className);
1126
1127        result = new ExternalClass(javaClass);
1128      }
1129      catch (ClassNotFoundException ignoreMe) {}
1130
1131      return result;
1132    }
1133
1134    /**
1135     * find a class from <code>BaseCode</code> or its parent
1136     * @param className name of the class to be load or found
1137     * @param parentClass its parent class
1138     * @return <code>IClass</code>
1139     * @see net.sourceforge.transmogrify.symtab.SymbolTable
1140     * @see net.sourceforge.transmogrify.symtab.IClass
1141     * @see #loadClass(String)
1142     */
1143    private IClass findOrLoadClass(String className, IClass parentClass) {
1144      IClass result = null;
1145
1146      if (parentClass == null) {
1147        result = symbolTable.getBaseScope().getClassDefinition(className);
1148      }
1149      else {
1150        int index = className.lastIndexOf("$");
1151        if (index < 0) {
1152          index = className.lastIndexOf(".");
1153        }
1154
1155        result = parentClass.getClassDefinition(className.substring(index + 1));
1156      }
1157
1158      if (result == null) {
1159        result = loadClass(className);
1160      }
1161
1162      return result;
1163    }
1164
1165    /**
1166    *
1167    * If the class has a super class a reference to this super class
1168    * is added to this class.
1169    * @return <code>void</code>
1170    * @see net.sourceforge.transmogrify.symtab.ClassDef
1171    */
1172    private void setSuperclass() {
1173      if (_def.getTreeNode().getType() == TokenTypes.CLASS_DEF) {
1174        SymTabAST extendsNode = getExtendsNode(_def);
1175        if ( extendsNode != null ) {
1176          String superclassName = ASTUtil.constructDottedName(extendsNode);
1177          IClass superclass = _def.getClassDefinition(superclassName);
1178          if ( superclass != null ) {
1179            _def.setSuperclass( superclass );
1180            superclass.addSubclass( _def );
1181          }
1182        }
1183        else {
1184          _def.setSuperclass(new ExternalClass(Object.class));
1185        }
1186      }
1187      else {
1188        _def.setSuperclass(new ExternalClass(Object.class));
1189      }
1190    }
1191
1192    /**
1193    *
1194    * If the class implements an interface a reference to this interface
1195    * is added to this class.
1196    * @return <code>void</code>
1197    * @see net.sourceforge.transmogrify.symtab.ClassDef
1198    */
1199    private void addInterfaces() {
1200      SymTabAST implementsClause = null;
1201
1202      if (_def.getTreeNode().getType() == TokenTypes.CLASS_DEF) {
1203        implementsClause
1204          = _node.findFirstToken(TokenTypes.IMPLEMENTS_CLAUSE);
1205      }
1206      else {
1207        implementsClause
1208          = _node.findFirstToken(TokenTypes.EXTENDS_CLAUSE);
1209      }
1210
1211      if ( implementsClause != null ) {
1212        SymTabAST interfaceNode = (SymTabAST)implementsClause.getFirstChild();
1213        while ( interfaceNode != null ) {
1214          IClass implemented =
1215            _def.getClassDefinition(interfaceNode.getText());
1216          if ( implemented != null ) {
1217            _def.addInterface( implemented );
1218            implemented.addImplementor( _def );
1219          }
1220        interfaceNode = (SymTabAST)(interfaceNode.getNextSibling());
1221        }
1222      }
1223    }
1224  }
1225
1226  /**
1227   *
1228   * Completes a Variable by setting all required references
1229   *
1230   */
1231  class VariableFinisher extends DefinitionFinisher {
1232    VariableDef _def = null;
1233
1234
1235    /**
1236    *
1237    * Constructor. Creates a VariableFinishes from the <code>Definition</code>
1238    * @param def VariableDef to be finished
1239    * @see net.sourceforge.transmogrify.symtab.VariableDef
1240    */
1241    public VariableFinisher( Definition def ) {
1242      super( def );
1243      _def = (VariableDef)def;
1244    }
1245
1246
1247    /**
1248    *
1249    * Finishes the variable by setting the Type
1250    * @return <code>void</code>
1251    * @see #getType(Definition, SymTabAST)
1252    * @see net.sourceforge.transmogrify.symtab.VariableDef
1253    */
1254    public void finish() {
1255
1256      SymTabAST typeNode = _node.findFirstToken(TokenTypes.TYPE);
1257
1258      SymTabAST typeTextNode = (SymTabAST)(typeNode.getFirstChild());
1259      if ( typeTextNode.getType() == TokenTypes.ARRAY_DECLARATOR ) {
1260        typeTextNode = (SymTabAST)(typeTextNode.getFirstChild());
1261      }
1262      typeTextNode.setLine(ASTUtil.getLine( _def.getTreeNode() ));
1263
1264      IClass varType = getType(_def, typeNode);
1265      _def.setType( varType );
1266
1267    }
1268  }
1269
1270  /**
1271   *
1272   * Completes a Variable by setting all required references
1273   *
1274   */
1275  class MethodFinisher extends DefinitionFinisher {
1276    MethodDef _def = null;
1277
1278
1279    /**
1280    *
1281    * Creates a MethodFinisher from a <code> Definition <code>
1282    * @param def MethodDef to be finished
1283    * @see net.sourceforge.transmogrify.symtab.MethodDef
1284    */
1285    public MethodFinisher( Definition def ) {
1286      super( def );
1287      _def = (MethodDef)def;
1288    }
1289
1290    /**
1291    *
1292    * Completes a method by setting all references to return types,
1293    * signatures and exceptions.
1294    * @return <code>void</code>
1295    * @see #setReturnType()
1296    * @see #setSignature()
1297    * @see #setExceptionsThrown()
1298    */
1299    public void finish() {
1300      setReturnType();
1301      setSignature();
1302      setExceptionsThrown();
1303    }
1304
1305    /**
1306    *
1307    * setReturnType adds a reference to the methods return type
1308    * to the method definition
1309    * @return <code>void</code>
1310    * @see net.sourceforge.transmogrify.symtab.MethodDef
1311    * @see #getType(Definition, SymTabAST)
1312    * @see #getTypeNode()
1313    */
1314    private void setReturnType() {
1315      IClass type = null;
1316
1317      if ( isConstructor() ) {
1318        type = _def.getEnclosingClass();
1319      }
1320      else {
1321        type = getType(_def, getTypeNode());
1322      }
1323
1324      _def.setType(type);
1325    }
1326
1327    /**
1328    *
1329    * setSignature adds a reference to the methods paramaters
1330    * to the method definition
1331    * @return <code>void</code>
1332    * @see #makeVariableDef(SymTabAST, Definition)
1333    * @see VariableFinisher
1334    * @see net.sourceforge.transmogrify.symtab.MethodDef
1335    */
1336    private void setSignature() {
1337      SymTabAST parametersNode
1338        = _node.findFirstToken(TokenTypes.PARAMETERS);
1339
1340      SymTabAST parameterNode = (SymTabAST)(parametersNode.getFirstChild());
1341      while ( parameterNode != null ) {
1342        if (parameterNode.getType() == TokenTypes.PARAMETER_DEF) {
1343            VariableDef parameter = makeVariableDef( parameterNode, _def );
1344            new VariableFinisher( parameter ).finish();
1345</