KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > usage > transmogrify > TableMaker


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 JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.Vector JavaDoc;
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 JavaDoc currentFile;
54   private Vector JavaDoc imports = new Vector JavaDoc();
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(def).finish();
142     }
143     else if ( def instanceof VariableDef ) {
144       new VariableFinisher( def ).finish();
145     }
146     else if (def instanceof DefaultConstructor) {}
147     else if ( def instanceof MethodDef ) {
148       new MethodFinisher( 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 JavaDoc 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       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( 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 = tree;
256         //walk parameters, in case of anonymous inner class
257
walkTree(symtabTree.findFirstToken(TokenTypes.ELIST),
258           makeAnonymousScopes);
259         SymTabAST objblock
260           = symtabTree.findFirstToken(TokenTypes.OBJBLOCK);
261         if (objblock != null) {
262           SymTabAST classExtended
263             = symtabTree.findFirstToken(TokenTypes.IDENT);
264
265           processAnonymousInnerClass(objblock, classExtended);
266         }
267         break;
268
269       case TokenTypes.SLIST:
270         if (makeAnonymousScopes) {
271           processBlock(tree, true);
272         }
273         else {
274           walkSiblings((SymTabAST)tree.getFirstChild(), true);
275         }
276         break;
277
278       case TokenTypes.CTOR_DEF:
279         processConstructorDef(tree);
280         break;
281
282       case TokenTypes.METHOD_DEF:
283         processMethodDef(tree);
284         break;
285
286       case TokenTypes.LITERAL_FINALLY:
287         processFinally(tree);
288         break;
289
290       case TokenTypes.LITERAL_TRY:
291         processTry(tree);
292         break;
293
294       case TokenTypes.VARIABLE_DEF:
295         processVariableDef(tree);
296         break;
297
298       case TokenTypes.PACKAGE_DEF:
299         processPackage(tree);
300         break;
301
302       case TokenTypes.LABELED_STAT:
303         processLabel(tree);
304         break;
305
306       case TokenTypes.IMPORT:
307         processImport(tree);
308         break;
309
310       case TokenTypes.CLASS_DEF:
311       case TokenTypes.INTERFACE_DEF:
312         processClass(tree);
313         break;
314
315       case TokenTypes.LITERAL_FOR:
316         processFor(tree);
317         break;
318
319       case TokenTypes.LITERAL_IF:
320         processIf(tree);
321         break;
322       
323       case TokenTypes.LITERAL_ASSERT:
324         processAssert(tree);
325         break;
326
327       case TokenTypes.LITERAL_CATCH:
328       case TokenTypes.LITERAL_WHILE:
329       case TokenTypes.LITERAL_SWITCH:
330       case TokenTypes.LITERAL_DO:
331       case TokenTypes.LITERAL_SYNCHRONIZED:
332       case TokenTypes.STATIC_INIT:
333       case TokenTypes.INSTANCE_INIT:
334         processBlock(tree, false);
335         break;
336
337       default:
338         walkSiblings((SymTabAST)tree.getFirstChild(), false);
339       }
340     }
341   }
342
343   /**
344  * @param tree
345  */

346 public void processAssert(SymTabAST tree) {
347     BlockDef block = makeBlock(tree);
348
349     SymTabAST expr = tree.findFirstToken(TokenTypes.EXPR);
350     SymTabAST message = (SymTabAST)expr.getNextSibling();
351     while ((message != null) && (message.getType() != TokenTypes.EXPR)) {
352         message = (SymTabAST) message.getNextSibling();
353     }
354
355
356     symbolTable.pushScope( block );
357     walkTree(expr, false);
358     if (message != null) {
359         walkTree(message, false);
360     }
361     symbolTable.popScope();
362 }
363
364 /**
365    * processes the given <code>SymTabAST</code> and each of its siblings
366    *
367    * @param tree <code>SymTabAST</code> node to process
368    * @param makeAnonymousScopes
369    *
370    * @return <code>void</code>
371    * @see #walkTree(SymTabAST, boolean)
372    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
373    */

374   public void walkSiblings(SymTabAST tree, boolean makeAnonymousScopes) {
375     while(tree != null) {
376       walkTree(tree, makeAnonymousScopes);
377       tree = (SymTabAST)tree.getNextSibling();
378     }
379   }
380
381   /**
382    * processes the given <code>SymTabAST</code> as a package defintion
383    *
384    * @param tree the <code>SymTabAST</code> to process
385    * @return <code>void</code>
386    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
387    * @see net.sourceforge.transmogrify.symtab.PackageDef
388    * @see net.sourceforge.transmogrify.symtab.SymbolTable
389    */

390   public void processPackage(SymTabAST tree) {
391     SymTabAST firstChild = (SymTabAST)tree.getFirstChild();
392
393     String JavaDoc name = ASTUtil.constructDottedName(firstChild);
394     firstChild.ignoreChildren();
395
396     PackageDef pkg = symbolTable.getPackage(name);
397
398     if (pkg == null) {
399       pkg = createPackage( (SymTabAST)(tree.getFirstChild()) );
400     }
401
402     symbolTable.pushScope(pkg);
403   }
404
405   /**
406    * processes a java class that use default no package
407    *
408    * @param file <code>File</code> object of the java class
409    * @return <code>void</code>
410    * @see net.sourceforge.transmogrify.symtab.PackageDef
411    * @see net.sourceforge.transmogrify.symtab.SymbolTable
412    */

