001    /*BEGIN_COPYRIGHT_BLOCK
002     *
003     * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
004     * All rights reserved.
005     * 
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions are met:
008     *    * Redistributions of source code must retain the above copyright
009     *      notice, this list of conditions and the following disclaimer.
010     *    * Redistributions in binary form must reproduce the above copyright
011     *      notice, this list of conditions and the following disclaimer in the
012     *      documentation and/or other materials provided with the distribution.
013     *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014     *      names of its contributors may be used to endorse or promote products
015     *      derived from this software without specific prior written permission.
016     * 
017     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026     * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028     *
029     * This software is Open Source Initiative approved Open Source Software.
030     * Open Source Initative Approved is a trademark of the Open Source Initiative.
031     * 
032     * This file is part of DrJava.  Download the current version of this project
033     * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034     * 
035     * END_COPYRIGHT_BLOCK*/
036    
037    package edu.rice.cs.javalanglevels;
038    
039    import edu.rice.cs.javalanglevels.tree.*;
040    import edu.rice.cs.javalanglevels.parser.*;
041    import edu.rice.cs.javalanglevels.util.*;
042    import java.util.*;
043    import java.io.*;
044    
045    import junit.framework.TestCase;
046    
047    /** Class body walking LanguageLevelVisitor for the FullJava Language Level. Builds the symbol table for a .java file
048      * without performing any syntax checking.  This file will also be compiled by javac, which will catch the syntax
049      * errors.
050      */
051    public class ClassBodyFullJavaVisitor extends FullJavaVisitor {
052      
053      /**The SymbolData corresponding to this class.*/
054      private SymbolData _enclosing;
055      
056      /** Deprecated onstructor for ClassBodyFullJavaVisitor.
057        * @param sd  The SymbolData that encloses the context we are visiting.  Must be non-null.
058        * @param className The name of the enclosing class.  Must be non-null and non-empty.
059        * @param file  The source file this came from.
060        * @param packageName  The package the source file is in
061        * @importedFiles  A list of classes that were specifically imported
062        * @param importedPackages  A list of package names that were specifically imported
063        * @param classesInThisFile  A list of the classes that are yet to be defined in this source file
064        * @param continuations  A hashtable corresponding to the continuations (unresolved Symbol Datas) that will need to 
065        *                       be resolved
066        * TODO: coalesce className and enclosingClassName
067        */
068      public ClassBodyFullJavaVisitor(SymbolData sd, 
069                                      String className,
070                                      File file, 
071                                      String packageName,
072                                      LinkedList<String> importedFiles, 
073                                      LinkedList<String> importedPackages,
074                                      HashSet<String> classesInThisFile, 
075                                      Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
076                                      LinkedList<Command> fixUps) {
077        super(file, packageName, className, importedFiles, importedPackages, classesInThisFile, continuations, fixUps);
078        _enclosing = sd;
079        assert sd != null && className != null &&  ! className.equals("");
080      }
081      
082      /** Preferred constructor for ClassBodyFullJavaVisitor.
083        * @param sd  The SymbolData that encloses the context we are visiting.  Must be non-null.ty.
084        * @param file  The source file this came from.
085        * @param packageName  The package the source file is in
086        * @importedFiles  A list of classes that were specifically imported
087        * @param importedPackages  A list of package names that were specifically imported
088        * @param classesInThisFile  A list of the classes that are yet to be defined in this source file
089        * @param continuations  A hashtable corresponding to the continuations (unresolved Symbol Datas) that will need to 
090        *                       be resolved
091        * TODO: coalesce className and enclosingClassName
092        */
093      public ClassBodyFullJavaVisitor(SymbolData sd, 
094                                      File file, 
095                                      String packageName,
096                                      LinkedList<String> importedFiles, 
097                                      LinkedList<String> importedPackages,
098                                      HashSet<String> classesInThisFile, 
099                                      Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
100                                      LinkedList<Command> fixUps,
101                                      HashMap<String, SymbolData> genericTypes) {
102        super(file, packageName, sd.getName(), importedFiles, importedPackages, classesInThisFile, continuations, fixUps, 
103              genericTypes);
104        _enclosing = sd;
105        assert sd != null;
106      }
107      
108      /* Ignore ForStatement. */
109      public Void forStatementDoFirst(Statement that) { return null; }
110      
111      /** Ignore ConcreteMethodDef. */
112      
113      /** Ignore AbstractMake sure that this abstract method def is declared to be abstract. */
114      public Void forAbstractMethodDefDoFirst(AbstractMethodDef that) {
115        
116    //    ModifiersAndVisibility mav = that.getMav();
117    //    String[] modifiers = mav.getModifiers();
118        if (! _enclosing.isInterface() && ! _enclosing.hasModifier("abstract")) { // interfaces not yet marked abstract
119          _addError("Abstract methods can only be declared in abstract classes", that);
120        }
121        return super.forAbstractMethodDefDoFirst(that);
122      }
123      
124      /*Add an appropriate error*/
125      public Void forInstanceInitializerDoFirst(InstanceInitializer that) {
126        _addError("This open brace must mark the beginning of a method or class body", that);
127        return null;
128      }
129      
130      /** Processes a field declaration.  Converts the VariableDeclaration to VariableData[].  Adds the variable datas to 
131        * the symbol data, and gives an error if two fields have the same names
132        */
133      public Void forVariableDeclarationOnly(VariableDeclaration that) {
134    //    System.err.println("forVariableDeclarationOnly called in ClassBodyFullJavaVisitor for " + that);
135        VariableData[] vds = _variableDeclaration2VariableData(that, _enclosing);
136    //    System.err.println(" ## generated vds = " + Arrays.toString(vds));
137        
138        // Add the variable datas to the symbol data    
139        if (! _enclosing.addVars(vds)) {
140          _addAndIgnoreError("You cannot have two fields with the same name.  Either you already have a field by that " 
141                               + "name in this class, or one of your superclasses or interfaces has a field by that name", 
142                             that);
143        }
144        return null;
145      }
146      
147      /** Create a method data corresponding to this method declaration, and then visit the
148        * concrete method def with a new bodybody visitor, passing it the enclosing method data.
149        * Make sure the method name is different from the class name.
150        */
151      public Void forConcreteMethodDef(ConcreteMethodDef that) {
152        forConcreteMethodDefDoFirst(that);
153        if (prune(that)) return null;
154        assert _enclosing != null;
155        
156        TypeParameter[] tps = that.getTypeParams();
157    
158        // TODO !!! pass genericTypes as a parameter to createMethod and critical submethods.  The scope of the
159        // new generic types table includes all of createMethodData processing, notably processing the return type.
160        // Passing an extended generic types table to BodyBodyFullJavaVisitor is insufficient
161          
162        // Save a snapshot of _genericTypes
163        HashMap<String, SymbolData> oldGenericTypes = _genericTypes;
164        
165        // Rebind _genericTypes to a shallow copy of itself for use in processing this method. The temporary variable copy
166        // gets around a bug in javac in processing the SuppressWarnings statement.
167        @SuppressWarnings("unchecked")
168        HashMap<String, SymbolData> copy = (HashMap<String, SymbolData>) _genericTypes.clone();
169        _genericTypes = copy;
170        
171        if (tps != null && tps.length > 0) {  // extend genericTypes by new polymorphic method type variable bindings
172    //      Utilities.show("forConcreteMethodDef encountered a non-empty type parameters list:\n" + Arrays.toString(tps));
173    //      System.err.println("forConcreteMethodDef encountered a non-empty type parameters list:\n" + Arrays.toString(tps));
174          for (TypeParameter tp: tps) {
175            final String typeName = tp.getVariable().getName();
176            final String boundName = tp.getBound().getName();
177    //        System.err.println("***** Type variable " + typeName + " is bound to " + boundName);
178            SymbolData boundSD = _identifyType(boundName, that.getSourceInfo(), _enclosingClassName);
179    //        System.err.println("***** Corresponding SymbolData is " + boundSD);
180    //        Utilities.show("Type variable " + typeName + " is bound to " + boundName + " Corresponding SD is " + boundSD);
181            //  TODO: could create a separate unbound type variable singleton class?
182            if (boundSD == null) { // create a dummy SymbolData 
183              boundSD = symbolTable.get("java.lang.Object"); 
184    //        System.err.println("Creating dummy SymbolData for bounding type " + typeName + " in inner class " + name);
185              // TODO!  !!!!! Create an appropriate fixUp mechanism
186            }
187    //        System.err.println("In method " + _enclosing + "." + that.getName().getText() + ", type " + typeName 
188    //                             + " is bound to " + boundSD);
189            _genericTypes.put(typeName, boundSD);
190          }
191        }
192        
193        MethodData md = createMethodData(that, _enclosing);
194        String className = getUnqualifiedClassName(_enclosing.getName());
195        
196        if (className.equals(md.getName())) {
197          _addAndIgnoreError("Only constructors can have the same name as the class they appear in, and constructors "
198                               + "do not have an explicit return type",
199                             that);
200        }
201        else _enclosing.addMethod(md);
202        that.getBody().visit(new BodyBodyFullJavaVisitor(md, _file, _package, _enclosingClassName, _importedFiles, 
203                                                         _importedPackages, 
204                                                         _classesInThisFile, continuations, fixUps, 
205                                                         new HashSet<String>(), _genericTypes));
206        _genericTypes = oldGenericTypes;
207        return null;
208      }
209      
210      /** Creates a MethodData corresponding to this method declaration. Ensures that the method name is different from the 
211        * class name.
212        */
213      public Void forAbstractMethodDef(AbstractMethodDef that) {
214        forAbstractMethodDefDoFirst(that);
215        if (prune(that)) return null;
216        
217        assert _enclosing != null;
218        
219        // Process type parameters
220        TypeParameter[] tps = that.getTypeParams();
221    
222        // TODO !!! pass genericTypes as a parameter to createMethod and critical submethods.  The scope of the
223        // new generic types table includes all of createMethodData processing, notably processing the return type.
224        // Passing an extended generic types table to BodyBodyFullJavaVisitor is insufficient
225          
226        // Save a snapshot of _genericTypes
227        HashMap<String, SymbolData> oldGenericTypes = _genericTypes;
228        
229        // Rebind _genericTypes to a shallow copy of itself for use in processing this method. The temporary variable copy
230        // gets around a bug in javac in processing the SuppressWarnings statement.
231        @SuppressWarnings("unchecked")
232        HashMap<String, SymbolData> copy = (HashMap<String, SymbolData>)_genericTypes.clone();
233        _genericTypes = copy;
234        
235        if (tps != null) {  // extend genericTypes by new type variable bindings
236          for (TypeParameter tp: tps) {
237            final String typeName = tp.getVariable().getName();
238            final String boundName = tp.getBound().getName();
239            SymbolData boundSD = _identifyType(boundName, that.getSourceInfo(), _enclosingClassName);
240            if (boundSD == null) { // create a dummy SymbolData 
241              boundSD = symbolTable.get("java.lang.Object"); //  TODO: could create a separate unbound type variable singleton class?
242    //        System.err.println("Creating dummy SymbolData for bounding type " + typeName + " in inner class " + name);
243              // TODO!  !!!!! Create an appropriate fixUp mechanism
244            }
245    //        System.err.println("In method " + _enclosing + "." + that.getName().getText() + ", type " + typeName 
246    //                             + " is bound to " + boundSD);
247            _genericTypes.put(typeName, boundSD);
248          }
249        }
250        
251        MethodData md = createMethodData(that, _enclosing);
252        String className = getUnqualifiedClassName(_enclosing.getName());
253        if (className.equals(md.getName())) {
254          _addAndIgnoreError("Only constructors can have the same name as the class they appear in, and constructors do "
255                               + "not have an explicit return type",
256                             that);
257        }
258        else _enclosing.addMethod(md);
259        _genericTypes = oldGenericTypes;
260        return null;
261      }
262      
263      /**Call the method in FullJavaVisitor since it's common to this and FullJavaBodyFullJavaVisitor. */
264      public Void forInnerInterfaceDef(InnerInterfaceDef that) {
265        String relName = that.getName().getText();
266        handleInnerInterfaceDef(that, _enclosing, relName, getQualifiedClassName(_enclosing.getName()) + '.' + relName);
267        return null;
268      }
269      
270      /**Call the method in FullJavaVisitor since it's common to this and FullJavaBodyFullJavaVisitor. */
271      public Void forInnerClassDef(InnerClassDef that) {
272        String relName = that.getName().getText();
273        handleInnerClassDef(that, _enclosing, relName, getQualifiedClassName(_enclosing.getName()) + '.' + relName);
274        return null;
275      }
276      
277      /** Create a constructor corresponding to the specifications in the ConstructorDef, and then
278        * visit the constructor body, passing the constructor as the enclosing data.
279        */
280      public Void forConstructorDef(ConstructorDef that) {
281        forConstructorDefDoFirst(that);
282        if (prune(that)) return null;
283        
284        that.getMav().visit(this);
285        String name = getUnqualifiedClassName(that.getName().getText());
286        if ((that.getName().getText().indexOf('.') != -1 && ! that.getName().getText().equals(_enclosing.getName()))
287              || ! name.equals(getUnqualifiedClassName(_enclosing.getName()))) {
288          _addAndIgnoreError("The constructor return type and class name must match", that);
289        }
290        
291        // Turn the thrown exceptions from a ReferenceType[] to a String[]
292        String[] throwStrings = referenceType2String(that.getThrows());
293        
294        SymbolData returnType = _enclosing;
295        MethodData md = MethodData.make(name, that.getMav(), new TypeParameter[0], returnType, 
296                                        new VariableData[0], throwStrings, _enclosing, that);  // VariableData is dummy
297        
298        _checkError(); // reset check flag
299        // Turn the parameters from a FormalParameterList to a VariableData[]
300        VariableData[] vds = formalParameters2VariableData(that.getParameters(), _enclosing);
301        if (! _checkError()) {  //if there was an error converting the formalParameters, don't use them.
302          md.setParams(vds);
303          if (!md.addVars(vds)) {
304            _addAndIgnoreError("You cannot have two method parameters with the same name", that);
305          }
306        }
307        
308        _enclosing.addMethod(md);
309        that.getStatements().visit(new BodyBodyFullJavaVisitor(md, _file, _package, _enclosingClassName, _importedFiles, 
310                                                               _importedPackages, _classesInThisFile, continuations, fixUps,
311                                                               new HashSet<String>()));
312        
313        //note that we have seen a constructor.
314        _enclosing.incrementConstructorCount();
315        return null;
316      }
317      
318      /** Delegate to method in LanguageLevelVisitor */
319      public Void forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation that) {
320        complexAnonymousClassInstantiationHelper(that, _enclosing);  // TODO: the wrong enclosing context?
321        return null;
322      }
323      
324      /**Delegate to method in LanguageLevelVisitor */
325      public Void forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation that) {
326        simpleAnonymousClassInstantiationHelper(that, _enclosing);
327        return null;
328      }
329      
330      /** Check for problems with modifiers that are specific to method definitions. */
331      public Void forModifiersAndVisibilityDoFirst(ModifiersAndVisibility that) {
332        String[] modifiers = that.getModifiers();
333    //    System.err.println("***Checking for bad modifers in " + Arrays.toString(modifiers) + " isAbstact = " + 
334    //                       Utilities.isAbstract(modifiers) + " isStatic = " + Utilities.isStatic(modifiers));
335        if (Utilities.isAbstract(modifiers) && Utilities.isStatic(modifiers))  _badModifiers("static", "abstract", that);
336        return super.forModifiersAndVisibilityDoFirst(that);
337      }
338      
339      /** Test the methods that are declared above. */
340      public static class ClassBodyFullJavaVisitorTest extends TestCase {
341        
342        private ClassBodyFullJavaVisitor _cbfjv;
343        
344        private SymbolData _sd1;
345        private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
346        private ModifiersAndVisibility _protectedMav = 
347          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
348        private ModifiersAndVisibility _privateMav = 
349          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
350        private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
351        private ModifiersAndVisibility _abstractMav = 
352          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
353        private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
354        private ModifiersAndVisibility _staticMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static"});
355        private ModifiersAndVisibility _abstractStaticMav = 
356          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract", "static"});
357        private ModifiersAndVisibility _finalStaticMav = 
358          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static", "final"});
359        
360        
361        public ClassBodyFullJavaVisitorTest() { this(""); }
362        public ClassBodyFullJavaVisitorTest(String name) { super(name); }
363        
364        public void setUp() {
365          _sd1 = new SymbolData("i.like.monkey");  // creates a continuation
366          
367          errors = new LinkedList<Pair<String, JExpressionIF>>();
368          LanguageLevelConverter.symbolTable.clear();
369          LanguageLevelConverter.symbolTable.put("i.like.monkey", _sd1);
370          LanguageLevelConverter._newSDs.clear();
371          visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
372    //      _hierarchy = new Hashtable<String, TypeDefBase>();
373          _cbfjv = new ClassBodyFullJavaVisitor(_sd1, 
374                                                "i.like.monkey", 
375                                                new File(""), 
376                                                "", 
377                                                new LinkedList<String>(), 
378                                                new LinkedList<String>(), 
379                                                new HashSet<String>(), 
380                                                new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
381                                                new LinkedList<Command>());
382          _cbfjv._classesInThisFile = new HashSet<String>();
383          _cbfjv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(); // no _sd1
384    //      _cbfjv._resetNonStaticFields();
385          _cbfjv._importedPackages.addFirst("java.lang");
386          
387          _errorAdded = false;
388        }
389        
390        public void testForConcreteMethodDefDoFirst() {
391          // Check one that works
392          ConcreteMethodDef cmd = new ConcreteMethodDef(SourceInfo.NONE, 
393                                                        _publicMav, 
394                                                        new TypeParameter[0], 
395                                                        new PrimitiveType(SourceInfo.NONE, "int"), 
396                                                        new Word(SourceInfo.NONE, "methodName1"),
397                                                        new FormalParameter[0],
398                                                        new ReferenceType[0], 
399                                                        new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
400          cmd.visit(_cbfjv);
401          assertEquals("There should not be any errors", 0, errors.size());
402          
403          // Check one that doesn't work because it is declared abstract but is actually a concrete method
404          ConcreteMethodDef cmd2 = new ConcreteMethodDef(SourceInfo.NONE, 
405                                                         _abstractMav, 
406                                                         new TypeParameter[0], 
407                                                         new PrimitiveType(SourceInfo.NONE, "double"), 
408                                                         new Word(SourceInfo.NONE, "methodName2"),
409                                                         new FormalParameter[0],
410                                                         new ReferenceType[0], 
411                                                         new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
412          cmd2.visit(_cbfjv);
413          assertEquals("There should be one error", 1, errors.size());
414          assertEquals("The error message should be correct", 
415                       "Methods that have a braced body cannot be declared \"abstract\"", 
416                       errors.get(0).getFirst());
417          
418          //Check that a static method does not result in an error.
419          ConcreteMethodDef cmd3 = new ConcreteMethodDef(SourceInfo.NONE, 
420                                                         _staticMav, 
421                                                         new TypeParameter[0], 
422                                                         new PrimitiveType(SourceInfo.NONE, "double"), 
423                                                         new Word(SourceInfo.NONE, "methodName2"),
424                                                         new FormalParameter[0],
425                                                         new ReferenceType[0], 
426                                                         new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
427          cmd3.visit(_cbfjv);
428          assertEquals("There should still be one error", 1, errors.size());
429          
430          
431        }
432        
433        public void testForAbstractMethodDefDoFirst() {
434          // Check one that doesn't work
435          AbstractMethodDef amd = new AbstractMethodDef(SourceInfo.NONE, 
436                                                        _abstractMav, 
437                                                        new TypeParameter[0], 
438                                                        new PrimitiveType(SourceInfo.NONE, "int"), 
439                                                        new Word(SourceInfo.NONE, "methodName"),
440                                                        new FormalParameter[0],
441                                                        new ReferenceType[0]);
442          amd.visit(_cbfjv);
443          assertEquals("There should be one error.", 1, errors.size());
444          assertEquals("The error message should be correct.", "Abstract methods can only be declared in abstract classes", 
445                       errors.get(0).getFirst());
446          
447          // Check one that works
448          _cbfjv._enclosing.setMav(_abstractMav);
449          AbstractMethodDef amd2 = new AbstractMethodDef(SourceInfo.NONE, 
450                                                         _abstractMav, 
451                                                         new TypeParameter[0], 
452                                                         new PrimitiveType(SourceInfo.NONE, "double"), 
453                                                         new Word(SourceInfo.NONE, "methodName"),
454                                                         new FormalParameter[0],
455                                                         new ReferenceType[0]);
456          amd2.visit(_cbfjv);
457          assertEquals("There should still be one error", 1, errors.size());
458          
459          // Check that static methods are now allowed at the FullJava level.
460          AbstractMethodDef amd3 = new AbstractMethodDef(SourceInfo.NONE, 
461                                                         _abstractStaticMav, 
462                                                         new TypeParameter[0], 
463                                                         new PrimitiveType(SourceInfo.NONE, "double"), 
464                                                         new Word(SourceInfo.NONE, "methodName2"),
465                                                         new FormalParameter[0],
466                                                         new ReferenceType[0]);
467          amd3.visit(_cbfjv);
468          assertEquals("There should be two errors", 2, errors.size());
469          assertEquals("The error message should be correct.", 
470                       "Illegal combination of modifiers. Can't use static and abstract together.", 
471                       errors.get(1).getFirst());
472        }
473        
474        public void testForInstanceInitializerDoFirst() {
475          InstanceInitializer ii = new InstanceInitializer(SourceInfo.NONE, 
476                                                           new Block(SourceInfo.NONE, 
477                                                                     new BracedBody(SourceInfo.NONE, new BodyItemI[0])));
478          ii.visit(_cbfjv);
479          assertEquals("There should be one error.", 1, errors.size());
480          assertEquals("The error message should be correct.", 
481                       "This open brace must mark the beginning of a method or class body", errors.get(0).getFirst());
482        }
483        
484        public void testForVariableDeclaration() {
485          
486          ArrayInitializer ai = new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[0]);
487          TypeVariable tv = new TypeVariable(SourceInfo.NONE, "String");
488          SymbolData _string = LanguageLevelConverter.symbolTable.get("java.lang.String");
489          assertNotNull("java.lang.String already in table", _string);
490          ArrayType at = new ArrayType(SourceInfo.NONE, "String[]", tv);
491          
492          VariableDeclarator vd = 
493            new UninitializedVariableDeclarator(SourceInfo.NONE, at, new Word(SourceInfo.NONE, "myArray"));
494          
495          VariableDeclaration vdecl = 
496            new VariableDeclaration(SourceInfo.NONE, _publicMav, new VariableDeclarator[] { vd });
497          assertEquals("There should be no errors", 0, errors.size());
498          
499    //      System.err.println("*** Beginning traversal of VariableDeclaration with String[]");
500          vdecl.visit(_cbfjv);
501    //      System.err.println("Traversal of VariableDeclaration above is complete");
502          assertEquals("There should be no errors", 0, errors.size());
503    //      System.err.println("That error is: " + errors.getLast().getFirst());
504          
505          SymbolData bob = LanguageLevelConverter.symbolTable.get("java.lang.String[]");
506    //      System.err.println("Getting READY to fail");
507    //      try { Thread.sleep(1000); } catch (Exception e) { };
508          assertNotNull("bob should not be null", bob);
509        }
510        
511        /* These test is shared with BodyIntermediateVisitor, perhaps we could factor it out. */
512        
513        public void testForVariableDeclarationOnly() {
514          // Check one that works
515          VariableDeclaration vdecl = new VariableDeclaration(SourceInfo.NONE,
516                                                              _packageMav,
517                                                              new VariableDeclarator[] {
518            new UninitializedVariableDeclarator(SourceInfo.NONE, 
519                                                new PrimitiveType(SourceInfo.NONE, "double"), 
520                                                new Word (SourceInfo.NONE, "field1")),
521              new UninitializedVariableDeclarator(SourceInfo.NONE, 
522                                                  new PrimitiveType(SourceInfo.NONE, "boolean"), 
523                                                  new Word (SourceInfo.NONE, "field2"))});
524          VariableData vd1 = new VariableData("field1", _packageMav, SymbolData.DOUBLE_TYPE, false, _cbfjv._enclosing);
525          VariableData vd2 = new VariableData("field2", _packageMav, SymbolData.BOOLEAN_TYPE, false, _cbfjv._enclosing);
526          vdecl.visit(_cbfjv);
527          assertEquals("There should not be any errors.", 0, errors.size());
528          
529    //      System.err.println("_sd1 vars =  " + _sd1.getVars());
530          assertTrue("field1 was added.", _sd1.getVars().contains(vd1));
531          assertTrue("field2 was added.", _sd1.getVars().contains(vd2));
532          
533          // Check one that doesn't work
534          VariableDeclaration vdecl2 = 
535            new VariableDeclaration(SourceInfo.NONE,
536                                    _packageMav,
537                                    new VariableDeclarator[] {
538            new UninitializedVariableDeclarator(SourceInfo.NONE, 
539                                                new PrimitiveType(SourceInfo.NONE, "double"), 
540                                                new Word(SourceInfo.NONE, "field3")),
541              new UninitializedVariableDeclarator(SourceInfo.NONE, 
542                                                  new PrimitiveType(SourceInfo.NONE, "int"), 
543                                                  new Word(SourceInfo.NONE, "field3"))});
544          VariableData vd3 = new VariableData("field3", _packageMav, SymbolData.DOUBLE_TYPE, false, _cbfjv._enclosing);
545          vdecl2.visit(_cbfjv);
546          assertEquals("There should be one error.", 1, errors.size());
547          assertEquals("The error message should be correct", 
548                       "You cannot have two fields with the same name.  Either you already have a field by that name in " 
549                         + "this class, or one of your superclasses or interfaces has a field by that name", 
550                       errors.get(0).getFirst());
551    //      System.err.println("_sd1 vars =  " + _sd1.getVars());
552          assertTrue("field3 was added.", _sd1.getVars().contains(vd3));
553          
554          //Check a static field that has not been assigned (won't work)
555          VariableDeclaration vdecl3 = new VariableDeclaration(SourceInfo.NONE,
556                                                               _staticMav,
557                                                               new VariableDeclarator[] {
558            new UninitializedVariableDeclarator(SourceInfo.NONE, 
559                                                new PrimitiveType(SourceInfo.NONE, "double"), 
560                                                new Word (SourceInfo.NONE, "field4"))});
561          // true value for hasAssigned in next line based on default initialization provided by Java.  GOOD IDEA?
562          VariableData vd4 = new VariableData("field4", _staticMav, SymbolData.DOUBLE_TYPE, false, _cbfjv._enclosing);
563          vdecl3.visit(_cbfjv);
564    //      System.err.println("vd4 = " + vd4);
565          assertEquals("There should still be one error", 1, errors.size());
566    //      assertEquals("The error message should be correct", "All static fields must be initialized", 
567    //                   errors.get(1).getFirst());
568    //      System.err.println("_sd1 vars =  " + _sd1.getVars());
569          assertTrue("field4 was added.", _sd1.getVars().contains(vd4));
570          
571          //Check a non-static field that has been assigned.  (will work);
572          VariableDeclaration vdecl5 = new VariableDeclaration(SourceInfo.NONE,
573                                                               _publicMav,
574                                                               new VariableDeclarator[] {
575            new InitializedVariableDeclarator(SourceInfo.NONE, 
576                                              new PrimitiveType(SourceInfo.NONE, "double"), 
577                                              new Word(SourceInfo.NONE, "field5"), 
578                                              new DoubleLiteral(SourceInfo.NONE, 2.4))});
579          vdecl5.visit(_cbfjv);
580          VariableData vd5 = new VariableData("field5", _publicMav, SymbolData.DOUBLE_TYPE, true, _cbfjv._enclosing);
581          vd5.setHasInitializer(true);
582          assertEquals("There should still be one error", 1, errors.size());
583          assertTrue("Field 5 was added.", _sd1.getVars().contains(vd5));
584          
585    //      //check one that overrides the super class's field
586    //      VariableDeclaration vdecl6 = new VariableDeclaration(SourceInfo.NONE,
587    //                                                           _packageMav,
588    //                                                           new VariableDeclarator[] {
589    //        new UninitializedVariableDeclarator(SourceInfo.NONE, 
590    //                                            new PrimitiveType(SourceInfo.NONE, "double"), 
591    //                                            new Word(SourceInfo.NONE, "field6"))});
592    //      
593    //      
594    //      VariableData vd6 = new VariableData("field6", _packageMav, SymbolData.DOUBLE_TYPE, true, _cbfjv._enclosing);
595    //      SymbolData myData = new SymbolData("myData");
596    //      myData.addVar(vd6);
597    //      _cbfjv._enclosing.setSuperClass(myData);
598    //      vdecl6.visit(_cbfjv);
599    //      assertEquals("There should be two errors.", 2, errors.size());
600    //      assertEquals("The error message should be correct", 
601    //                   "You cannot have two fields with the same name.  Either you already have a field by that name in "
602    //                     + "this class, or one of your superclasses or interfaces has a field by that name", 
603    //                   errors.get(1).getFirst());
604          
605        }
606        
607        public void testFormalParameters2VariableData() {
608          FormalParameter[] fps = new FormalParameter[] {
609            new FormalParameter(SourceInfo.NONE, 
610                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
611                                                                    new PrimitiveType(SourceInfo.NONE, "double"), 
612                                                                    new Word (SourceInfo.NONE, "field1")),
613                                false),
614              new FormalParameter(SourceInfo.NONE, 
615                                  new UninitializedVariableDeclarator(SourceInfo.NONE, 
616                                                                      new PrimitiveType(SourceInfo.NONE, "boolean"), 
617                                                                      new Word (SourceInfo.NONE, "field2")),
618                                  false)};
619          
620          
621          VariableData vd1 = new VariableData("field1", _packageMav, SymbolData.DOUBLE_TYPE, true, _cbfjv._enclosing);
622          VariableData vd2 = new VariableData("field2", _packageMav, SymbolData.BOOLEAN_TYPE, true, _cbfjv._enclosing);
623          
624          VariableData[] mVds = new VariableData[] { vd1, vd2 };
625          
626          MethodData aMethod = new MethodData("method", 
627                                              _publicMav, 
628                                              new TypeParameter[0], 
629                                              _cbfjv._enclosing, 
630                                              mVds, 
631                                              new String[0], 
632                                              _cbfjv._enclosing,
633                                              null);
634          
635          VariableData[] vds = _cbfjv.formalParameters2VariableData(fps, _cbfjv._enclosing);
636          assertEquals("There should not be any errors.", 0, errors.size());
637          assertEquals("vd1 should be the first entry in vds.", vd1, vds[0]);
638          assertEquals("vd2 should be the second entry in vds.", vd2, vds[1]);
639        }
640        
641        
642        
643        
644        
645        public void xtestForConcreteMethodDef() {
646          // Test one that works.
647          MethodDef mdef = new ConcreteMethodDef(SourceInfo.NONE, 
648                                                 _packageMav, 
649                                                 new TypeParameter[0], 
650                                                 new PrimitiveType(SourceInfo.NONE, "int"), 
651                                                 new Word(SourceInfo.NONE, "methodName"),
652                                                 new FormalParameter[0],
653                                                 new ReferenceType[0], 
654                                                 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
655          mdef.visit(_cbfjv);
656          assertEquals("There should not be any errors.", 0, errors.size());
657          // Test one that doesn't work.
658          mdef = new ConcreteMethodDef(SourceInfo.NONE, 
659                                       _packageMav, 
660                                       new TypeParameter[0], 
661                                       new PrimitiveType(SourceInfo.NONE, "int"), 
662                                       new Word(SourceInfo.NONE, "monkey"),
663                                       new FormalParameter[0],
664                                       new ReferenceType[0], 
665                                       new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
666          mdef.visit(_cbfjv);
667          assertEquals("There should be one error.", 1, errors.size());
668          assertEquals("The error message should be correct.", 
669                       "Only constructors can have the same name as the class they appear in, and constructors do not have an explicit return type",
670                       errors.get(0).getFirst());
671        }
672        
673        public void xtestForAbstractMethodDef() {
674          // Test one that works.
675          MethodDef mdef = new AbstractMethodDef(SourceInfo.NONE, 
676                                                 _abstractMav, 
677                                                 new TypeParameter[0], 
678                                                 new PrimitiveType(SourceInfo.NONE, "int"), 
679                                                 new Word(SourceInfo.NONE, "methodName"),
680                                                 new FormalParameter[0],
681                                                 new ReferenceType[0]);
682          _cbfjv._enclosing.setMav(_abstractMav);
683          mdef.visit(_cbfjv);
684          assertEquals("There should not be any errors.", 0, errors.size());
685          // Test one that doesn't work.
686          mdef = new AbstractMethodDef(SourceInfo.NONE, 
687                                       _abstractMav, 
688                                       new TypeParameter[0], 
689                                       new PrimitiveType(SourceInfo.NONE, "int"), 
690                                       new Word(SourceInfo.NONE, "monkey"),
691                                       new FormalParameter[0],
692                                       new ReferenceType[0]);
693          mdef.visit(_cbfjv);
694          assertEquals("There should be one error.", 1, errors.size());
695          assertEquals("The error message should be correct.", 
696                       "Only constructors can have the same name as the class they appear in, and constructors do not have an explicit return type",
697                       errors.get(0).getFirst());
698        }
699        
700        
701        public void xtestForInitializedVariableDeclaratorDoFirst() {
702          InitializedVariableDeclarator ivd = new InitializedVariableDeclarator(SourceInfo.NONE,
703                                                                                new PrimitiveType(SourceInfo.NONE, "int"),
704                                                                                new Word(SourceInfo.NONE, "i"),
705                                                                                new IntegerLiteral(SourceInfo.NONE, 2));
706          
707          ivd.visit(_cbfjv);
708          
709          assertEquals("There should be no errors now", 0, errors.size());
710        }
711        
712        public void xtestForInnerClassDef() {
713          SymbolData obj = new SymbolData("java.lang.Object");
714          LanguageLevelConverter.symbolTable.put("java.lang.Object", obj);
715          InnerClassDef cd1 = new InnerClassDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Bart"),
716                                                new TypeParameter[0], new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]), new ReferenceType[0], 
717                                                new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
718          InnerClassDef cd0 = new InnerClassDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Lisa"),
719                                                new TypeParameter[0], new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]), new ReferenceType[0], 
720                                                new BracedBody(SourceInfo.NONE, new BodyItemI[] {cd1}));
721          
722          
723          SymbolData sd0 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa", _packageMav, new TypeParameter[0], obj, 
724                                          new ArrayList<SymbolData>(), null); 
725          _cbfjv._enclosing.addInnerClass(sd0);
726          sd0.setOuterData(_cbfjv._enclosing);
727          SymbolData sd1 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa$Bart", _packageMav, new TypeParameter[0], 
728                                          obj, new ArrayList<SymbolData>(), null); 
729          sd0.addInnerClass(sd1);
730          sd1.setOuterData(sd0);
731          
732          sd0.setIsContinuation(true);
733          sd1.setIsContinuation(true);
734          
735          
736          
737          LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa", sd0);
738    //      LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa$Bart", sd1);
739          
740          cd0.visit(_cbfjv);
741          
742    //      sd0.setName("Lisa");
743    //      sd1.setName("Bart");
744          
745          SymbolData sd = _cbfjv._enclosing.getInnerClassOrInterface("Lisa");
746          assertEquals("There should be no errors", 0, errors.size());
747          assertEquals("This symbolData should now have sd0 as an inner class", sd0, sd);
748          assertEquals("sd0 should have the correct outer data", _cbfjv._enclosing, sd0.getOuterData());
749          assertEquals("sd1 should have the correct outer data", sd0, sd1.getOuterData());
750          assertEquals("Sd should now have sd1 as an inner class", sd1, sd.getInnerClassOrInterface("Bart"));
751          
752          
753          assertEquals("Lisa should have 0 methods", 0, sd0.getMethods().size());
754          
755        }
756        
757        public void xtestForInnerInterfaceDef() {
758    //      SymbolData obj = new SymbolData("java.lang.Object");
759    //      LanguageLevelConverter.symbolTable.put("java.lang.Object", obj);
760          InnerInterfaceDef cd1 = new InnerInterfaceDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Bart"),
761                                                        new TypeParameter[0], new ReferenceType[0], 
762                                                        new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
763          
764          InnerInterfaceDef cd0 = new InnerInterfaceDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Lisa"),
765                                                        new TypeParameter[0], new ReferenceType[0], 
766                                                        new BracedBody(SourceInfo.NONE, new BodyItemI[] {cd1}));
767          
768          SymbolData sd0 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa", _packageMav, new TypeParameter[0], 
769                                          new ArrayList<SymbolData>(), null); 
770          SymbolData sd1 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa$Bart", _packageMav, new TypeParameter[0], 
771                                          new ArrayList<SymbolData>(), null);
772          sd0.addInnerInterface(sd1);
773          sd0.setIsContinuation(true);
774          sd1.setIsContinuation(true);
775          
776          _cbfjv._enclosing.addInnerInterface(sd0);
777          sd0.setOuterData(_cbfjv._enclosing);
778          
779          sd0.addInnerInterface(sd1);
780          sd1.setOuterData(sd0);
781          
782    //    
783    //      LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa", sd0);
784    //      LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa$Bart", sd1);
785          
786          cd0.visit(_cbfjv);
787          
788          SymbolData sd = _cbfjv._enclosing.getInnerClassOrInterface("Lisa");
789          
790          assertEquals("There should be no errors", 0, errors.size());
791          assertEquals("This symbolData should now have sd0 as an inner interface", sd0, sd);
792          assertEquals("sd0 should have the correct outer data", _cbfjv._enclosing, sd0.getOuterData());
793          assertEquals("sd1 should have the correct outer data", sd0, sd1.getOuterData());
794          assertEquals("Sd should now have sd1 as an inner interface", sd1, sd.getInnerClassOrInterface("Bart"));
795          assertTrue("Lisa should be an interface", sd0.isInterface());
796          assertTrue("Bart should be an interface", sd1.isInterface());
797          
798          
799        }
800        
801        public void xtestForConstructorDef() {
802          //this is a ConstructorDef with no formal parameters and no throws
803          ConstructorDef cd = new ConstructorDef(SourceInfo.NONE, new Word(SourceInfo.NONE, "MyClass"), _publicMav, new FormalParameter[0], new ReferenceType[0], 
804                                                 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
805          
806          //What if constructor name and SymbolData name don't match?  Should throw an error.
807          _cbfjv._enclosing = new SymbolData("NotRightName");
808          cd.visit(_cbfjv);
809          assertEquals("Should be 1 error", 1, errors.size());
810          assertEquals("Error message should be correct", "The constructor return type and class name must match", errors.getLast().getFirst());
811          
812          //If they are the same, it should work just fine.
813          _cbfjv._enclosing = new SymbolData("MyClass");
814          
815          MethodData constructor = new MethodData("MyClass", 
816                                                  _publicMav, 
817                                                  new TypeParameter[0], 
818                                                  _cbfjv._enclosing, 
819                                                  new VariableData[0], 
820                                                  new String[0], 
821                                                  _cbfjv._enclosing,
822                                                  null);
823          
824          
825          cd.visit(_cbfjv);
826          
827          
828          assertEquals("Should still be 1 error", 1, errors.size());
829          assertEquals("SymbolData should have 1 method", 1, _cbfjv._enclosing.getMethods().size());
830          assertTrue("SymbolData's constructor should be correct", _cbfjv._enclosing.getMethods().contains(constructor));
831          
832          //With a ConstructorDef with more throws and variables, should work okay.
833          FormalParameter fp = 
834            new FormalParameter(SourceInfo.NONE, 
835                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
836                                                                    new PrimitiveType(SourceInfo.NONE, "int"), 
837                                                                    new Word(SourceInfo.NONE, "i")), 
838                                false);
839          ReferenceType rt = new TypeVariable(SourceInfo.NONE, "MyMadeUpException");
840          ConstructorDef cd2 = 
841            new ConstructorDef(SourceInfo.NONE, 
842                               new Word(SourceInfo.NONE, "MyClass"), 
843                               _publicMav, 
844                               new FormalParameter[] {fp}, 
845                               new ReferenceType[] {rt}, 
846                               new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
847          
848          VariableData vd = new VariableData("i", _finalMav, SymbolData.INT_TYPE, true, null);
849          MethodData constructor2 = new MethodData("MyClass", _publicMav, new TypeParameter[0], _cbfjv._enclosing, 
850                                                   new VariableData[] {vd}, 
851                                                   new String[] {"MyMadeUpException"}, 
852                                                   _cbfjv._enclosing,
853                                                   null);
854          
855          
856          
857          constructor2.addVar(vd);
858          cd2.visit(_cbfjv);
859          vd.setEnclosingData(_cbfjv._enclosing.getMethods().getLast());                                        
860          assertEquals("Should still be 1 error", 1, errors.size());
861          assertEquals("SymbolData should have 2 methods", 2, _cbfjv._enclosing.getMethods().size());
862          
863          assertTrue("SymbolData should have new constructor", _cbfjv._enclosing.getMethods().contains(constructor2));
864          
865          
866          //If two variable names are duplicated, should throw an error.
867          FormalParameter fp2 = 
868            new FormalParameter(SourceInfo.NONE, 
869                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
870                                                                    new PrimitiveType(SourceInfo.NONE, "double"), 
871                                                                    new Word(SourceInfo.NONE, "i")), 
872                                false);
873          
874          ConstructorDef cd3 = 
875            new ConstructorDef(SourceInfo.NONE, 
876                               new Word(SourceInfo.NONE, "MyClass"), 
877                               _publicMav,
878                               new FormalParameter[] {fp, fp2}, 
879                               new ReferenceType[] {rt}, 
880                               new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
881          cd3.visit(_cbfjv);
882          
883          assertEquals("Should now be 2 errors", 2, errors.size());
884          assertEquals("Error message should be correct","You cannot have two method parameters with the same name" , 
885                       errors.getLast().getFirst());
886          
887          //Test that an error is thrown if the class name and constructor name are packaged differently
888          _cbfjv._enclosing.setName("package.MyClass2");
889          ConstructorDef cd4 = 
890            new ConstructorDef(SourceInfo.NONE, 
891                               new Word(SourceInfo.NONE, "different.MyClass2"), 
892                               _publicMav, 
893                               new FormalParameter[0], 
894                               new ReferenceType[0], 
895                               new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
896          cd4.visit(_cbfjv);
897          
898          assertEquals("There should now be 3 errors", 3, errors.size());
899          assertEquals("Error message should be correct", "The constructor return type and class name must match", errors.getLast().getFirst());
900        }
901        public void testDummy() { }
902      }
903    }