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.JExprParser;
041    import java.util.*;
042    import java.io.*;
043    
044    import junit.framework.TestCase;
045    
046    /** Do the TypeChecking appropriate to the context of a constructor body.  Common to all Language Levels. */
047    public class ConstructorBodyTypeChecker extends BodyTypeChecker {
048    
049      /** Constructor for ConstructorBodyTypeChecker.
050        * @param bodyData  The bodyData corresponding to the constructor we are visiting
051        * @param file  The File corresponding to the source file we are checking.
052        * @param packageName  The package of the source file.
053        * @param importedFiles  A list of the names of the classes that are specifically imported in the source file
054        * @param importedPackages  A list of the names of the packages that are imported in the source file.
055        * @param vars  A list of the variable datas that can be seen and have been given a value before this context
056        * @param thrown  The exceptions that are thrown
057        */
058      public ConstructorBodyTypeChecker(BodyData bodyData, File file, String packageName, LinkedList<String> importedFiles,
059                                        LinkedList<String> importedPackages, LinkedList<VariableData> vars, 
060                                        LinkedList<Pair<SymbolData, JExpression>> thrown) {
061        super(bodyData, file, packageName, importedFiles, importedPackages, vars, thrown);
062      }
063     
064      
065      /** Creates a new instance of this class for visiting inner bodies. */
066      protected BodyTypeChecker 
067        createANewInstanceOfMe(BodyData bodyData, File file, String pakage, LinkedList<String> importedFiles, 
068                               LinkedList<String> importedPackages, LinkedList<VariableData> vars, 
069                               LinkedList<Pair<SymbolData, JExpression>> thrown) {
070        return new ConstructorBodyTypeChecker(bodyData, file, pakage, importedFiles, importedPackages, vars, thrown);
071      }
072      
073      
074      /** This is used in the case where a simple this constructor invocation is allowed.  i.e. when it is the first 
075        * statement of a constructor body.
076       */
077      public TypeData simpleThisConstructorInvocationAllowed(SimpleThisConstructorInvocation that) {
078        //Verify that a constructor of this form is in this--if not, an error will be thrown by this method invocation.
079        //we continue with this method regardless.
080        String name = LanguageLevelVisitor.getUnqualifiedClassName(_data.getSymbolData().getName());
081        InstanceData[] args = getArgTypesForInvocation(that.getArguments());
082        if (args == null) {return null;}
083        MethodData cd = _lookupMethod(name, _data.getSymbolData(), args, that, 
084                               "No constructor found in class " + _data.getSymbolData().getName() + " with signature: ", 
085                               true, _data.getSymbolData());
086        
087        if (cd==null) {return null;}
088        
089        //set all final fields to have a value--they should have gotten caught.
090        LinkedList<VariableData> myFields = _data.getSymbolData().getVars();
091        for (int i = 0; i<myFields.size(); i++) {
092          if (myFields.get(i).hasModifier("final")) {
093            _vars.get(_vars.indexOf(myFields.get(i))).gotValue();
094            thingsThatHaveBeenAssigned.addLast(_vars.get(_vars.indexOf(myFields.get(i))));
095          }
096        }
097        
098        // if constructor is declared to throw exceptions, add them to thrown list:
099        String[] thrown = cd.getThrown();
100        for (int i = 0; i < thrown.length; i++) {
101          _thrown.addLast(new Pair<SymbolData, JExpression>(getSymbolData(thrown[i], _getData(), that), that));
102        }  
103        return null;
104      }
105      
106      /** ComplexThisConstructorInvocations are not ever allowed--throw an appropriate error. */
107      public TypeData complexThisConstructorInvocationNotAllowed(ComplexThisConstructorInvocation that) {
108        _addError("Constructor Invocations of this form are never allowed.  A constructor invocation can appear here, "
109                    + "but it must either be a super constructor invocation or have the form this(...)", that);
110        return null;
111      }
112      
113      /** This is used in the case where a simple super constructor invocation is allowed i.e. when it is the first statement
114        * of a constructor body.
115        */
116      public TypeData simpleSuperConstructorInvocationAllowed(SimpleSuperConstructorInvocation that) {
117        
118        SymbolData superClass = _data.getSymbolData().getSuperClass();
119        
120        if (superClass == null) {  //This should never happen.
121          _addError("The class " + _data.getSymbolData().getName() + " does not have a super class", that);
122          return null;
123        }
124    
125        //If the super class is an inner class, a constructor of this form can only be used if it is static.
126        if (superClass.getOuterData() != null && !(superClass.hasModifier("static"))) {
127          _addError(superClass.getName() + " is a non-static inner class of " + superClass.getOuterData().getName() + ".  Its constructor must be invoked from an instance of its outer class", that);
128          return null;
129        }
130    
131        
132        //Look in this's super class and try to match the invocation.  If no match is found, the method invocation will add an error.
133        String name = LanguageLevelVisitor.getUnqualifiedClassName(superClass.getName());
134        InstanceData[] args = getArgTypesForInvocation(that.getArguments());
135        if (args == null) return null;
136        MethodData cd = _lookupMethod(name, superClass, args, that, 
137                               "No constructor found in class " + superClass.getName() + " with signature: ", 
138                               true, superClass);
139    
140        if (cd == null) return null;
141        
142        // if constructor is declared to throw exceptions, add them to thrown list:
143        String[] thrown = cd.getThrown();
144        for (int i = 0; i < thrown.length; i++) {
145          _thrown.addLast(new Pair<SymbolData, JExpression>(getSymbolData(thrown[i], _getData(), that), that));
146        }
147        return null;
148      }
149      
150      /** This is used in the case where a complex super constructor invocation is allowed i.e. when it is the first 
151        * statement of a constructor body.
152        */
153      public TypeData complexSuperConstructorInvocationAllowed(ComplexSuperConstructorInvocation that) {
154        //resolve the first part of the super invocation using an ETC and super class and try to match the invocation.
155        ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, 
156                                                              _vars, _thrown);
157        TypeData enclosingResult = that.getEnclosing().visit(etc);
158        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
159    
160        if (! assertFound(enclosingResult, that)) return null;
161        SymbolData superClass = _data.getSymbolData().getSuperClass();
162        
163        //enclosingResult must be the outerclass of the super class of this class.
164        if (superClass == null) { 
165          _addError("A qualified super constructor invocation can only be used to invoke the constructor of your super "
166                      + "class from the context of its outer class.  The class " + _data.getSymbolData().getName() + 
167                    " does not have a super class, so you cannot do this here", 
168                    that);
169          return null;
170        }
171        else if (superClass.getOuterData() == null) { 
172          _addError("A qualified super constructor invocation can only be used to invoke the constructor of your super "
173                      + "class from the context of its outer class.  The super class " + superClass.getName() 
174                      + " does not have an outer class, so you cannot do this here", 
175                    that);
176          return null;
177        }
178        else if (enclosingResult == null) {
179          _addError("A qualified super constructor invocation can only be used to invoke the constructor of your super "
180                      + "class from the context of its outer class.", 
181                    that);
182          return null;
183        }
184        else if (superClass.getOuterData() != enclosingResult.getSymbolData()) {
185          _addError("A qualified super constructor invocation can only be used to invoke the constructor of your super "
186                      + "class from the context of its outer class.  The class or interface " 
187                      + enclosingResult.getSymbolData().getName() + " is not the outer class of the super class " 
188                      + superClass.getName(), 
189                    that);
190          return null;
191        }
192        else if (!enclosingResult.isInstanceType()) {
193          _addError("A qualified super constructor invocation can only be made from the context of an instance of the "
194                      + "outer class of the super class.  You have specified a type name", 
195                    that);
196          return null;
197        }
198        else if (superClass.hasModifier("static")) {
199          _addError("A qualified super constructor invocation can only be used to invoke the constructor of a non-static "
200                      + "super class from the context of its outer class.  The super class " + superClass.getName() 
201                      + " is a static inner class",
202                    that);
203          return null;
204        }
205        String name = LanguageLevelVisitor.getUnqualifiedClassName(superClass.getName());
206        InstanceData[] args = getArgTypesForInvocation(that.getArguments());
207        if (args == null) {return null;}
208        MethodData cd = _lookupMethod(name, superClass, args, that, 
209                                      "No constructor found in class " + superClass.getName() + " with signature: ", 
210                                      true, superClass);
211        if (cd == null) {return null;}
212        //if constructor is declared to throw exceptions, add them to thrown list:
213        String[] thrown = cd.getThrown();
214        for (int i = 0; i<thrown.length; i++) {
215          _thrown.addLast(new Pair<SymbolData, JExpression>(getSymbolData(thrown[i], _getData(), that), that));
216        }
217        return null;
218      }
219      
220      /** Called when the first line of a constructor is not an explicit constructor invocation.
221        * In this case, if the class has a super class (which it should), we assume there is an implicit call
222        * to the super constructor, passing no arguments.
223        */
224      private void implicitSuperConstructor(BracedBody that) {
225    //    System.err.println("implicitSuperConstructor called for " + _data.getSymbolData());
226        SymbolData superClass = _data.getSymbolData().getSuperClass();
227        
228        if (superClass == null) {  //This should never happen, but if it does, no reason to throw an error.
229          return;
230        }
231    
232        //If the super class is an inner class, there cannot be an implicit constructor call
233        if (superClass.getOuterData() != null && !(superClass.hasModifier("static"))) {
234          _addError("There is an implicit call to the constructor of " + superClass.getName() + " here, but " + 
235                    superClass.getName() + " is a non-static inner class of " + superClass.getOuterData().getName() + 
236                    ".  Thus, you must explicitly invoke its constructor from an instance of its outer class", 
237                    that);
238          return;
239        }
240    
241        
242        // Look in this's super class and try to match the invocation.  If no match is found, the method invocation will 
243        // add an error.
244        String name = LanguageLevelVisitor.getUnqualifiedClassName(superClass.getName());
245        
246        // There must be a default constructor with no arguments, or an error is thrown.
247        // (Note--if there were no constructors in the super class at all, the default no arguments constructor would exist.  
248        // However, a constructor is always generated for a LanguageLevel file, and any class file that relied on the 
249        // default constructor would already have it.  Therefore, we can assume that all classes have at least one constructor).
250        
251        MethodData cd = 
252          _lookupMethod(name, 
253                        superClass, 
254                        new InstanceData[0], 
255                        that, 
256                        "You must invoke one of " + superClass.getName() + 
257                        "'s constructors here.  You can either explicitly invoke one of its exisitng constructors or "
258                          + "add a constructor with signature: ", 
259                        true, superClass);
260    
261        if (cd == null) return;
262        // if constructor is declared to throw exceptions, add them to thrown list:
263        // add BracedBody as the JExpression corresponding to the error
264        String[] thrown = cd.getThrown();
265        for (int i = 0; i<thrown.length; i++) {
266          _thrown.addLast(new Pair<SymbolData, JExpression>(getSymbolData(thrown[i], _getData(), that), that));
267        }
268        return;
269      }
270        
271      /** Void return statements are allowed in constructor bodies, since according to java, constructors are
272        * void return methods.  However, we treat them as if they returned an instance of the class they
273        * are a constructor for, so we will return that symbol data here.
274        */
275      public TypeData forVoidReturnStatementOnly(VoidReturnStatement that) {
276        // Just return the type the constructor would return.
277        return _bodyData.getSymbolData().getInstanceData();
278      }
279    
280      /** Throw an error and return null, becuase constructors cannot have value return statements in their bodies. */
281      public TypeData forValueReturnStatementOnly(ValueReturnStatement that, TypeData valueRes) {
282          _addError("You cannot return a value from a class's constructor", that);
283          return _bodyData.getSymbolData().getInstanceData();
284      }
285      
286      /** Walk over the statements in the BracedBody, treating the first line specially.  A super constructor
287        * invocation can only appear on the first line of a constructor, so see if there is one on the
288        * first line, and if so, call the appropriate method.  If there is no super constructor invocation, 
289        * then assume there is an implicit one.  Then visit the rest of the statements in the body like normal.
290        * Make sure errors are thrown for any uncaught exceptions.
291        */
292      public TypeData forBracedBody(BracedBody that) {
293    //    System.err.println("forBracedBody called in " + _data.getSymbolData() + " for " + that);
294        int startIndex = 0;
295        final TypeData[] items_result = makeArrayOfRetType(that.getStatements().length);
296        if (items_result.length > 0) {
297          // The first line of a constructor is treated specially:
298          if (that.getStatements()[0] instanceof ExpressionStatement) {
299            Expression firstExpression = ((ExpressionStatement) that.getStatements()[0]).getExpression();
300            if (firstExpression instanceof SimpleThisConstructorInvocation) {
301              items_result[0] = simpleThisConstructorInvocationAllowed((SimpleThisConstructorInvocation) firstExpression);
302              startIndex ++;
303            }
304            
305            else if (firstExpression instanceof ComplexThisConstructorInvocation) {
306              items_result[0] = complexThisConstructorInvocationNotAllowed((ComplexThisConstructorInvocation) firstExpression);
307              startIndex++;
308            }    
309            else if (firstExpression instanceof SimpleSuperConstructorInvocation) {
310              items_result[0] = simpleSuperConstructorInvocationAllowed((SimpleSuperConstructorInvocation) firstExpression);
311              startIndex++;
312            }
313            else if (firstExpression instanceof ComplexSuperConstructorInvocation) {
314              items_result[0] = complexSuperConstructorInvocationAllowed((ComplexSuperConstructorInvocation) firstExpression);
315              startIndex++;
316            }      
317          }
318        }
319        if (startIndex == 0) implicitSuperConstructor(that);
320        
321        int thrownSize = _thrown.size();
322    //    System.err.println("_thrown.size() in " + _data + " = " + thrownSize);
323        for (int j = 0; j < thrownSize; j++) {
324          if (isUncaughtCheckedException(_thrown.get(j).getFirst(), that)) {
325            handleUncheckedException(_thrown.get(j).getFirst(), _thrown.get(j).getSecond());
326          }
327        }
328        // TODO: ???? Provision for field initialization?
329        /** The following is supposed to be equivalent to calling SpecialTypeChecker.forBody(that, items_result) */
330        for (int i = startIndex; i < that.getStatements().length; i++) {
331            items_result[i] = that.getStatements()[i].visit(this);
332          // Walk over what has been thrown and throw an error if it contains an unchecked exception
333          for (int j = thrownSize; j < _thrown.size(); j++) {
334            if (isUncaughtCheckedException(_thrown.get(j).getFirst(), that)) {
335              handleUncheckedException(_thrown.get(j).getFirst(), _thrown.get(j).getSecond());
336            }
337          }
338        }
339    
340        return forBracedBodyOnly(that, items_result);
341      }
342      
343      /** Tests the methods in the above class. */
344      public static class ConstructorBodyTypeCheckerTest extends TestCase {
345        
346        private ConstructorBodyTypeChecker _cbtc;
347        
348        private MethodData _bd1;
349    //    private MethodData _bd2;
350        
351        private SymbolData _sd1;
352        private SymbolData _sd2;
353        private SymbolData _sd3;
354        private SymbolData _sd4;
355        private SymbolData _sd5;
356        private SymbolData _sd6;
357        private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
358        private ModifiersAndVisibility _protectedMav = 
359          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
360        private ModifiersAndVisibility _privateMav = 
361          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
362        private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
363        private ModifiersAndVisibility _abstractMav = 
364          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
365        private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
366        
367        public ConstructorBodyTypeCheckerTest() { this(""); }
368        public ConstructorBodyTypeCheckerTest(String name) { super(name); }
369        
370        public void setUp() {
371          _sd1 = new SymbolData("i.like.monkey");
372          _sd2 = new SymbolData("i.like.giraffe");
373          _sd3 = new SymbolData("zebra");
374          _sd4 = new SymbolData("u.like.emu");
375          _sd5 = new SymbolData("elephant");
376          _sd6 = new SymbolData("cebu");
377    
378          VariableData[] vds = new VariableData[] { new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, null), 
379                                                    new VariableData(SymbolData.BOOLEAN_TYPE) };
380          _bd1 = new MethodData("monkey", 
381                                _packageMav, 
382                                new TypeParameter[0], 
383                                _sd1, 
384                                vds,
385                                new String[0],
386                                _sd1,
387                                null); // no SourceInfo
388          
389          _bd1.getParams()[0].setEnclosingData(_bd1);                      
390          _bd1.getParams()[1].setEnclosingData(_bd1);                      
391    
392          errors = new LinkedList<Pair<String, JExpressionIF>>();
393          LanguageLevelConverter.symbolTable.clear();
394          LanguageLevelConverter._newSDs.clear();
395          _bd1.addEnclosingData(_sd1);
396          _bd1.addVars(_bd1.getParams());
397          _cbtc = new ConstructorBodyTypeChecker(_bd1, 
398                                                 new File(""), 
399                                                 "", 
400                                                 new LinkedList<String>(), 
401                                                 new LinkedList<String>(), 
402                                                 new LinkedList<VariableData>(), 
403                                                 new LinkedList<Pair<SymbolData, JExpression>>());
404          _cbtc._importedPackages.addFirst("java.lang");
405        }
406        
407        
408        public void testForVoidReturnStatementOnly() {
409          _cbtc._bodyData = _bd1; // this body data returns _sd1 (yeah, it's a constructor)
410    
411          //test one that works
412          BracedBody bb1 = new BracedBody(SourceInfo.NONE, 
413                                          new BodyItemI[] { new VoidReturnStatement(SourceInfo.NONE)});
414    
415          TypeData sd = bb1.visit(_cbtc);
416    
417          assertEquals("There should be no errors.", 0, errors.size());
418          assertEquals("Should return i.like.monkey type.", _sd1.getInstanceData(), sd);
419    
420        }
421       
422        public void testforValueReturnStatementOnly() {
423          //value return statement should always throw an error.
424          BodyItemI[] bis = 
425            new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
426                                                       new BooleanLiteral(SourceInfo.NONE, true))};
427          BracedBody bb1 = new BracedBody(SourceInfo.NONE, bis);
428          TypeData sd = bb1.visit(_cbtc);
429          assertEquals("There should be one error", 1, errors.size());
430          assertEquals("Should return i.like.monkey type", _sd1.getInstanceData(), sd);
431          assertEquals("Error message should be correct", "You cannot return a value from a class's constructor", 
432                       errors.get(0).getFirst());
433    
434        }
435        
436        public void testCreateANewInstanceOfMe() {
437          //make sure that the correct visitor is returned from createANewInstanceOfMe
438          BodyTypeChecker btc = 
439            _cbtc.createANewInstanceOfMe(_cbtc._bodyData, _cbtc._file, _cbtc._package, _cbtc._importedFiles, 
440                                         _cbtc._importedPackages, _cbtc._vars, _cbtc._thrown);
441          assertTrue("Should be an instance of ConstructorBodyTypeChecker", btc instanceof ConstructorBodyTypeChecker);
442        }
443        
444        public void testForBracedBody() {
445          LanguageLevelVisitor llv = 
446            new LanguageLevelVisitor(new File(""), 
447                                     "", 
448                                     null, // enclosingClassName for top level traversal
449                                     new LinkedList<String>(), 
450                                     new LinkedList<String>(), 
451                                     new HashSet<String>(), 
452                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
453                                     new LinkedList<Command>());
454          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
455          llv._errorAdded=false;
456    //      LanguageLevelConverter.symbolTable = llv.symbolTable = new Symboltable();
457          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
458          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
459    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
460          llv._classesInThisFile = new HashSet<String>();
461          
462          // TODO: The next line should be unnecessary because the subsequent two lines should force its loading
463          SymbolData throwable = llv.getSymbolData("java.lang.Exception", SourceInfo.NONE, true);  
464          SymbolData eb = llv.getSymbolData("java.util.prefs.BackingStoreException", SourceInfo.NONE, true);
465          SymbolData re = llv.getSymbolData("java.lang.RuntimeException", SourceInfo.NONE, true);
466    //      LanguageLevelConverter.symbolTable = symbolTable = llv.symbolTable;
467          
468          assert symbolTable.contains(eb);
469          assert symbolTable.contains(re);
470          assert symbolTable.containsKey("java.lang.Throwable");
471          assert symbolTable.containsKey("java.lang.Exception");
472    
473          _sd3.setIsContinuation(false);
474          _sd3.setMav(_publicMav);
475          _sd1.setSuperClass(_sd3);
476          // Make sure that it is not okay to invoke a super constructor that throws an exception if the enclosing method 
477          // is not declared to throw it
478          _cbtc._bodyData.getMethodData().setThrown(new String[0]);
479          _sd3.setMav(_publicMav);
480          _sd3.setIsContinuation(false);
481          _cbtc.symbolTable.put(_sd3.getName(), _sd3);
482          MethodData constructor = new MethodData("zebra", 
483                                                  _publicMav, 
484                                                  new TypeParameter[0], 
485                                                  _sd3, 
486                                                  new VariableData[0], 
487                                                  new String[] {"java.util.prefs.BackingStoreException"}, 
488                                                  _sd3, 
489                                                  null);
490          _sd3.addMethod(constructor);
491          
492          SimpleSuperConstructorInvocation ssci = 
493            new SimpleSuperConstructorInvocation(SourceInfo.NONE, 
494                                                 new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
495          BracedBody supConstr = 
496            new BracedBody(SourceInfo.NONE, new BodyItemI[]{new ExpressionStatement(SourceInfo.NONE, ssci)});
497          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
498          supConstr.visit(_cbtc);
499          assertEquals("There should be one error", 1, errors.size());
500          assertEquals("The error message should be correct", 
501                       "The constructor of this class's super class could throw the exception " +
502                       "java.util.prefs.BackingStoreException, so the enclosing constructor needs to be declared to throw it", 
503                       errors.getLast().getFirst());
504    
505          
506          //if enclosing method is delared to throw it, should be okay:
507          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
508          _cbtc._bodyData.getMethodData().setThrown(new String[] {"java.util.prefs.BackingStoreException"});
509          supConstr.visit(_cbtc);
510          assertEquals("There should still be one error", 1, errors.size());
511          
512    //      //if implicit reference, still give error.
513          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
514          _cbtc._bodyData.getMethodData().setThrown(new String[0]);
515          BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
516          emptyBody.visit(_cbtc);
517          assertEquals("There should be 2 errors", 2, errors.size());
518          assertEquals("The error message should be correct", "There is an implicit call to the superclass's constructor here.  That constructor could throw the exception java.util.prefs.BackingStoreException, so the enclosing constructor needs to be declared to throw it", errors.getLast().getFirst());
519    
520          //if enclosing method is delared to throw it, should be okay:
521          _cbtc._bodyData.getMethodData().setThrown(new String[] {"java.util.prefs.BackingStoreException"});
522          emptyBody.visit(_cbtc);
523          assertEquals("There should still be two errors", 2, errors.size());
524          
525          //make sure that it is not okay to invoke a this constructor that throws an exception if the enclosing constructor is not declared to throw it
526          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
527          BracedBody thisConstr = new BracedBody(SourceInfo.NONE, new BodyItemI[]{new ExpressionStatement(SourceInfo.NONE, new SimpleThisConstructorInvocation(SourceInfo.NONE, new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])))});
528    
529          MethodData thisConstructor = new MethodData("cebu", _publicMav, new TypeParameter[0], _sd6, new VariableData[0], new String[] {"java.util.prefs.BackingStoreException"}, _sd6, null);
530          MethodData thisConstructorNoThrown = new MethodData("cebu", _publicMav, new TypeParameter[0], _sd6, new VariableData[0], new String[0], _sd6, null);
531          _sd6.addMethod(thisConstructor);
532          BodyData oldData = _cbtc._bodyData;
533          _cbtc._data = thisConstructorNoThrown;
534          _cbtc._bodyData = thisConstructorNoThrown;
535    
536          thisConstr.visit(_cbtc);
537          assertEquals("There should be 3 errors", 3, errors.size());
538          assertEquals("The error message should be correct", "This constructor could throw the exception java.util.prefs.BackingStoreException, so this enclosing constructor needs to be declared to throw it", errors.getLast().getFirst());
539    
540          //if enclosing method is delared to throw it, should be okay:
541          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
542          _cbtc._bodyData.getMethodData().setThrown(new String[] {"java.util.prefs.BackingStoreException"});
543          thisConstr.visit(_cbtc);
544          assertEquals("There should still be 3 errors", 3, errors.size());
545          
546          
547          //make sure that it is not okay to invoke a complex super constructor that throws an exception if the enlcosing constructor is not declared to throw it.
548          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
549          
550          _sd5.setIsContinuation(false);
551          _sd5.addInnerClass(_sd3);
552          _sd3.setOuterData(_sd5);
553          
554          _sd5.setMav(_publicMav);
555          _sd5.setIsContinuation(false);
556          symbolTable.put("elephant", _sd5);
557          
558          BracedBody complexSC = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new ExpressionStatement(SourceInfo.NONE, new ComplexSuperConstructorInvocation(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "e")), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])))});
559          oldData.getMethodData().setThrown(new String[0]);
560          _cbtc._vars.add(new VariableData("e", _publicMav, _sd5, true, _sd3));
561          _cbtc._data = oldData;
562          _cbtc._bodyData = oldData;
563          
564          complexSC.visit(_cbtc);
565          assertEquals("There should be 4 errors", 4, errors.size());
566          assertEquals("Error message should be correct", "The constructor of this class's super class could throw the exception java.util.prefs.BackingStoreException, so the enclosing constructor needs to be declared to throw it", errors.getLast().getFirst());
567    
568          //if enclosing method is delared to throw it, should be okay:
569          _cbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
570    
571          _cbtc._bodyData.getMethodData().setThrown(new String[] {"java.util.prefs.BackingStoreException"});
572          complexSC.visit(_cbtc);
573          assertEquals("There should still be 4 errors", 4, errors.size());
574    
575        }
576        
577        public void testSimpleThisConstructorInvocationAllowed() {
578          // if there is a constructor of the right form, all variable datas will be given a value
579          MethodData constructor = 
580            new MethodData("zebra", _publicMav, new TypeParameter[0], _sd3, 
581                           new VariableData[] {new VariableData(SymbolData.INT_TYPE)}, new String[0], _sd3, null);
582          _sd3.addMethod(constructor);
583          _cbtc._bodyData = constructor;
584          _cbtc._data = constructor;
585          
586          VariableData vd1 = new VariableData("i", _finalMav, SymbolData.INT_TYPE, false, _sd3);
587          VariableData vd2 = new VariableData("d", _finalMav, SymbolData.DOUBLE_TYPE, false, _sd3);
588          VariableData vd3 = new VariableData("notFinal", _publicMav, SymbolData.BOOLEAN_TYPE, false, _sd3);
589          _cbtc._vars.add(vd1);
590          _cbtc._vars.add(vd2);
591          _cbtc._vars.add(vd3);
592          _sd3.addVar(vd1);
593          _sd3.addVar(vd2);
594          _sd3.addVar(vd3);
595          
596          SimpleThisConstructorInvocation constr = 
597            new SimpleThisConstructorInvocation(SourceInfo.NONE, 
598                                                new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {
599            new IntegerLiteral(SourceInfo.NONE, 5)}));
600          _cbtc.simpleThisConstructorInvocationAllowed(constr);
601          assertEquals("Should be no errors", 0, errors.size());
602          assertEquals("vd1 should have value", true, vd1.hasValue());
603          assertEquals("vd2 should have value", true, vd2.hasValue());
604          assertEquals("vd3 is not final, and thus should not have a value", false, vd3.hasValue());
605          assertEquals("thrown should have 0 elements", 0, _cbtc._thrown.size());
606          
607          //if there is not a constructor of the right form, an error will be given
608          vd1.lostValue();
609          vd2.lostValue();
610          
611          SimpleThisConstructorInvocation constr2 = new SimpleThisConstructorInvocation(SourceInfo.NONE, new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
612          _cbtc.simpleThisConstructorInvocationAllowed(constr2);
613          assertEquals("Should be one error", 1, errors.size());
614          assertEquals("Error message should be correct", "No constructor found in class zebra with signature: zebra().", errors.getLast().getFirst());
615          assertFalse("vd1 should not have value", vd1.hasValue());
616          assertFalse("vd2 should not have value", vd2.hasValue());
617          assertFalse("vd3 should not have a value", vd3.hasValue());
618          assertEquals("thrown should have 0 elements", 0, _cbtc._thrown.size());
619    
620          
621          //if there is a constructor of the right form, but it throws an exception, the exception will be added to the _thrown list.
622          constructor.setThrown(new String[] {"java.util.prefs.BackingStoreException"});
623          _cbtc.simpleThisConstructorInvocationAllowed(constr);
624          assertEquals("Should still be 1 error", 1, errors.size());
625          assertTrue("vd1 should have a value", vd1.hasValue());
626          assertTrue("vd2 should have a value", vd2.hasValue());
627          assertFalse("vd3 is not final, and thus should not have a value", vd3.hasValue());
628          assertEquals("thrown should have 1 element", 1, _cbtc._thrown.size());
629          
630        }
631    
632        
633        public void testComplexThisConstructorInvocationNotAllowed() {
634          ComplexThisConstructorInvocation constr = new ComplexThisConstructorInvocation(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
635          _cbtc.complexThisConstructorInvocationNotAllowed(constr);
636          assertEquals("There should be 1 error", 1, errors.size());
637          assertEquals("Error message should be correct", "Constructor Invocations of this form are never allowed.  A constructor invocation can appear here, but it must either be a super constructor invocation or have the form this(...)", errors.getLast().getFirst());
638        }
639        
640    
641        public void testSimpleSuperConstructorInvocationAllowed() {
642          //if current class does not have a super class, give an error
643          SimpleSuperConstructorInvocation constr = new SimpleSuperConstructorInvocation(SourceInfo.NONE, new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new IntegerLiteral(SourceInfo.NONE, 5)}));
644          _cbtc.simpleSuperConstructorInvocationAllowed(constr);
645          assertEquals("Should be 1 error", 1, errors.size());
646          assertEquals("Error message should be correct", "The class i.like.monkey does not have a super class", errors.getLast().getFirst());
647          
648          //if current class has a super class, but there isn't a constructor of the right form, give an error
649          _sd1.setSuperClass(_sd3);
650          _cbtc.simpleSuperConstructorInvocationAllowed(constr);
651          assertEquals("Should be 2 errors", 2, errors.size());
652          assertEquals("Error message should be correct", "No constructor found in class zebra with signature: zebra(int).", errors.getLast().getFirst());
653          
654          //if everything is right, should work with no errors
655          MethodData constructor = new MethodData("zebra", _publicMav, new TypeParameter[0], _sd3, new VariableData[] {new VariableData(SymbolData.INT_TYPE)}, new String[0], _sd3, null);
656          _sd3.addMethod(constructor);
657          _cbtc.simpleSuperConstructorInvocationAllowed(constr);
658          assertEquals("Should still be 2 errors", 2, errors.size());
659          
660          //if there is a constructor of the right form, but it throws an exception, the exception will be added to the _thrown list.
661          constructor.setThrown(new String[] {"java.util.prefs.BackingStoreException"});
662          _cbtc.simpleSuperConstructorInvocationAllowed(constr);
663          assertEquals("Should still be 2 errors", 2, errors.size());
664          assertEquals("thrown should have 1 element", 1, _cbtc._thrown.size());
665          
666          //if super class is an inner class, it must be static--if not, throw an error
667          constructor.setThrown(new String[0]);
668          _sd3.setOuterData(_sd5);
669          _cbtc.simpleSuperConstructorInvocationAllowed(constr);
670          assertEquals("Should be 3 errors", 3, errors.size());
671          assertEquals("Error message should be correct", "zebra is a non-static inner class of elephant.  Its constructor must be invoked from an instance of its outer class", errors.getLast().getFirst());
672          
673    
674          //if super class is a static inner class, no error
675          _sd3.addModifier("static");
676          _cbtc.simpleSuperConstructorInvocationAllowed(constr);
677          assertEquals("Should still be 3 errors", 3, errors.size());
678     
679        }
680        
681        public void testComplexSuperConstructorInvocationAllowed() {
682    
683          //if enclosingResult is a PackageData, return null and add an error
684          ComplexSuperConstructorInvocation constr1 = new ComplexSuperConstructorInvocation(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "nonExistant")), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
685          _cbtc.complexSuperConstructorInvocationAllowed(constr1);
686          assertEquals("Should be 1 error", 1, errors.size());
687          assertEquals("Error message should be correct", "Could not resolve symbol nonExistant", errors.getLast().getFirst());
688          
689          //if the superclass is null, add error
690          ComplexSuperConstructorInvocation constr2 = new ComplexSuperConstructorInvocation(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "zebra")), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
691          symbolTable.put("zebra", _sd3);
692          _sd3.setIsContinuation(false);
693          _sd3.setMav(_publicMav);
694          _cbtc.complexSuperConstructorInvocationAllowed(constr2);
695          assertEquals("Should be 2 errors", 2, errors.size());
696          assertEquals("Error message should be correct", "A qualified super constructor invocation can only be used to invoke the constructor of your super class from the context of its outer class.  The class i.like.monkey does not have a super class, so you cannot do this here", errors.getLast().getFirst());
697    
698          //if the superclass exists, but the outer data is null, throw error
699          _sd1.setSuperClass(_sd5);
700          _cbtc.complexSuperConstructorInvocationAllowed(constr2);
701          assertEquals("Should be 3 errors", 3, errors.size());
702          assertEquals("Error message should be correct", "A qualified super constructor invocation can only be used to invoke the constructor of your super class from the context of its outer class.  The super class elephant does not have an outer class, so you cannot do this here", errors.getLast().getFirst());
703          
704          //if the outer data of the super class does not match the name specified in the constructor, give error
705          _sd5.setOuterData(_sd3);
706          ComplexSuperConstructorInvocation constr3 = new ComplexSuperConstructorInvocation(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "u.like.emu")), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
707          symbolTable.put("u.like.emu", _sd4);
708          _sd4.setPackage("u.like");
709          _sd4.setIsContinuation(false);
710          _sd4.setMav(_publicMav);
711          _cbtc.complexSuperConstructorInvocationAllowed(constr3);
712          assertEquals("Should be 4 errors", 4, errors.size());
713          assertEquals("Error message should be correct", "A qualified super constructor invocation can only be used to invoke the constructor of your super class from the context of its outer class.  The class or interface u.like.emu is not the outer class of the super class elephant", errors.getLast().getFirst());
714          
715          //if the enclosing is not an instance type, give an error
716          _cbtc.complexSuperConstructorInvocationAllowed(constr2);
717          assertEquals("Should be 5 errors", 5, errors.size());
718          assertEquals("Error message should be correct", "A qualified super constructor invocation can only be made from the context of an instance of the outer class of the super class.  You have specified a type name", errors.getLast().getFirst());
719    
720          //if it is an instance type but can't find constructor, give error
721          ComplexSuperConstructorInvocation constr4 = new ComplexSuperConstructorInvocation(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "var")), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
722          _cbtc._vars.add(new VariableData("var", _publicMav, _sd3, true, _sd1));
723          _cbtc.complexSuperConstructorInvocationAllowed(constr4);
724          assertEquals("Should be 6 errors", 6, errors.size());
725          assertEquals("Error message should be correct", "No constructor found in class elephant with signature: elephant().", errors.getLast().getFirst());
726          
727          //if it is an instance type and can match constructor, no problems--should add anything thrown to throws list
728          MethodData constructor = new MethodData("elephant", _publicMav, new TypeParameter[0], _sd5, new VariableData[0], new String[] {"java.util.prefs.BackingStoreException"}, _sd5, null);
729          _sd5.addMethod(constructor);
730          _cbtc.complexSuperConstructorInvocationAllowed(constr4);
731          assertEquals("Should still be 6 errors", 6, errors.size());
732          assertEquals("_thrown should now have 1 element", 1, _cbtc._thrown.size());
733          
734          //if it is an instance type, but the super class is static, give an error
735          _sd5.addModifier("static");
736          _cbtc.complexSuperConstructorInvocationAllowed(constr4);
737          assertEquals("Should be 7 errors", 7, errors.size());
738          assertEquals("Error message should be correct", "A qualified super constructor invocation can only be used to invoke the constructor of a non-static super class from the context of its outer class.  The super class elephant is a static inner class", errors.getLast().getFirst());
739        }
740        
741        
742        public void testImplicitSuperConstructor() {
743          BracedBody constr = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
744          //if current class has a super class, but there isn't a constructor of the right form, give an error
745          _sd1.setSuperClass(_sd3);
746          _cbtc.implicitSuperConstructor(constr);
747          assertEquals("Should be 1 error", 1, errors.size());
748          assertEquals("Error message should be correct", "You must invoke one of zebra's constructors here.  You can either explicitly invoke one of its exisitng constructors or add a constructor with signature: zebra().", 
749                       errors.getLast().getFirst());
750          
751          //if everything is right, should work with no errors
752          MethodData constructor = new MethodData("zebra", _publicMav, new TypeParameter[0], _sd3, new VariableData[0], new String[0], _sd3, null);
753          _sd3.addMethod(constructor);
754          _cbtc.implicitSuperConstructor(constr);
755          assertEquals("Should still be 1 error", 1, errors.size());
756          
757          //if there is a constructor of the right form, but it throws an exception, the exception will be added to the _thrown list.
758          constructor.setThrown(new String[] {"java.util.prefs.BackingStoreException"});
759          _cbtc.implicitSuperConstructor(constr);
760          assertEquals("Should still be 1 error", 1, errors.size());
761          assertEquals("thrown should have 1 element", 1, _cbtc._thrown.size());
762          
763          //if super class is an inner class, it must be static--if not, throw an error
764          constructor.setThrown(new String[0]);
765          _sd3.setOuterData(_sd5);
766          _cbtc.implicitSuperConstructor(constr);
767          assertEquals("Should be 2 errors", 2, errors.size());
768          assertEquals("Error message should be correct", "There is an implicit call to the constructor of zebra here, but zebra is a non-static inner class of elephant.  Thus, you must explicitly invoke its constructor from an instance of its outer class", errors.getLast().getFirst());
769          
770    
771          //if super class is a static inner class, no error
772          _sd3.addModifier("static");
773          _cbtc.implicitSuperConstructor(constr);
774          assertEquals("Should still be 2 errors", 2, errors.size());
775        }
776      }
777    }
778    
779    
780      
781    
782