413   public void processImplicitPackage( File JavaDoc file ) {
414     String JavaDoc name = file.getParent();
415     if (name == null) {
416         name = "";
417     }
418     PackageDef pkg = symbolTable.getPackage( name );
419
420     if ( pkg == null ) {
421       pkg = new PackageDef( name, symbolTable.getBaseScope(), null );
422       symbolTable.definePackage( pkg, symbolTable.getBaseScope() );
423     }
424
425     symbolTable.pushScope( pkg );
426   }
427
428   /**
429    * gets the package represented by the tree. The method
430    * analyzes the tree, constructs an appropriate package name
431    * and fetches it from the internal package list. If the package does not
432    * exist it is created.
433    *
434    * @param tree <code>SymTabAST</code> to consider
435    *
436    * @return <code>PackageDef</code> the resulting package definition
437    * @see #getPackage(Scope, SymTabAST)
438    */

439   private PackageDef createPackage( SymTabAST tree ) {
440     PackageDef result = null;
441
442     if (tree.getType() == TokenTypes.DOT) {
443       // find the package result of left child
444
SymTabAST leftChild = (SymTabAST)tree.getFirstChild();
445       SymTabAST rightChild = (SymTabAST)leftChild.getNextSibling();
446
447       PackageDef context = createPackage(leftChild);
448       result = getPackage( context, rightChild );
449     }
450     else {
451       result = getPackage(symbolTable.getBaseScope(), tree);
452     }
453
454     return result;
455   }
456
457   /**
458    * gets the package determined by the tree and parent package def.
459    * The method analyzes the tree and parent scope and retrieves the
460    * appropriate package definition from the internal package list.
461    * If the package does not exist it is created.
462    *
463    * @param tree <code>SymTabAST</code> to consider
464    * @param parent the parent package definition
465    *
466    * @return PackageDef the resulting package definition
467    * @see net.sourceforge.transmogrify.symtab.PackageDef
468    * @see net.sourceforge.transmogrify.symtab.SymbolTable
469    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
470    */

471   private PackageDef getPackage(Scope parent, SymTabAST tree ) {
472     String JavaDoc name = tree.getText();
473     PackageDef result = null;
474     if (!(parent instanceof BaseScope)) {
475       result = symbolTable.getPackage(parent.getQualifiedName() + "." + name);
476     }
477     else {
478       result = symbolTable.getPackage(name);
479     }
480
481     if (result == null) {
482       result = new PackageDef(tree.getText(), parent, tree);
483       symbolTable.definePackage(result, parent);
484     }
485
486     return result;
487   }
488
489   /**
490    * process the given <code>SymTabAST</code> as a file definition
491    *
492    * @param tree the <code>SymTabAST</code> to process
493    * @return <code>void</code>
494    * @see #setCurrentFile(String)
495    */

496   public void processFile(SymTabAST tree) {
497     setCurrentFile(tree.getText());
498   }
499
500   /**
501    * adds the given <code>SymTabAST</code> to <code>imports</code> member
502    *
503    * @param tree the <code>SymTabAST</code> to process
504    * @return <code>void</code>
505    */

506   public void processImport(SymTabAST tree) {
507     imports.add( tree );
508   }
509
510   /**
511    * clears the <code>imports</code> member
512    * @return <code>void</code>
513    */

514   private void clearImports() {
515     imports.clear();
516   }
517
518   /**
519    * process the given SymTabAST as a label definition
520    *
521    * @param tree the SymTabAST to process
522    * @return <code>void</code>
523    * @see com.trwx.symtab.antlr.SymTabAST
524    * @see net.sourceforge.transmogrify.symtab.LabelDef
525    * @see #walkTree(SymTabAST, boolean)
526    */

527   public void processLabel(SymTabAST tree) {
528     String JavaDoc name = tree.findFirstToken(TokenTypes.IDENT).getText();
529     LabelDef label = new LabelDef( name, symbolTable.getCurrentScope(),
530            tree );
531     symbolTable.defineLabel( label );
532
533     walkTree((SymTabAST)tree.getFirstChild().getNextSibling(), false);
534   }
535
536   /**
537    * process the given <code>SymTabAST</code> as a class definition
538    *
539    * @param tree the <code>SymTabAST</code> to process
540    * @return <code>void</code>
541    * @see #makeClass(String, SymTabAST)
542    * @see #walkSiblings(SymTabAST, boolean)
543    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
544    */

