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    
043    import java.util.*;
044    import java.io.*;
045    
046    import junit.framework.TestCase;
047    
048    /*
049     * Language Level Visitor that represents the Intermediate Language Level.  Enforces constraints during the
050     * first walk of the AST (checking for langauge specific errors and building the symbol table).
051     * This class enforces things that are common to all contexts reachable within a class body at 
052     * the Intermediate Language Level. 
053     */
054    public class ClassBodyIntermediateVisitor extends IntermediateVisitor {
055      
056      /** The SymbolData corresponding to this class. */
057      private SymbolData _enclosing;
058      
059      /** Constructor for ClassBodyAdvancedVisitor.
060        * @param sd  The SymbolData that encloses the context we are visiting.
061        * @param file  The source file this came from.
062        * @param packageName  The package the source file is in
063        * @importedFiles  A list of classes that were specifically imported
064        * @param importedPackages  A list of package names that were specifically imported
065        * @param classesInThisFile  A list of the classes that are yet to be defined in this source file
066        * @param continuations  A hashtable corresponding to the continuations (unresolved Symbol Datas) that will need to 
067        *                       be resolved
068        * @param fixUps  A list of commands to be performed after this pass to fixup the symbolTable
069        */
070      public ClassBodyIntermediateVisitor(SymbolData sd,
071                                          String className,
072                                          File file, 
073                                          String packageName, 
074                                          LinkedList<String> importedFiles, 
075                                          LinkedList<String> importedPackages, 
076                                          HashSet<String> classesInThisFile, 
077                                          Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
078                                          LinkedList<Command> fixUps) {
079        super(file,  packageName, className, importedFiles, importedPackages, classesInThisFile, continuations, fixUps);    
080        _enclosing = sd;
081      }
082      
083      /*Add an appropriate error*/
084      public Void forStatementDoFirst(Statement that) {
085        _addError("Statements cannot appear outside of method bodies", that);
086        return null;
087      }
088      
089      /** Ignore AbstractMake sure that this abstract method def is declared to be abstract. */
090      public Void forAbstractMethodDefDoFirst(AbstractMethodDef that) {
091    
092    //    ModifiersAndVisibility mav = that.getMav();
093    //    String[] modifiers = mav.getModifiers();
094        if (! _enclosing.isInterface() && ! _enclosing.hasModifier("abstract")) { // interfaces not yet marked abstract
095          _addError("Abstract methods can only be declared in abstract classes", that);
096        }
097        return super.forAbstractMethodDefDoFirst(that);
098      }
099    
100      /**Add an appropriate error*/
101      public Void forInstanceInitializerDoFirst(InstanceInitializer that) {
102        _addError("This open brace must mark the beginning of a method or class body", that);
103        return null;
104      }
105        
106      /** Processes a field declaration. Converts VariableDeclaration to VariableData[].  Ensures that no fields are 
107        * declared to be abstract. Finally, adds the variable datas to the symbol data, and emits an 
108        * error if two fields have the same names. */
109      public Void forVariableDeclarationOnly(VariableDeclaration that) {
110    //    System.err.println("Calling _variableDeclaration2VariableData on " + that);
111        VariableData[] vds = _variableDeclaration2VariableData(that, _enclosing);
112    //    System.err.println("Constructed vds array = " + Arrays.toString(vds));
113        // make sure that every non-static field is private and no static field are uninitialized:
114    //    LinkedList<VariableData> vdsList = new LinkedList<VariableData>();
115        for (int i = 0; i < vds.length; i++) {
116          if (! vds[i].isStatic()) vds[i].setPrivate();
117          else if (that.getDeclarators()[i] instanceof UninitializedVariableDeclarator) {  
118            _addAndIgnoreError("All static fields must be initialized", that);
119          }
120    // TODO: where is abstract check?     
121        }
122    //    System.err.println("Processed vds array = " + Arrays.toString(vds));
123        if (! _enclosing.addFinalVars(vds /* vdsList.toArray(new VariableData[vdsList.size()]) */)) {
124    //      System.err.println("Duplicate variable declaration found");
125          _addAndIgnoreError("You cannot have two fields with the same name.  Either you already have a field by that "
126                               + "name in this class, or one of your superclasses or interfaces has a field by that name", 
127                             that);
128        }
129        return null;
130      }
131    
132      // TODO: lift the following two methods to LLV since they are identical in ClassBodyFullJavaVisitor. 
133      
134      /** Call the method in FullJavaVisitor since it's common to this and FullJavaBodyFullJavaVisitor. */
135      public Void forInnerInterfaceDef(InnerInterfaceDef that) {
136        String relName = that.getName().getText();
137        String innerClassName = getQualifiedClassName(_enclosing.getName()) + '.' + relName; 
138        handleInnerInterfaceDef(that, _enclosing, relName, innerClassName);
139        return null;
140      }
141      /** Process a local inner class definition */
142      public Void forInnerClassDef(InnerClassDef that) {
143    //    System.err.println("CBIV.forInnerClassDef called on " + that.getName());
144        String relName = that.getName().getText();
145        String innerClassName = getQualifiedClassName(_enclosing.getName()) + '.' + relName;
146        handleInnerClassDef(that, _enclosing, relName, innerClassName);
147        return null;
148      }
149      
150      /** Creates a method data corresponding to this method declaration, and then visit the concrete method def with a new 
151        * bodybody visitor, passing it the enclosing method data. Methods are still public by default, but this can be 
152        * overridden by the user. Make sure the method name is different from the class name.
153        */
154      public Void forConcreteMethodDef(ConcreteMethodDef that) {
155        forConcreteMethodDefDoFirst(that);
156        if (prune(that)) return null;
157        MethodData md = createMethodData(that, _enclosing);
158        
159        // At Intermediate Level, methods are still public by default.
160        if (! md.hasModifier("public") && ! md.hasModifier("private") && ! md.hasModifier("protected")) {
161          md.addModifier("public");
162        }
163    
164        String className = getUnqualifiedClassName(_enclosing.getName());
165        if (className.equals(md.getName())) {
166          _addAndIgnoreError("Only constructors can have the same name as the class they appear in, and constructors do "
167                               + "not have an explicit return type",
168                             that);
169        }
170        else _enclosing.addMethod(md);
171    
172        that.getBody().visit(new BodyBodyIntermediateVisitor(md, _file, _package, _enclosingClassName, _importedFiles, 
173                                                             _importedPackages, _classesInThisFile, continuations, 
174                                                             fixUps, new HashSet<String>()));
175        return forConcreteMethodDefOnly(that);
176      }
177      
178      /** Create a method data corresponding to this method declaration.
179        * Make sure the method name is different from the class name.
180        * At the Intermediate Level, methods are public by default, but this can be overridden by the user.
181        */
182      public Void forAbstractMethodDef(AbstractMethodDef that) {
183        forAbstractMethodDefDoFirst(that);
184        if (prune(that)) return null;
185        MethodData md = createMethodData(that, _enclosing);
186        
187        // At Intermediate Level, methods are still public by default.
188        if (! md.hasModifier("public") && ! md.hasModifier("private") && ! md.hasModifier("protected")) {
189          md.addModifier("public");
190        }
191    
192        String className = getUnqualifiedClassName(_enclosing.getName());
193        if (className.equals(md.getName())) {
194          _addAndIgnoreError("Only constructors can have the same name as the class they appear in, and constructors do "
195                               + "not have an explicit return type",
196                             that);
197        }
198        else _enclosing.addMethod(md);
199    
200        return forAbstractMethodDefOnly(that);
201      }
202      
203      /** Create a constructor corresponding to the specifications in the ConstructorDef.  */
204      public Void forConstructorDef(ConstructorDef that) {
205        forConstructorDefDoFirst(that);
206        if (prune(that)) return null;
207    
208        that.getMav().visit(this);
209        String name = getUnqualifiedClassName(that.getName().getText());
210        if (! name.equals(getUnqualifiedClassName(_enclosing.getName()))) {
211          _addAndIgnoreError("The constructor return type and class name must match", that);
212        }
213    
214        // Turn the thrown exceptions from a ReferenceType[] to a String[]
215        String[] throwStrings = referenceType2String(that.getThrows());
216        
217        SymbolData returnType = _enclosing;
218        MethodData md = new MethodData(name, that.getMav(), new TypeParameter[0], returnType, 
219                                       new VariableData[0], throwStrings, _enclosing, that);  // VariableData is dummy
220        
221        // At Intermediate Level, constructors are still public by default.
222        if (! md.hasModifier("public") && ! md.hasModifier("private") && ! md.hasModifier("protected")) {
223          md.addModifier("public");
224        }
225        
226        _checkError(); // reset check flag
227        
228        // Turn the parameters from a FormalParameterList to a VariableData[]
229        VariableData[] vds = formalParameters2VariableData(that.getParameters(), _enclosing);
230        if (! _checkError()) {  // if there was an error converting the formalParameters, don't use them.
231          md.setParams(vds);
232          if (! md.addFinalVars(vds)) {
233            _addAndIgnoreError("You cannot have two method parameters with the same name", that);
234          }
235        }
236        
237        _enclosing.addMethod(md);
238        that.getStatements().visit(new BodyBodyIntermediateVisitor(md, _file, _package, _enclosingClassName, _importedFiles,
239                                                                   _importedPackages, _classesInThisFile, continuations, 
240                                                                   fixUps, new HashSet<String>()));
241        //note that we have seen a constructor.
242        _enclosing.incrementConstructorCount();
243        return forConstructorDefOnly(that);
244      }
245      
246      /** Delegate to method in LLV. */
247      public Void forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation that) {
248        complexAnonymousClassInstantiationHelper(that, _enclosing);   // TODO: the wrong enclosing context?
249        return null;
250      }
251    
252      /** Delegate to method in LLV. */
253      public Void forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation that) {
254        simpleAnonymousClassInstantiationHelper(that, _enclosing);
255        return null;
256      }
257        
258    //  /** Check for problems with modifiers that are specific to method definitions. */
259    //  public Void forModifiersAndVisibilityDoFirst(ModifiersAndVisibility that) {
260    //    String[] modifiers = that.getModifiers();
261    //    if (Utilities.isAbstract(modifiers) && Utilities.isStatic(modifiers)) _badModifiers("static", "abstract", that);
262    //    return super.forModifiersAndVisibilityDoFirst(that);
263    //  }
264      
265      /** Test the methods in the above (enclosing) class. */
266      public static class ClassBodyIntermediateVisitorTest extends TestCase {
267        
268        private ClassBodyIntermediateVisitor _cbiv;
269        
270        private SymbolData _sd1;
271        private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
272        private ModifiersAndVisibility _publicFinalMav = 
273          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "final"});
274        private ModifiersAndVisibility _protectedMav = 
275          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
276        private ModifiersAndVisibility _privateMav = 
277          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
278        private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
279        private ModifiersAndVisibility _abstractMav =
280          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
281        private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
282        private ModifiersAndVisibility _staticMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static"});
283        private ModifiersAndVisibility _abstractStaticMav =
284          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract", "static"});
285        private ModifiersAndVisibility _privateAbstractMav = 
286          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private", "abstract"});
287        private ModifiersAndVisibility _staticFinalMav = 
288          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static", "final"});
289         private ModifiersAndVisibility _finalStaticMav = 
290          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "static"});
291        private ModifiersAndVisibility _finalPrivateMav = 
292          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "private"});
293        private ModifiersAndVisibility _privateFinalMav = 
294          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private", "final"});
295        
296        
297        public ClassBodyIntermediateVisitorTest() { this(""); }
298        public ClassBodyIntermediateVisitorTest(String name) { super(name); }
299        
300        public void setUp() {
301          _sd1 = new SymbolData("i.like.monkey");
302    
303          errors = new LinkedList<Pair<String, JExpressionIF>>();
304          LanguageLevelConverter.symbolTable.clear();
305          LanguageLevelConverter._newSDs.clear();
306          LanguageLevelConverter.symbolTable.put("i.like.monkey", _sd1);
307          visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
308    //      _hierarchy = new Hashtable<String, TypeDefBase>();
309          _cbiv = new ClassBodyIntermediateVisitor(_sd1,
310                                                   _sd1.getName(),
311                                                   new File(""), 
312                                                   "", 
313                                                   new LinkedList<String>(), 
314                                                   new LinkedList<String>(), 
315                                                   new HashSet<String>(), 
316                                                   new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
317                                                   new LinkedList<Command>());
318          _cbiv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(); // no _sd1
319          _cbiv._classesInThisFile = new HashSet<String>();
320    //      _cbiv._resetNonStaticFields();
321          _cbiv._importedPackages.addFirst("java.lang");
322          _errorAdded = false;
323        }
324        
325        public void testForConcreteMethodDefDoFirst() {
326          // Check one that works
327          ConcreteMethodDef cmd = new ConcreteMethodDef(SourceInfo.NONE, 
328                                                        _privateMav, 
329                                                        new TypeParameter[0], 
330                                                        new PrimitiveType(SourceInfo.NONE, "int"), 
331                                                        new Word(SourceInfo.NONE, "methodName"),
332                                                        new FormalParameter[0],
333                                                        new ReferenceType[0], 
334                                                        new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
335          cmd.visit(_cbiv);
336          assertEquals("There should not be any errors", 0, errors.size());
337          
338          
339          
340          // Check one that doesn't work because it is declared abstract but is actually a concrete method
341          ConcreteMethodDef cmd2 = new ConcreteMethodDef(SourceInfo.NONE, 
342                                                         _abstractMav, 
343                                                         new TypeParameter[0], 
344                                                         new PrimitiveType(SourceInfo.NONE, "double"), 
345                                                         new Word(SourceInfo.NONE, "methodName"),
346                                                         new FormalParameter[0],
347                                                         new ReferenceType[0], 
348                                                         new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
349          cmd2.visit(_cbiv);
350          assertEquals("There should be one error", 1, errors.size());
351          assertEquals("The error message should be correct", 
352                       "Methods that have a braced body cannot be declared \"abstract\"", 
353                       errors.get(0).getFirst());
354          
355    //      // Check one that doesn't work because it is static
356    //      ConcreteMethodDef cmd3 = new ConcreteMethodDef(SourceInfo.NONE, 
357    //                                                     _staticMav, 
358    //                                                     new TypeParameter[0], 
359    //                                                     new PrimitiveType(SourceInfo.NONE, "double"), 
360    //                                                     new Word(SourceInfo.NONE, "methodName"),
361    //                                                     new FormalParameter[0],
362    //                                                     new ReferenceType[0], 
363    //                                                     new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
364    //      cmd3.visit(_cbiv);
365    //      assertEquals("There should be two errors", 2, errors.size());
366    //      assertEquals("The error message should be correct", 
367    //                   "Static methods cannot be used at the Intermediate level", 
368    //                   errors.get(1).getFirst());
369    //      
370          
371        }
372        
373        public void testForAbstractMethodDefDoFirst() {
374          // Check one that doesn't work
375          AbstractMethodDef amd = new AbstractMethodDef(SourceInfo.NONE, 
376                                                        _abstractMav, 
377                                                        new TypeParameter[0], 
378                                                        new PrimitiveType(SourceInfo.NONE, "int"), 
379                                                        new Word(SourceInfo.NONE, "methodName"),
380                                                        new FormalParameter[0],
381                                                        new ReferenceType[0]);
382          amd.visit(_cbiv);
383          assertEquals("There should be one error.", 1, errors.size());
384          assertEquals("The error message should be correct.", "Abstract methods can only be declared in abstract classes", 
385                       errors.get(0).getFirst());
386          
387          // Check one that works
388          _cbiv._enclosing.setMav(_abstractMav);
389          AbstractMethodDef amd2 = new AbstractMethodDef(SourceInfo.NONE, 
390                                                         _abstractMav, 
391                                                         new TypeParameter[0], 
392                                                         new PrimitiveType(SourceInfo.NONE, "double"), 
393                                                         new Word(SourceInfo.NONE, "methodName"),
394                                                         new FormalParameter[0],
395                                                         new ReferenceType[0]);
396          amd2.visit(_cbiv);
397          assertEquals("There should still be one error", 1, errors.size());
398          
399    //      // Check one that doesn't work because it is static
400    //      AbstractMethodDef amd3 = new AbstractMethodDef(SourceInfo.NONE, 
401    //                                                     _abstractStaticMav, 
402    //                                                     new TypeParameter[0], 
403    //                                                     new PrimitiveType(SourceInfo.NONE, "double"), 
404    //                                                     new Word(SourceInfo.NONE, "methodName"),
405    //                                                     new FormalParameter[0],
406    //                                                     new ReferenceType[0]);
407    //      amd3.visit(_cbiv);
408    //      assertEquals("There should be two errors", 2, errors.size());
409    //      assertEquals("The error message should be correct", "Static methods cannot be used at the Intermediate level", 
410    //                   errors.get(1).getFirst());
411        }
412    
413        public void testForInstanceInitializerDoFirst() {
414          InstanceInitializer ii = new InstanceInitializer(SourceInfo.NONE, 
415                                                           new Block(SourceInfo.NONE, 
416                                                                     new BracedBody(SourceInfo.NONE, new BodyItemI[0])));
417          ii.visit(_cbiv);
418          assertEquals("There should be one error.", 1, errors.size());
419          assertEquals("The error message should be correct.", 
420                       "This open brace must mark the beginning of a method or class body", 
421                       errors.get(0).getFirst());
422        }
423        
424        /* These test is shared with BodyIntermediateVisitor,
425         * perhaps we could factor it out. */
426        
427        public void testForVariableDeclarationOnly() {
428          // Check one that works
429          VariableDeclaration vdecl = new VariableDeclaration(SourceInfo.NONE,
430                                                              _packageMav,
431                                                              new VariableDeclarator[] {
432            new UninitializedVariableDeclarator(SourceInfo.NONE, 
433                                                new PrimitiveType(SourceInfo.NONE, "double"), 
434                                                new Word (SourceInfo.NONE, "field1")),
435              new UninitializedVariableDeclarator(SourceInfo.NONE, 
436                                                  new PrimitiveType(SourceInfo.NONE, "boolean"), 
437                                                  new Word (SourceInfo.NONE, "field2"))});
438          VariableData vd1 = 
439            new VariableData("field1", _privateFinalMav, SymbolData.DOUBLE_TYPE, false, _cbiv._enclosing);
440          VariableData vd2 = 
441            new VariableData("field2", _privateFinalMav, SymbolData.BOOLEAN_TYPE, false, _cbiv._enclosing);
442          vdecl.visit(_cbiv);
443          
444    //      VariableData vd0 = _sd1.getVars().get(0);
445    //      System.err.println("Errors were: " + errors);
446          assertEquals("There should not be any errors.", 0, errors.size());
447    //      System.err.println("_sd1.getVars() = " + _sd1.getVars());
448    //      
449    //      System.err.println("vd1 = " + vd1);
450    //      System.err.println("vd1.getMav() = " + vd1.getMav());
451    //      System.err.println("vd1.getType() = " + vd1.getType());
452    //      System.err.println("vd1.getMav().getModifiers() = " + vd1.getMav().getModifiers());
453    //      assertEquals("enclosingData are equal", vd1.getEnclosingData(), vd0.getEnclosingData());
454    //      assertEquals("mavs are equal", vd1.getMav(), vd0.getMav());
455    //      assertEquals("vd1.equals(vd0)", vd1, vd0);
456    
457    //      System.err.println("_sd1 vars =  " + _sd1.getVars());
458    //      System.err.println("vd1 = " + vd1 + "; vd2 = " + vd2);
459          assertTrue("field1 was added.", _sd1.getVars().contains(vd1));
460          assertTrue("field2 was added.", _sd1.getVars().contains(vd2));
461          
462          //TODO: Test that static fields are made public
463          
464          // Check one that doesn't work
465          VariableDeclaration vdecl2 = new VariableDeclaration(SourceInfo.NONE,
466                                                            _packageMav,
467                                                            new VariableDeclarator[] {
468            new UninitializedVariableDeclarator(SourceInfo.NONE, 
469                                                new PrimitiveType(SourceInfo.NONE, "double"), 
470                                                new Word (SourceInfo.NONE, "field3")),
471            new UninitializedVariableDeclarator(SourceInfo.NONE, 
472                                                new PrimitiveType(SourceInfo.NONE, "int"), 
473                                                new Word (SourceInfo.NONE, "field3"))});
474          VariableData vd3 = 
475            new VariableData("field3", _privateFinalMav, SymbolData.DOUBLE_TYPE, false, _cbiv._enclosing);
476          vdecl2.visit(_cbiv);
477          assertEquals("There should be one error.", 1, errors.size());
478          assertEquals("The error message should be correct", 
479                       "You cannot have two fields with the same name.  Either you already have a field by that name in "
480                         + "this class, or one of your superclasses or interfaces has a field by that name", 
481                       errors.get(0).getFirst());
482    //      System.err.println("_sd1 vars =  " + _sd1.getVars());
483    //      System.err.println("vd3 = " + vd3);
484          assertTrue("field3 was added.", _sd1.getVars().contains(vd3));
485          
486          //Check a static field that has not been assigned is an error
487          VariableDeclaration vdecl3 = new VariableDeclaration(SourceInfo.NONE,
488                                                               _staticMav,
489                                                               new VariableDeclarator[] {
490            new UninitializedVariableDeclarator(SourceInfo.NONE, 
491                                                new PrimitiveType(SourceInfo.NONE, "double"), 
492                                                new Word (SourceInfo.NONE, "field4"))});
493          VariableData vd4 = 
494            new VariableData("field4", _staticFinalMav, SymbolData.DOUBLE_TYPE, false, _cbiv._enclosing);  
495          
496          vdecl3.visit(_cbiv);
497    //      System.err.println("vd4 = " + vd4);;
498    //      assertEquals("There should still be one error", 1, errors.size());
499          assertEquals("The error message should be correct", "All static fields must be initialized", 
500                       errors.get(1).getFirst());
501    //      System.err.println("_sd1 vars =  " + _sd1.getVars());
502          assertTrue("field4 was added.", _sd1.getVars().contains(vd4));   
503          
504          // Check a non-static field that has been assigned.
505          VariableDeclaration vdecl5 = new VariableDeclaration(SourceInfo.NONE,
506                                                            _packageMav,
507                                                            new VariableDeclarator[] {
508            new InitializedVariableDeclarator(SourceInfo.NONE, 
509                                                new PrimitiveType(SourceInfo.NONE, "double"), 
510                                                new Word (SourceInfo.NONE, "field5"), 
511                                              new DoubleLiteral(SourceInfo.NONE, 2.4))});
512          vdecl5.visit(_cbiv);
513          VariableData vd5 = 
514            new VariableData("field5", _privateFinalMav, SymbolData.DOUBLE_TYPE, true, _cbiv._enclosing);
515          vd5.setHasInitializer(true);
516    //      VariableData vd0 = _sd1.getVars().get(4);
517    //      System.err.println("vd5 = " + vd5);
518    //      System.err.println("vd0 = " + vd0);
519    //      System.err.println("vd5.getMav() = " + vd5.getMav());
520    //      System.err.println("vd5.getType() = " + vd5.getType());
521    //      System.err.println("vd0.getMav() = " + vd0.getMav());
522    //      System.err.println("vd0.getType() = " + vd0.getType());
523    //      assertEquals("mavs are equal", vd5.getMav(), vd0.getMav());
524    //      assertEquals("enclosingData are equal", vd5.getEnclosingData(), vd0.getEnclosingData());
525    //      assertEquals("vd5.equals(vd0)", vd5, vd0);
526          assertTrue("Field 5 was added.", _sd1.getVars().contains(vd5));
527          
528          // Check one that overrides the super class's field
529          VariableDeclaration vdecl6 = new VariableDeclaration(SourceInfo.NONE,
530                                                           _packageMav,
531                                                               new VariableDeclarator[] {
532            new UninitializedVariableDeclarator(SourceInfo.NONE, 
533                                                new PrimitiveType(SourceInfo.NONE, "double"), 
534                                                new Word (SourceInfo.NONE, "field6"))});
535          
536          
537          VariableData vd6 = 
538            new VariableData("field6", _finalPrivateMav, SymbolData.DOUBLE_TYPE, false, _cbiv._enclosing);
539          SymbolData myData = new SymbolData("myData");
540          myData.addVar(vd6);
541          _cbiv._enclosing.setSuperClass(myData);
542          vdecl6.visit(_cbiv);
543          assertEquals("There should be three errors.", 3, errors.size());
544          assertEquals("The error message should be correct", "You cannot have two fields with the same name.  Either you" +
545                       " already have a field by that name in this class, or one of your superclasses or interfaces has a" +
546                       " field by that name", 
547                       errors.getLast().getFirst());
548    
549        }
550        
551        public void testFormalParameters2VariableData() {
552          FormalParameter[] fps = new FormalParameter[] {
553            new FormalParameter(SourceInfo.NONE, 
554                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
555                                                                  new PrimitiveType(SourceInfo.NONE, "double"), 
556                                                                  new Word (SourceInfo.NONE, "field1")),
557                                false),
558            new FormalParameter(SourceInfo.NONE, 
559                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
560                                                                  new PrimitiveType(SourceInfo.NONE, "boolean"), 
561                                                                  new Word (SourceInfo.NONE, "field2")),
562                                false)};
563    
564          MethodData md = new MethodData("methodName", 
565                                         _packageMav, 
566                                         new TypeParameter[0], 
567                                         SymbolData.INT_TYPE, 
568                                         new VariableData[0],  // a dummy value
569                                         new String[0],
570                                         _sd1,  // enclosing class
571                                         null); // no SourceInfo
572          VariableData vd1 = new VariableData("field1", _finalMav, SymbolData.DOUBLE_TYPE, true, _sd1);
573          VariableData vd2 = new VariableData("field2", _finalMav, SymbolData.BOOLEAN_TYPE, true, _sd1);
574    //      System.err.println("vd1 = " + vd1);
575    //      System.err.println("vd2 = " + vd2);
576          VariableData[] vds = _cbiv.formalParameters2VariableData(fps, _sd1);
577          assertEquals("There should not be any errors.", 0, errors.size());
578    //      System.err.println("vds[0] = " + vds[0]);
579    //      System.err.println("vds[1] = " + vds[1]);
580          assertEquals("vd1 should be the first entry in vds.", vd1, vds[0]);
581          assertEquals("vd2 should be the second entry in vds.", vd2, vds[1]);
582        }
583        
584    
585        
586    
587        
588        public void testForConcreteMethodDef() {
589          // Test one that works.
590          MethodDef mdef = new ConcreteMethodDef(SourceInfo.NONE, 
591                                                 _privateMav, 
592                                                 new TypeParameter[0], 
593                                                 new PrimitiveType(SourceInfo.NONE, "int"), 
594                                                 new Word(SourceInfo.NONE, "methodName"),
595                                                 new FormalParameter[0],
596                                                 new ReferenceType[0], 
597                                                 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
598          mdef.visit(_cbiv);
599          assertEquals("There should not be any errors.", 0, errors.size());
600    
601          
602          //Check one that works but needs to be augmented with public
603          ConcreteMethodDef cmd1 = new ConcreteMethodDef(SourceInfo.NONE,
604                                                        _packageMav,
605                                                        new TypeParameter[0],
606                                                        new PrimitiveType(SourceInfo.NONE, "int"),
607                                                        new Word(SourceInfo.NONE, "noMavMethod"),
608                                                        new FormalParameter[0],
609                                                        new ReferenceType[0],
610                                                        new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
611          
612          cmd1.visit(_cbiv);
613          assertEquals("There should not be any errors", 0, errors.size());
614          assertEquals("_sd1 should contain 2 methods", 2, _sd1.getMethods().size());
615          assertTrue("The second method should be default public", _sd1.getMethods().get(1).hasModifier("public"));
616    
617          
618          
619          // Test one that doesn't work.
620          mdef = new ConcreteMethodDef(SourceInfo.NONE, 
621                                                 _packageMav, 
622                                                 new TypeParameter[0], 
623                                                 new PrimitiveType(SourceInfo.NONE, "int"), 
624                                                 new Word(SourceInfo.NONE, "monkey"),
625                                                 new FormalParameter[0],
626                                                 new ReferenceType[0], 
627                                                 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
628          mdef.visit(_cbiv);
629          assertEquals("There should be one error.", 1, errors.size());
630          assertEquals("The error message should be correct.", 
631                       "Only constructors can have the same name as the class they appear in, and constructors do not "
632                         + "have an explicit return type",
633                       errors.get(0).getFirst());
634        }
635        
636        public void testForAbstractMethodDef() {
637          // Test one that works but needs to be augmented with public.
638          MethodDef mdef = new AbstractMethodDef(SourceInfo.NONE, 
639                                                 _abstractMav, 
640                                                 new TypeParameter[0], 
641                                                 new PrimitiveType(SourceInfo.NONE, "int"), 
642                                                 new Word(SourceInfo.NONE, "methodName"),
643                                                 new FormalParameter[0],
644                                                 new ReferenceType[0]);
645          _cbiv._enclosing.setMav(_abstractMav);
646    
647          mdef.visit(_cbiv);
648          assertEquals("There should not be any errors", 0, errors.size());
649          assertEquals("_sd1 should contain 1 methods", 1, _sd1.getMethods().size());
650          assertTrue("The method should be default public", _sd1.getMethods().getFirst().hasModifier("public"));
651    
652          
653          
654          
655          // Test one that doesn't work.
656          mdef = new AbstractMethodDef(SourceInfo.NONE, 
657                                                 _abstractMav, 
658                                                 new TypeParameter[0], 
659                                                 new PrimitiveType(SourceInfo.NONE, "int"), 
660                                                 new Word(SourceInfo.NONE, "monkey"),
661                                                 new FormalParameter[0],
662                                                 new ReferenceType[0]);
663          mdef.visit(_cbiv);
664          assertEquals("There should be one error.", 1, errors.size());
665          assertEquals("The error message should be correct.", 
666                       "Only constructors can have the same name as the class they appear in, " +
667                       "and constructors do not have an explicit return type",
668                       errors.get(0).getFirst());
669        }
670        
671        /* These test is shared with BodyIntermediateVisitor,
672         * perhaps we could factor it out. */
673        
674    //    public void testForOtherExpressionOnly() {
675    //      // Test that if the OtherExpression contains a Word, that the Word is resolved.
676    //      assertFalse("java.lang.System should not be in the symbolTable.", symbolTable.containsKey("java.lang.System"));
677    //      Expression ex = new Expression( SourceInfo.NONE,
678    //                                     new ExpressionPiece[] { new OtherExpression(SourceInfo.NONE, 
679    //                                                                                 new Word(SourceInfo.NONE,
680    //                                                                                          "System"))});
681    //      ex.visit(_cbiv);
682    //      assertEquals("There should not be any errors.", 0, errors.size());
683    //      assertTrue("java.lang.System should be in the symbolTable.", symbolTable.containsKey("java.lang.System"));
684    //    }
685        
686        public void testForInitializedVariableDeclaratorDoFirst() {
687          InitializedVariableDeclarator ivd = 
688            new InitializedVariableDeclarator(SourceInfo.NONE,
689                                              new PrimitiveType(SourceInfo.NONE, "int"),
690                                              new Word(SourceInfo.NONE, "i"),
691                                              new IntegerLiteral(SourceInfo.NONE, 5));
692          
693          ivd.visit(_cbiv);
694          
695          assertEquals("There should be no errors now", 0, errors.size());
696    //      assertEquals("Error message should be correct",
697    //                   "Cannot initialize a class's fields at the Intermediate level.  To set the value of a field, when" +
698    //                   "you instantiate the class, assign the desired value using the class's constructor",
699    //                   errors.get(0).getFirst());
700        }
701    
702    
703        public void testForInnerInterfaceDef() {
704          InnerInterfaceDef cd1 = new InnerInterfaceDef(SourceInfo.NONE, _packageMav, 
705                                                        new Word(SourceInfo.NONE, "Bart"),
706                                           new TypeParameter[0], new ReferenceType[0], 
707                                           new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
708          
709          InnerInterfaceDef cd0 = new InnerInterfaceDef(SourceInfo.NONE, _packageMav, 
710                                                        new Word(SourceInfo.NONE, "Lisa"),
711                                           new TypeParameter[0], new ReferenceType[0], 
712                                                new BracedBody(SourceInfo.NONE, new BodyItemI[] {cd1}));
713          
714          SymbolData sd0 = new SymbolData(_cbiv._enclosing.getName() + "$Lisa", _packageMav, new TypeParameter[0], 
715                                          new ArrayList<SymbolData>(), null); 
716          SymbolData sd1 = new SymbolData(_cbiv._enclosing.getName() + "$Lisa$Bart", _packageMav, new TypeParameter[0], 
717                                          new ArrayList<SymbolData>(), null);
718          sd0.addInnerInterface(sd1);
719          sd0.setIsContinuation(true);
720          sd1.setIsContinuation(true);
721          
722          LanguageLevelConverter.symbolTable.put(_cbiv._enclosing.getName() + "$Lisa", sd0);
723          LanguageLevelConverter.symbolTable.put(_cbiv._enclosing.getName() + "$Lisa$Bart", sd1);
724    
725          cd0.visit(_cbiv);
726    
727          SymbolData sd = _cbiv._enclosing.getInnerClassOrInterface("Lisa");
728    
729          // NOTE: No longer allowing inner interfaces at the intermediate level
730          assertEquals("There should be no errors", 0, errors.size());
731          // Nested interfaces now work
732        }
733        
734        public void testForConstructorDef() {
735          //this is a ConstructorDef with no formal parameters and no throws
736          ConstructorDef cd = new ConstructorDef(SourceInfo.NONE, 
737                                                 new Word(SourceInfo.NONE, "MyClass"), _publicMav, 
738                                                 new FormalParameter[0], new ReferenceType[0], 
739                                                 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
740          
741          //What if constructor name and SymbolData name don't match?  Should throw an error.
742          _cbiv._enclosing = new SymbolData("NotRightName");
743          cd.visit(_cbiv);
744          assertEquals("Should be 1 error", 1, errors.size());
745          assertEquals("Error message should be correct", 
746                       "The constructor return type and class name must match", errors.getLast().getFirst());
747          
748          //If they are the same, it should work just fine.
749          _cbiv._enclosing = new SymbolData("MyClass");
750          
751          MethodData constructor = new MethodData("MyClass", _publicMav, new TypeParameter[0], _cbiv._enclosing, 
752                                                  new VariableData[0], 
753                                                  new String[0], 
754                                                  _cbiv._enclosing,
755                                                  null);
756          
757          
758          cd.visit(_cbiv);
759          
760          
761          assertEquals("Should still be 1 error", 1, errors.size());
762          assertEquals("SymbolData should have 1 method", 1, _cbiv._enclosing.getMethods().size());
763          assertTrue("SymbolData's constructor should be correct", _cbiv._enclosing.getMethods().contains(constructor));
764          
765          //With a ConstructorDef with more throws and variables, should work okay.
766          FormalParameter fp = 
767            new FormalParameter(SourceInfo.NONE, 
768                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
769                                                                    new PrimitiveType(SourceInfo.NONE, "int"), 
770                                                                    new Word(SourceInfo.NONE, "i")), false);
771          ReferenceType rt = new TypeVariable(SourceInfo.NONE, "MyMadeUpException");
772          ConstructorDef cd2 = new ConstructorDef(SourceInfo.NONE, 
773                                                  new Word(SourceInfo.NONE, "MyClass"), 
774                                                  _publicMav, 
775                                                  new FormalParameter[] {fp}, 
776                                                  new ReferenceType[] {rt}, 
777                                                  new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
778          
779          VariableData vd = new VariableData("i", _finalMav, SymbolData.INT_TYPE, true, _cbiv._enclosing);
780          MethodData constructor2 = new MethodData("MyClass", 
781                                                   _publicMav, 
782                                                   new TypeParameter[0], 
783                                                   _cbiv._enclosing, 
784                                                   new VariableData[] {vd}, 
785                                                   new String[] {"MyMadeUpException"}, 
786                                                   _cbiv._enclosing,
787                                                   null);
788    
789                                               
790          constructor2.addVar(vd);
791          cd2.visit(_cbiv);
792    //      vd.setEnclosingData(_cbiv._enclosing.getMethods().getLast());
793          assertEquals("Should still be 1 error", 1, errors.size());
794          assertEquals("SymbolData should have 2 methods", 2, _cbiv._enclosing.getMethods().size());
795          
796          assertTrue("SymbolData should have new constructor", _cbiv._enclosing.getMethods().contains(constructor2));
797          
798                                                  
799          //If two variable names are duplicated, should throw an error.
800          FormalParameter fp2 = 
801            new FormalParameter(SourceInfo.NONE, 
802                                new UninitializedVariableDeclarator(SourceInfo.NONE, 
803                                                                    new PrimitiveType(SourceInfo.NONE, "double"), 
804                                                                    new Word(SourceInfo.NONE, "i")), false);
805          
806          ConstructorDef cd3 = new ConstructorDef(SourceInfo.NONE, 
807                                                  new Word(SourceInfo.NONE, "MyClass"), _publicMav, 
808                                                  new FormalParameter[] {fp, fp2}, new ReferenceType[] {rt}, 
809                                                 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
810          cd3.visit(_cbiv);
811          
812          assertEquals("Should now be 2 errors", 2, errors.size());
813          assertEquals("Error message should be correct", "You cannot have two method parameters with the same name", 
814                       errors.getLast().getFirst());
815        }    
816      }
817    }