545   public void processClass(SymTabAST tree) {
546     String JavaDoc name = tree.findFirstToken(TokenTypes.IDENT).getText();
547
548     makeClass(name, tree);
549     final SymTabAST objblock =
550         tree.findFirstToken(TokenTypes.OBJBLOCK);
551     SymTabAST start = (SymTabAST)objblock.getFirstChild();
552     if (start != null) {
553         //skip LPAREN
554
if (start.getType() == TokenTypes.LPAREN) {
555             start = (SymTabAST)start.getNextSibling();
556         }
557         walkSiblings(start, false);
558     }
559     
560     symbolTable.popScope();
561   }
562
563   /**
564    * creates <code>ClassDef</code> for the current class node and add it to the
565    * symbol table
566    * @param name name of the class
567    * @param tree current node to be processed
568    * @return <code>void</code>
569    * @see net.sourceforge.transmogrify.symtab.ClassDef
570    * @see net.sourceforge.transmogrify.symtab.SymbolTable
571    */

572   public void makeClass(String JavaDoc name, SymTabAST tree) {
573     ClassDef def = new ClassDef(name, symbolTable.getCurrentScope(), tree);
574     def.addUnprocessedImports(imports);
575     symbolTable.defineClass(def);
576     symbolTable.pushScope(def);
577   }
578
579   /**
580    * processes anonymous inner class encountered in the tree
581    * @param objblock the anonymous block
582    * @param classExtended
583    * @return <code>void</code>
584    * @see net.sourceforge.transmogrify.symtab.AnonymousInnerClass
585    * @see net.sourceforge.transmogrify.symtab.SymbolTable
586    */

587   public void processAnonymousInnerClass(SymTabAST objblock,
588                                          SymTabAST classExtended) {
589     ClassDef def = new AnonymousInnerClass(objblock,
590                                            classExtended,
591                                            symbolTable.getCurrentScope());
592     symbolTable.defineClass(def);
593     symbolTable.pushScope(def);
594     walkSiblings((SymTabAST)objblock.getFirstChild(), false);
595     symbolTable.popScope();
596   }
597
598   /**
599    * process the given SymTabAST as a variable definition
600    *
601    * @param tree the SymTabAST to process
602    * @return <code>void</code>
603    * @see net.sourceforge.transmogrify.symtab.VariableDef
604    * @see net.sourceforge.transmogrify.symtab.SymbolTable
605    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
606    * @see #makeVariableDef(SymTabAST, Scope)
607    * @see #walkTree(SymTabAST, boolean)
608    */

609   private void processVariableDef(SymTabAST tree) {
610     VariableDef def = makeVariableDef( tree, symbolTable.getCurrentScope() );
611     symbolTable.defineVariable(def);
612     SymTabAST assignmentNode
613       = tree.findFirstToken(TokenTypes.ASSIGN);
614     if (assignmentNode != null) {
615       walkTree((SymTabAST)assignmentNode.getFirstChild(), false);
616     }
617   }
618
619   /**
620    * creates <code>VariableDef</code> based on the current tree node and scope
621    * @param tree the current tree node
622    * @param scope the current scope
623    * @return <code>VariableDef</code>
624    * @see net.sourceforge.transmogrify.symtab.VariableDef
625    */

626   public VariableDef makeVariableDef(SymTabAST tree, Scope scope) {
627     String JavaDoc name = tree.findFirstToken(TokenTypes.IDENT).getText();
628     VariableDef result = new VariableDef(name, scope, tree);
629
630     return result;
631   }
632
633   /**
634    * process the given SymTabAST as a try block
635    *
636    * @param tree the SymTabAST to process
637    * @return <code>void</code>
638    * @see #makeBlock(SymTabAST)
639    * @see net.sourceforge.transmogrify.symtab.antlr.SymTabAST
640    * @see #walkTree(SymTabAST, boolean)
641    * @see #walkSiblings(SymTabAST, boolean)
642    */

643   public void processTry(SymTabAST tree){
644     BlockDef block = makeBlock(tree);
645
646     SymTabAST slist = tree.findFirstToken(TokenTypes.SLIST);
647     SymTabAST everythingElse = (SymTabAST)slist.getNextSibling();
648
649     symbolTable.pushScope( block );
650     walkTree( slist, false );
651     symbolTable.popScope();
652
653     walkSiblings( everythingElse, false );
654   }
655
656   /**
657    * process the given SymTabAST as a finally block
658    *
659    * @param tree the SymTabAST to process
660    * @return <code>void</code>
661    * @see #makeBlock(SymTabAST)
662    * @see #walkTree(SymTabAST, boolean)
663    */

664   public void processFinally(SymTabAST tree){
665     BlockDef block = makeBlock(tree);
666
667     SymTabAST slist = tree.findFirstToken(TokenTypes.SLIST);
668     SymTabAST tryBlock = tree.findFirstToken(TokenTypes.LITERAL_TRY);
669
670     symbolTable.pushScope( block );
671     walkTree( slist, false );
672     symbolTable.popScope();
673
674     walkTree( tryBlock, false );
675   }
676
677
678   /**
679    * process the given SymTabAST as a method definition
680    *
681    * @param tree the SymTabAST to process
682    * @return <code>void</code>
683    * @see net.sourceforge.transmogrify.symtab.MethodDef
684    * @see net.sourceforge.transmogrify.symtab.SymbolTable
685    * @see #walkTree(SymTabAST, boolean)
686    */

687   public void processMethodDef(SymTabAST tree) {
688     String JavaDoc name = tree.findFirstToken(TokenTypes.IDENT).getText();
689     MethodDef method = new MethodDef(name, symbolTable.getCurrentScope(),
690                                      tree);
691     symbolTable.defineMethod( method );
692
693     symbolTable.pushScope( method );
694     walkTree(tree.findFirstToken(TokenTypes.SLIST), false);
695     symbolTable.popScope();
696   }
697
698   /**
699    * process the given SymTabAST as a constructor definition
700    *
701    * @param tree the SymTabAST to process
702    * @return <code>void</code>
703    * @see net.sourceforge.transmogrify.symtab.MethodDef
704    * @see net.sourceforge.transmogrify.symtab.SymbolTable
705    * @see #walkTree(SymTabAST, boolean)
706    */

707   public void processConstructorDef(SymTabAST tree) {
708     processMethodDef(tree);
709   }
710
711   /**
712    * process the given SymTabAST as a for block
713    *
714    * @param tree the SymTabAST to process
715    * @return <code>void</code>
716    * @see #makeBlock(SymTabAST)
717    * @see #walkTree(SymTabAST, boolean)
718    */

719   public void processFor(SymTabAST tree) {
720     BlockDef block = makeBlock(tree);
721
722     symbolTable.pushScope( block );
723     SymTabAST body;
724     SymTabAST forEach = tree.findFirstToken(TokenTypes.FOR_EACH_CLAUSE);
725     if (forEach != null) {
726         walkTree(forEach, false);
727         body = (SymTabAST)forEach.getNextSibling();
728     }
729     else {
730         walkTree(tree.findFirstToken(TokenTypes.FOR_INIT), false);
731         walkTree(tree.findFirstToken(TokenTypes.FOR_CONDITION), false);
732
733         SymTabAST forIter = tree.findFirstToken(TokenTypes.FOR_ITERATOR);
734         walkTree(forIter, false);
735         body = (SymTabAST)forIter.getNextSibling();
736     }
737
738     //handle Checkstyle grammar
739
if (body.getType() == TokenTypes.RPAREN) {
740         body = (SymTabAST) body.getNextSibling();
741     }
742     walkTree(body, false);
743     symbolTable.popScope();
744   }
745
746   /**
747    * process the given SymTabAST as an if block
748    *
749    * @param tree the SymTabAST to process
750    * @return <code>void</code>
751    * @see #makeBlock(SymTabAST)
752    * @see #walkTree(SymTabAST, boolean)
753    * @see #processElse(SymTabAST)
754    */

755   public void processIf(SymTabAST tree) {
756     BlockDef block = makeBlock(tree);
757
758     SymTabAST expr = tree.findFirstToken(TokenTypes.EXPR);
759     SymTabAST ifBranch = (SymTabAST)expr.getNextSibling();
760     // handle Checkstyle grammar
761
if (ifBranch.getType() == TokenTypes.RPAREN) {
762         ifBranch = (SymTabAST) ifBranch.getNextSibling();
763     }
764     SymTabAST elseBranch = (SymTabAST)ifBranch.getNextSibling();
765     // handle Checkstyle grammar
766
if ((elseBranch != null) && (elseBranch.getType() == TokenTypes.SEMI)) {
767             elseBranch = (SymTabAST) elseBranch.getNextSibling();
768     }
769     if ((elseBranch != null) && (elseBranch.getType() == TokenTypes.LITERAL_ELSE)) {
770         elseBranch = (SymTabAST) elseBranch.getFirstChild();
771     }
772
773     symbolTable.pushScope( block );
774     walkTree(expr, false);
775     walkTree(ifBranch, false);
776     symbolTable.popScope();
777
778     processElse(elseBranch);
779   }
780
781   /**
782    * process the given SymTabAST as an else block
783    *
784    * @param tree the SymTabAST to process
785    * @return <code>void</code>
786    * @see #processIf(SymTabAST)
787    * @see #makeElseBlock(SymTabAST)
788    */

789   public void processElse(SymTabAST tree) {
790     if (tree != null) {
791       if (tree.getType() == TokenTypes.LITERAL_IF) {
792         processIf(tree);
793       }
794       else {
795         makeElseBlock(tree);
796       }
797     }
798   }
799
800   /**
801    * defines an anonymous block to enclose the scope of an else block
802    *
803    * @param tree the SymTabAST to process
804    * @return <code>void</code>
805    * @see #makeBlock(SymTabAST)
806    * @see #walkTree(SymTabAST, boolean)
807    */

808   public void makeElseBlock(SymTabAST tree) {
809     if (tree.getType() == TokenTypes.SLIST) {
810       BlockDef block = makeBlock(tree);
811       symbolTable.pushScope( block );
812       walkTree(tree, false);
813       symbolTable.popScope();
814     }
815     else {
816       walkTree(tree, false);
817     }
818   }
819
820   /**
821    * processes the current tree node as BlockDef
822    * @param tree current tree node
823    * @param makeAnonymousScopes
824    * @return <code>void</code>
825    */

826   public void processBlock(SymTabAST tree, boolean makeAnonymousScopes) {
827     BlockDef block = makeBlock(tree);
828     symbolTable.pushScope(block);
829     //handle Checkstyle grammar
830
SymTabAST child = (SymTabAST)tree.getFirstChild();
831     if ((child != null) && (child.getType() == TokenTypes.LPAREN)) {
832         child = (SymTabAST) child.getNextSibling();
833     }
834     walkSiblings(child, makeAnonymousScopes);
835     symbolTable.popScope();
836   }
837
838   /**
839    * set the current file to the named file
840    *
841    * @param fileName the name of the file
842    * @return <code>void</code>
843    */

844   public void setCurrentFile(String JavaDoc fileName) {
845     currentFile = new File JavaDoc(fileName);
846     symbolTable.setCurrentFile(currentFile);
847   }
848
849
850   /**
851    * creates a new <code> BlockDef </code> in the SymbolTable
852    *
853    * @param tree is a <code> SymTabAST </code> whose root begins the new block
854    * @return <code> BlockDef </code>
855    * @see net.sourceforge.transmogrify.symtab.BlockDef
856    * @see net.sourceforge.transmogrify.symtab.SymbolTable
857    */

858   private BlockDef makeBlock( SymTabAST tree ) {
859     BlockDef block = new BlockDef( symbolTable.getCurrentScope(), tree );
860     symbolTable.defineBlock( block );
861     return block;
862   }
863
864   /**
865    * returns the <code>SymTabAST</code> that contains the parameter classDef's
866    * extends nodes
867    *
868    * @param classDef is a <code> ClassDef </code> whose extends nodes we want
869    * @return <code> SymTabAST </code>
870    */

871   public static SymTabAST getExtendsNode(ClassDef classDef) {
872     SymTabAST result = null;
873     SymTabAST extendsClause = null;
874
875     SymTabAST classDefTreeNode = classDef.getTreeNode();
876     extendsClause =
877       classDefTreeNode.findFirstToken(TokenTypes.EXTENDS_CLAUSE);
878
879     if (extendsClause != null) {
880       result = (SymTabAST)(extendsClause.getFirstChild());
881     }
882
883     return result;
884   }
885
886   /**
887    * Superclass for different kind of XXXFinisher subclass
888    * @see CatchFinisher
889    * @see ClassFinisher
890    * @see DefinitionFinisher
891    * @see MethodFinisher
892    * @see VariableFinisher
893    */

894   class DefinitionFinisher {
895
896     protected SymTabAST _node = null;
897
898     /**
899     * Constructor. It finishes the definition passed to it
900     *
901     */

902     public DefinitionFinisher( Definition def ) {
903       _node = def.getTreeNode();
904     }
905
906     public void finish() throws SymbolTableException {}
907
908     /**
909      * gets the classDef that represents the type of the given definition
910      *
911      *
912      * @param def the definition whose type to find
913      * @param typeNode the TokenTypes.TYPE node associated with the def
914      *
915      * @return the resulting class definition
916      */

917     protected IClass getType( Definition def, SymTabAST typeNode ) {
918       IClass result = null;
919
920       SymTabAST typeClassNode = null;
921       boolean isArray = false;
922
923       if ( typeNode.getFirstChild().getType()
924            == TokenTypes.ARRAY_DECLARATOR ) {
925         isArray = true;
926         typeClassNode = (SymTabAST)typeNode.getFirstChild().getFirstChild();
927       }
928       else {
929         typeClassNode = (SymTabAST)typeNode.getFirstChild();
930       }
931
932       Scope lookupScope = null;
933
934       if (def instanceof Scope) {
935          lookupScope = (Scope)def;
936       }
937       else {
938          lookupScope = def.getParentScope();
939       }
940
941       Resolver resolver = new Resolver(symbolTable);
942       IClass typeClass = resolver.resolveClass(typeClassNode, lookupScope, null, false);
943
944       if ( isArray ) {
945         result = new ArrayDef( typeClass );
946       }
947       else {
948         result = typeClass;
949       }
950
951       return result;
952     }
953
954   }
955
956   class ClassFinisher extends DefinitionFinisher {
957
958     private ClassDef _def = null;
959
960     /**
961     * Constructor. Creates a ClassFinisher from a <code> Definition </code>
962     *
963     * @param def is a <code> Definition </code>
964     */

965     public ClassFinisher( Definition def ) {
966       super( def );
967       _def = (ClassDef)def;
968     }
969
970     /**
971     * Completes all tasks required for finishing a ClassDef
972     * Including adding imports, setting super classes and adding
973     * interfaces.
974     * @return <code>void</code>
975     * @throws <code>SymbolTableException</code>
976     * @see #addImports()
977     * @see #setSuperclass()
978     * @see #addInterfaces()
979     */

980     public void finish() throws SymbolTableException {
981       if ( _node != null ) {
982         addImports();
983         setSuperclass();
984         addInterfaces();
985       }
986     }
987
988     /**
989     * Adds all packages and classes that are imported by this class
990     * to the class for later reference
991     */

992     private void addImports() throws ClassImportException {
993       IPackage java = new ExternalPackage("java", null);
994       IPackage lang = new ExternalPackage("lang", java);
995       java.addDefinition(lang);
996       _def.importPackage(lang);
997
998       Vector JavaDoc unprocessedImports = _def.getUnprocessedImports();
999       for ( int i = 0; i < unprocessedImports.size(); i++ ) {
1000        SymTabAST importNode = (SymTabAST)unprocessedImports.get(i);
1001        SymTabAST imported = (SymTabAST)importNode.getFirstChild();
1002        SymTabAST lastPart = (SymTabAST)imported.getFirstChild().getNextSibling();
1003
1004        DotIterator it = new DotIterator(imported);
1005        SymTabAST current = null;
1006        String JavaDoc className = null;
1007        IClass importedClass = null;
1008
1009        // attempt at each token to find the class
1010
// first in source
1011
// then on classpath
1012
//
1013
// if there are more tokens left
1014
// continue until you hit the last token
1015
// if it's a star
1016
// import all inner classes
1017
// else
1018
// import the explicitly named inner class
1019
// else import the class
1020
//
1021
// if no classes were found, import the package
1022

1023        while(it.hasNext()) {
1024          current = it.nextNode();
1025          if (className == null) {
1026            className = current.getText();
1027          }
1028          else {
1029            if (!current.getText().equals("*")) {
1030              className += "." + current.getText();
1031            }
1032            else {
1033              break;
1034            }
1035          }
1036          importedClass = findOrLoadClass(className, importedClass);
1037
1038          if (importedClass != null) {
1039            break;
1040          }
1041        }
1042
1043        if (it.hasNext()) {
1044          boolean isImported = false;
1045          while(it.hasNext()) {
1046            current = it.nextNode();
1047            if (current.getText().equals("*")) {
1048              importInnerClasses(importedClass);
1049              isImported = true;
1050            }
1051            else {
1052              className += "$" + current.getText();
1053              importedClass = findOrLoadClass(className, importedClass);
1054            }
1055          }
1056          if (!isImported) {
1057            _def.importClass(importedClass);
1058          }
1059        }
1060        else {
1061          if (importedClass != null) {
1062            _def.importClass(importedClass);
1063          }
1064          else {
1065            if (current != null && current.getText().equals("*")) {
1066              IPackage pkg = symbolTable.getPackage(className);
1067              if (pkg == null) {
1068                pkg = getPackage(className);
1069              }
1070              _def.importPackage(pkg);
1071            }
1072            else {
1073              //TODO: can we safely ignore this?
1074
//throw new ClassImportException(className);
1075
;
1076            }
1077          }
1078        }
1079
1080        // now set definitions where appropriate
1081
imported.ignoreChildren();
1082        if ((lastPart.getType() == TokenTypes.IDENT)
1083            //TODO: guard added for class not loaded
1084
//This is OK for single file processing, but not
1085
//multiple files.
1086
&& (importedClass != null)
1087            )
1088        {
1089          lastPart.setDefinition(importedClass, null, true);
1090          lastPart.setMeaningfulness(true);
1091        }
1092      }
1093    }
1094
1095    /**
1096     * creates <code>ExternalPackage</code>
1097     * @param packageName name of the package
1098     * @return <code>ExternalPackage</code>
1099     * @see net.sourceforge.transmogrify.symtab.ExternalPackage
1100     */

1101    private ExternalPackage getPackage(String JavaDoc packageName) {
1102      return new ExternalPackage(packageName, null);
1103    }
1104
1105    /**
1106     * stores the inner classes in the approriate ClassDef
1107     * @param outerClass
1108     * @return <code>void</code>
1109     */

1110    private void importInnerClasses(IClass outerClass) {
1111      IClass[] innerClasses = outerClass.getInnerClasses();
1112
1113      for (int i = 0; i < innerClasses.length; i++) {
1114        _def.importClass(innerClasses[i]);
1115      }
1116    }
1117
1118    /**
1119     * creates <code>ExternalClass</code> based on a java class
1120     * @param className class to be loaded
1121     * @return <code>IClass</code>
1122     * @see net.sourceforge.transmogrify.symtab.ExternalClass
1123     */

1124    private IClass loadClass(String JavaDoc className) {
1125      IClass result = null;
1126
1127      try {
1128        Class JavaDoc javaClass
1129          = ClassManager.getClassLoader().loadClass(className);
1130
1131        result = new ExternalClass(javaClass);
1132      }
1133      catch (ClassNotFoundException JavaDoc ignoreMe) {}
1134
1135      return result;
1136    }
1137
1138    /**
1139     * find a class from <code>BaseCode</code> or its parent
1140     * @param className name of the class to be load or found
1141     * @param parentClass its parent class
1142     * @return <code>IClass</code>
1143     * @see net.sourceforge.transmogrify.symtab.SymbolTable
1144     * @see net.sourceforge.transmogrify.symtab.IClass
1145     * @see #loadClass(String)
1146     */

1147    private IClass findOrLoadClass(String JavaDoc className, IClass parentClass) {
1148      IClass result = null;
1149
1150      if (parentClass == null) {
1151        result = symbolTable.getBaseScope().getClassDefinition(className);
1152      }
1153      else {
1154        int index = className.lastIndexOf("$");
1155        if (index < 0) {
1156          index = className.lastIndexOf(".");
1157        }
1158
1159        result = parentClass.getClassDefinition(className.substring(index + 1));
1160      }
1161
1162      if (result == null) {
1163        result = loadClass(className);
1164      }
1165
1166      return result;
1167    }
1168
1169    /**
1170    *
1171    * If the class has a super class a reference to this super class
1172    * is added to this class.
1173    * @return <code>void</code>
1174    * @see net.sourceforge.transmogrify.symtab.ClassDef
1175    */

1176    private void setSuperclass() {
1177      if (_def.getTreeNode().getType() == TokenTypes.CLASS_DEF) {
1178        SymTabAST extendsNode = getExtendsNode(_def);
1179        if ( extendsNode != null ) {
1180          String JavaDoc superclassName = ASTUtil.constructDottedName(extendsNode);
1181          IClass superclass = _def.getClassDefinition(superclassName);
1182          if ( superclass != null ) {
1183            _def.setSuperclass( superclass );
1184            superclass.addSubclass( _def );
1185          }
1186        }
1187        else {
1188          _def.setSuperclass(new ExternalClass(Object JavaDoc.class));
1189        }
1190      }
1191      else {
1192        _def.setSuperclass(new ExternalClass(Object JavaDoc.class));
1193      }
1194    }
1195
1196    /**
1197    *
1198    * If the class implements an interface a reference to this interface
1199    * is added to this class.
1200    * @return <code>void</code>
1201    * @see net.sourceforge.transmogrify.symtab.ClassDef
1202    */

1203    private void addInterfaces() {
1204      SymTabAST implementsClause = null;
1205
1206      if (_def.getTreeNode().getType() == TokenTypes.CLASS_DEF) {
1207        implementsClause
1208          = _node.findFirstToken(TokenTypes.IMPLEMENTS_CLAUSE);
1209      }
1210      else {
1211        implementsClause
1212          = _node.findFirstToken(TokenTypes.EXTENDS_CLAUSE);
1213      }
1214
1215      if ( implementsClause != null ) {
1216        SymTabAST interfaceNode = (SymTabAST)implementsClause.getFirstChild();
1217        while ( interfaceNode != null ) {
1218          IClass implemented =
1219            _def.getClassDefinition(interfaceNode.getText());
1220          if ( implemented != null ) {
1221            _def.addInterface( implemented );
1222            implemented.addImplementor( _def );
1223          }
1224        interfaceNode = (SymTabAST)(interfaceNode.getNextSibling());
1225        }
1226      }
1227    }
1228  }
1229
1230  /**
1231   *
1232   * Completes a Variable by setting all required references
1233   *
1234   */

1235  class VariableFinisher extends DefinitionFinisher {
1236    VariableDef _def = null;
1237
1238
1239    /**
1240    *
1241    * Constructor. Creates a VariableFinishes from the <code>Definition</code>
1242    * @param def VariableDef to be finished
1243    * @see net.sourceforge.transmogrify.symtab.VariableDef
1244    */

1245    public VariableFinisher( Definition def ) {
1246      super( def );
1247      _def = (VariableDef)def;
1248    }
1249
1250
1251    /**
1252    *
1253    * Finishes the variable by setting the Type
1254    * @return <code>void</code>
1255    * @see #getType(Definition, SymTabAST)
1256    * @see net.sourceforge.transmogrify.symtab.VariableDef
1257    */

1258    public void finish() {
1259
1260      SymTabAST typeNode = _node.findFirstToken(TokenTypes.TYPE);
1261
1262      SymTabAST typeTextNode = (SymTabAST)(typeNode.getFirstChild());
1263      if ( typeTextNode.getType() == TokenTypes.ARRAY_DECLARATOR ) {
1264        typeTextNode = (SymTabAST)(typeTextNode.getFirstChild());
1265      }
1266      typeTextNode.setLine(ASTUtil.getLine( _def.getTreeNode() ));
1267
1268      IClass varType = getType(_def, typeNode);
1269      _def.setType( varType );
1270
1271    }
1272  }
1273
1274  /**
1275   *
1276   * Completes a Variable by setting all required references
1277   *
1278   */

1279  class MethodFinisher extends DefinitionFinisher {
1280    MethodDef _def = null;
1281
1282
1283    /**
1284    *
1285    * Creates a MethodFinisher from a <code> Definition <code>
1286    * @param def MethodDef to be finished
1287    * @see net.sourceforge.transmogrify.symtab.MethodDef
1288    */

1289    public MethodFinisher( Definition def ) {
1290      super( def );
1291      _def = (MethodDef)def;
1292    }
1293
1294    /**
1295    *
1296    * Completes a method by setting all references to return types,
1297    * signatures and exceptions.
1298    * @return <code>void</code>
1299    * @see #setReturnType()
1300    * @see #setSignature()
1301    * @see #setExceptionsThrown()
1302    */

1303    public void finish() {
1304      setReturnType();
1305      setSignature();
1306      setExceptionsThrown();
1307    }
1308
1309    /**
1310    *
1311    * setReturnType adds a reference to the methods return type
1312    * to the method definition
1313    * @return <code>void</code>
1314    * @see net.sourceforge.transmogrify.symtab.MethodDef
1315    * @see #getType(Definition, SymTabAST)
1316    * @see #getTypeNode()
1317    */

1318    private void setReturnType() {
1319      IClass type = null;
1320
1321      if ( isConstructor() ) {
1322        type = _def.getEnclosingClass();
1323      }
1324      else {
1325        type = getType(_def, getTypeNode());
1326      }
1327
1328      _def.setType(type);
1329    }
1330
1331    /**
1332    *
1333    * setSignature adds a reference to the methods paramaters
1334    * to the method definition
1335    * @return <code>void</code>
1336    * @see #makeVariableDef(SymTabAST, Definition)
1337    * @see VariableFinisher
1338    * @see net.sourceforge.transmogrify.symtab.MethodDef
1339    */

1340    private void setSignature() {
1341      SymTabAST parametersNode
1342        = _node.findFirstToken(TokenTypes.PARAMETERS);
1343
1344      SymTabAST parameterNode = (SymTabAST)(parametersNode.getFirstChild());
1345      while ( parameterNode != null ) {
1346        if (parameterNode.getType() == TokenTypes.PARAMETER_DEF) {
1347            VariableDef parameter = makeVariableDef( parameterNode, _def );
1348            new VariableFinisher( parameter ).finish();
1349            _def.addParameter( parameter );
1350        }
1351        parameterNode = (SymTabAST)(parameterNode.getNextSibling());
1352      }
1353
1354    }
1355
1356    /**
1357    *
1358    * setExceptionsThrown adds a reference to the methods Exceptions
1359    * to the method definition
1360    * @return <code>void</code>
1361    * @see net.sourceforge.transmogrify.symtab.SymbolTable
1362    * @see net.sourceforge.transmogrify.symtab.PackageDef
1363    * @see net.sourceforge.transmogrify.symtab.MethodDef
1364    */

1365    private void setExceptionsThrown() {
1366      IClass exception = null;
1367      SymTabAST throwsNode
1368        = _node.findFirstToken(TokenTypes.LITERAL_THROWS);
1369
1370      if ( throwsNode != null ) {
1371        SymTabAST exceptionNode = (SymTabAST)(throwsNode.getFirstChild());
1372        while (exceptionNode != null ) {
1373          if (exceptionNode.getType() == TokenTypes.DOT) {
1374            PackageDef pkg = symbolTable.getPackage(ASTUtil.constructPackage(exceptionNode));
1375            if ( pkg != null ) {
1376              exception = pkg.getClassDefinition(ASTUtil.constructClass(exceptionNode));
1377            }
1378          }
1379          else {
1380            exception = _def.getClassDefinition(exceptionNode.getText());
1381          }
1382          _def.addException(exception);
1383          exceptionNode = (SymTabAST)(exceptionNode.getNextSibling());
1384        }
1385      }
1386
1387    }
1388
1389    /**
1390    *
1391    * isConstructor sets the flag in the method definition to indicate
1392    * whether it is a constructor or not
1393    * @return <code>boolean</code> <code>true</code> if a node has no return type
1394    * <code>false</code> if a node has a return type
1395    * @see #getTypeNode()
1396    */

1397    private boolean isConstructor() {
1398      boolean result = false;
1399
1400      if ( getTypeNode() == null ) {
1401        result = true;
1402      }
1403
1404      return result;
1405    }
1406
1407    /**
1408    *
1409    * getTypeNode returnss the <code> SymTabAST</code> node that is the
1410    * return type of this method
1411    *
1412    * @return <code>SymTabAST</code>
1413    */

1414    private SymTabAST getTypeNode() {
1415      return _node.findFirstToken(TokenTypes.TYPE);
1416    }
1417  }
1418
1419  class CatchFinisher extends DefinitionFinisher {
1420    BlockDef _def = null;
1421
1422    /**
1423     * constructor that takes a <code>BlockDef</code>
1424     * @param def <code>BlockDef</code> for the catch block
1425     */

1426    public CatchFinisher(BlockDef def) {
1427      super(def);
1428      _def = def;
1429    }
1430
1431    /**
1432     * finishes definition creation
1433     * @return <code>void</code>
1434     * @see #createExceptionVariable()
1435     */

1436    public void finish() {
1437      createExceptionVariable();
1438    }
1439
1440    /**
1441     * creates <code>VariableDef<code> and finishes creation definition for
1442     * arguments in the catch clause
1443     * @return <code>void</code>
1444     * @see net.sourceforge.transmogrify.symtab.VariableDef
1445     * @see #makeVariableDef(SymTabAST, Definition)
1446     * @see VariableFinisher
1447     */

1448    private void createExceptionVariable() {
1449      SymTabAST exceptionNode
1450        = _def.getTreeNode().findFirstToken(TokenTypes.PARAMETER_DEF);
1451
1452      VariableDef exception = makeVariableDef(exceptionNode, _def);
1453      new VariableFinisher(exception).finish();
1454      _def.addDefinition(exception);
1455    }
1456  }
1457
1458}
1459
1460
1461
Popular Tags