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    import edu.rice.cs.plt.reflect.JavaVersion;
044    import edu.rice.cs.plt.iter.*;
045    
046    import junit.framework.TestCase;
047    
048    /** TypeChecks the context of a body, such as a method body.  Common to all Language Levels.*/
049    public class BodyTypeChecker extends SpecialTypeChecker {
050      /** The MethodData of this method. */
051      protected BodyData _bodyData;
052      
053      /** Constructor for BodyTypeChecker.  Calls the super constructor for everything except bodyData, which we store here
054        * in order to have the proper type at compile time.  (SpecialTypeChecker stores it as a Data).
055        * @param bodyData  The enclosing BodyData for the context we are type checking.
056        * @param file  The File corresponding to the source file.
057        * @param packageName  The package name from the source file.
058        * @param importedFiles  The names of the files that are specifically imported (through a class import statement) in
059        *                       the source file.
060        * @param importedPackages  The names of all the packages that are imported through a package import statement in the
061        *                          source file.
062        * @param vars  The list of VariableData that have already been defined (used so we can make sure we don't use a 
063        *              variable before it has been defined).
064        * @param thrown  The list of exceptions thrown in this body
065        */
066      public BodyTypeChecker(BodyData bodyData, File file, String packageName, LinkedList<String> importedFiles, 
067                             LinkedList<String> importedPackages, LinkedList<VariableData> vars, 
068                             LinkedList<Pair<SymbolData, JExpression>> thrown) {
069        super(bodyData, file, packageName, importedFiles, importedPackages, vars, thrown);
070        _bodyData = bodyData;
071      }
072      
073       /** @return the bodyData (enclosing data) for this context. */
074      protected Data _getData() { return _bodyData; }
075      
076      /** @return the instance data of the class/interface enclosing this body data. */
077      public TypeData forSimpleThisReferenceOnly(SimpleThisReference that) {
078        return _bodyData.getSymbolData().getInstanceData();
079      }
080    
081      /** @return the instance data of the super class of the class enclosing this body data. */
082      public TypeData forSimpleSuperReferenceOnly(SimpleSuperReference that) {
083        return _bodyData.getSymbolData().getSuperClass().getInstanceData();
084      }
085      
086      /** Create a new instance of this class for visiting inner bodies. */
087      protected BodyTypeChecker createANewInstanceOfMe(BodyData bodyData, 
088                                                       File file, 
089                                                       String pakage, 
090                                                       LinkedList<String> importedFiles, 
091                                                       LinkedList<String> importedPackages, 
092                                                       LinkedList<VariableData> vars, 
093                                                       LinkedList<Pair<SymbolData, JExpression>> thrown) {
094        return new BodyTypeChecker(bodyData, file, pakage, importedFiles, importedPackages, vars, thrown);
095      }
096      
097      /* There is currently no way to differentiate between a block statement and
098       * an instance initializer in a braced body given the general nature of a 
099       * braced body.  Whenever an instance initialization is visited in a method
100       * body, we must assume that it is a block statement.
101       */
102      public TypeData forInstanceInitializer(InstanceInitializer that) {
103        return forBlock(that.getCode());
104      }
105      
106      /** We need to do this so that expressions (which should only occur in variable initializers and
107        * initializer blocks) can know which fields have already been declared.  Add all the variable
108        * datas that are declared in this declarator to the list of variables that are visibile from where we are.
109        */
110      public TypeData forUninitializedVariableDeclaratorOnly(UninitializedVariableDeclarator that, 
111                                                             TypeData typeRes, 
112                                                             TypeData nameRes) {
113        _vars.addLast(_bodyData.getVar(that.getName().getText()));
114        return null;
115      }
116    
117    
118      /** Look at the result of each item in the body.  If one is not null and does not correspond to an Expression
119        * Statement, then that means that that statement returns a value.  Check to make sure that there are no
120        * statements following it.  If there are, then those statements are unreachable so give an error.
121        * @param that  The Body we were type checking
122        * @param items_result  Array of results for each item in the body that was visited.
123        */
124      public TypeData forBodyOnly(Body that, TypeData[] items_result) {
125        for (int i = 0; i < items_result.length; i++) {
126          if (items_result[i] != null && !(that.getStatements()[i] instanceof ExpressionStatement)) {
127            
128            // Found a statement that returns a value.
129            if (i < items_result.length - 1) {
130              
131              // there must be unreachable statements
132              _addError("Unreachable statement.", (JExpression)that.getStatements()[i+1]);
133            }
134            // either way, return the result to keep on type-checking.
135            return items_result[i];
136          }
137        }
138        return null;
139      }
140      
141      /** Delegates to forBodyOnly. */
142      public TypeData forBracedBodyOnly(BracedBody that, TypeData[] items_result) {
143        return forBodyOnly(that, items_result);
144      }
145      
146      /** Delegates to forBodyOnly. */
147      public TypeData forUnbracedBodyOnly(UnbracedBody that, TypeData[] items_result) {
148        return forBodyOnly(that, items_result);
149      }
150    
151      
152      /** Make sure the enclosing method data is declared to return void.  If it is not, give an error.
153        * @return the type the method is declared to return.
154        */
155      public TypeData forVoidReturnStatementOnly(VoidReturnStatement that) {
156        MethodData md = _bodyData.getMethodData();
157        if (md.getReturnType() != SymbolData.VOID_TYPE) {
158          _addError("Cannot return void when the method's expected return type is not void.", that);
159    
160          // Return the correct type to allow type-checking to continue.
161          return md.getReturnType().getInstanceData();
162        }
163        return SymbolData.VOID_TYPE.getInstanceData();
164      }
165    
166      /** Visit the value being returned to determine its type.  Do the necessary bookkeeping and
167        * then delegate to forValueReturnStatementOnly.
168        */
169      public TypeData forValueReturnStatement(ValueReturnStatement that) {
170        ExpressionTypeChecker etc = 
171          new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
172        TypeData valueRes = that.getValue().visit(etc);
173        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
174        return forValueReturnStatementOnly(that, valueRes);
175      }
176    
177      /** Make sure that the enclosing method is declared to throw the same type as the return statement
178        * is trying to return.  Also make sure that what is being returned is an instance of the type,
179        * not the type itself.
180        */
181      public TypeData forValueReturnStatementOnly(ValueReturnStatement that, TypeData valueRes) {
182        MethodData md = _bodyData.getMethodData();
183        SymbolData expected = md.getReturnType();
184        
185        if (expected == null) {
186          // There was an error processing the method's return type; return the result type
187          return valueRes;
188        }
189        
190        if (valueRes == null || ! assertFound(valueRes, that)) { 
191          // There was an error parsing the return type, return the expected type.
192          return expected.getInstanceData(); 
193        }
194        
195        if (valueRes != null && !valueRes.isInstanceType()) {
196         _addError("You cannot return a class or interface name.  Perhaps you meant to say " + valueRes.getName() +
197                   ".class or to create an instance", that);
198         return valueRes.getInstanceData();
199        }
200        
201        if (expected == SymbolData.VOID_TYPE) {
202          _addError("Cannot return a value when the method's expected return type is void.", that);
203          // Return the correc type to allow type-checking to continue.
204          return SymbolData.VOID_TYPE.getInstanceData();
205        }
206        else if (!_isAssignableFrom(expected, valueRes.getSymbolData())) {
207          _addError("This method expected to return type: " + '"' + expected.getName() + '"' 
208                      + " but here returned type: " + '"' + valueRes.getName() + '"', 
209                    that);
210        }
211        return valueRes;
212      }
213      
214      /** First, visit the condition expression of the for statement with a special visitor that
215        * makes sure no assignment is done.
216        * Then, visit the condition expression with the ExpressionTypeChecker which will do all the
217        * normal expression stuff.
218        * Then, visit the update and and code (block) of the for statement with this visitor.
219        * Be very careful about maintaing the various scopes here.
220        */
221      public TypeData forForStatement(ForStatement that) {
222        Boolean expOk = Boolean.TRUE;
223        if (that.getCondition() instanceof Expression) {
224          Expression exp = (Expression) that.getCondition();
225          // Assignment cannot be used in this expression
226          expOk = exp.visit(new NoAssignmentAllowedInExpression("the conditional expression of a for-statement"));
227        }
228    
229        LinkedList<VariableData> newVars = cloneVariableDataList(_vars);
230        BodyTypeChecker btc = 
231          createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, newVars, _thrown);
232        final TypeData init_result = that.getInit().visit(btc);
233        
234        ExpressionTypeChecker etc = 
235          new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, btc._vars, _thrown);
236        final TypeData condition_result = that.getCondition().visit(etc);
237        btc.thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
238        final TypeData update_result = that.getUpdate().visit(btc);
239        final TypeData codeRes = that.getCode().visit(btc);
240        
241        // Now, change any VariableDatas that were given a value in the ForStatement back to having been unassigned since 
242        // its code is not necessarily executed.
243        unassignVariableDatas(btc.thingsThatHaveBeenAssigned);
244        if (expOk.booleanValue()) 
245          return forForStatementOnly(that, init_result, condition_result, update_result, codeRes);
246        else {return null;}
247      }
248      
249      
250      /* Make sure that the conditional expression has the right type. */
251      public TypeData forForStatementOnly(ForStatement that, TypeData init_result, TypeData condition_result, 
252                                          TypeData update_result, TypeData codeRes) {
253        if (condition_result != null && assertFound(condition_result, that)) { 
254          if (!condition_result.isInstanceType()) {
255            _addError("This for-statement's conditional expression must be a boolean value. Instead, it is a class or " +
256                      "interface name", that);
257          }
258          else if (!condition_result.getSymbolData().isBooleanType(LanguageLevelConverter.OPT.javaVersion())) {
259            _addError("This for-statement's conditional expression must be a boolean value. Instead, its type is " + 
260                      condition_result.getName(), that);
261          }
262        }
263        return null;
264      }
265      
266      /** First, visit the condition expression of the if statement with a special visitor that
267        * makes sure no assignment is done.
268        * Then, visit the condition expression with the ExpressionTypeChecker which will do all the
269        * normal expression stuff.
270        * Then, visit the body of the if statement with this visitor.
271        * Be very careful about maintaing the various scopes here.
272        */
273      public TypeData forIfThenStatement(IfThenStatement that) {
274        Boolean expOk = Boolean.TRUE;
275        if (that.getTestExpression() instanceof Expression) {
276          Expression exp = that.getTestExpression();
277          // Assignment cannot be used in this expression
278          expOk = exp.visit(new NoAssignmentAllowedInExpression("the conditional expression of an if-then statement"));
279        }
280    
281        // Update what has been assigned here with results from test expression, because any variables it sees or assigns 
282        // will be visible in the rest of the body.
283        ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, 
284                                                              _vars, _thrown);
285        final TypeData testExpression_result = that.getTestExpression().visit(etc);
286        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
287    
288        //Use a new visitor for the body of the then statement--it is a different lexical scope, so we want to track the
289        //variables seperately.
290        BodyTypeChecker btc = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, 
291                                                     cloneVariableDataList(_vars), _thrown);
292        final TypeData thenStatement_result = that.getThenStatement().visit(btc);
293        
294        //Now, change any VariableDatas that were given a value in the ThenStatement back to having been unassigned
295        unassignVariableDatas(btc.thingsThatHaveBeenAssigned);
296        
297        if (expOk.booleanValue()) {return forIfThenStatementOnly(that, testExpression_result, thenStatement_result);}
298        return null;
299      }
300      
301      /* Make sure that the conditional expression has the right type. */
302      public TypeData forIfThenStatementOnly(IfThenStatement that, TypeData testExpression_result, 
303                                             TypeData thenStatement_result) {
304        if (testExpression_result != null && assertFound(testExpression_result, that.getTestExpression())) {
305          if (!testExpression_result.isInstanceType()) {
306            _addError("This if-then-statement's conditional expression must be a boolean value. Instead, it is a class " +
307                        "or interface name", that);
308          }
309          else if (!testExpression_result.getSymbolData().isBooleanType(LanguageLevelConverter.OPT.javaVersion())) {
310            _addError("This if-then-statement's conditional expression must be a boolean value. Instead, its type is " + 
311                      testExpression_result.getName(), that.getTestExpression());
312          }
313        }
314        return null;
315      }
316      
317    
318      /** First, visit the condition expression of the if-then-else statement with a special visitor that
319        * makes sure no assignment is done.
320        * Then, visit the condition expression with the ExpressionTypeChecker which will do all the
321        * normal expression stuff.
322        * Then, visit the body of the if statement and the else with this visitor.
323        * Be very careful about maintaing the various scopes here.
324        */
325      public TypeData forIfThenElseStatement(IfThenElseStatement that) {
326        Boolean expOk = Boolean.TRUE;
327        if (that.getTestExpression() instanceof Expression) {
328          Expression exp = that.getTestExpression();
329          // Assignment cannot be used in this expression
330          expOk = exp.visit(new NoAssignmentAllowedInExpression("the conditional expression of an if-then-else statement"));
331        }
332        
333        // Update list of what has been assigned with one from test expression, because any variables it sees or assigns 
334        // will be visible in the rest of the body.
335        ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, 
336                                                              _vars, _thrown);
337        final TypeData testExpression_result = that.getTestExpression().visit(etc);
338        thingsThatHaveBeenAssigned = etc.thingsThatHaveBeenAssigned;
339        
340        //Use a new visitor for the body of the then statement--it is a different lexical scope, so we want to track the
341        //variables seperately.
342        BodyTypeChecker btcThen = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, 
343                                                         cloneVariableDataList(_vars), _thrown);
344        final TypeData thenStatement_result = that.getThenStatement().visit(btcThen);
345        //Now, change any VariableDatas that were given a value in the ThenStatement back to having been unassigned
346        unassignVariableDatas(btcThen.thingsThatHaveBeenAssigned);
347    
348    
349        //Use a new visitor for the body of the else statement--it is a different lexical scope, so we want to track the
350        //variables seperately.
351        BodyTypeChecker btcElse = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, 
352                                                         cloneVariableDataList(_vars), _thrown);
353        final TypeData elseStatement_result = that.getElseStatement().visit(btcElse);
354        //Now, change any VariableDatas that were given a value in the ElseStatement back to having been unassigned
355        unassignVariableDatas(btcElse.thingsThatHaveBeenAssigned);
356    
357        //Now compare the two lists of VariableDatas, and reassign those that were assigned in both branches.
358        reassignVariableDatas(btcThen.thingsThatHaveBeenAssigned, btcElse.thingsThatHaveBeenAssigned);
359        
360        if (expOk.booleanValue()) {return forIfThenElseStatementOnly(that, testExpression_result, thenStatement_result, 
361                                                                     elseStatement_result);}
362        return null;
363      }
364        
365      /** Make sure that the conditional expression has the right type, and if both branches of the
366        * if/else return, return a value the common super type of the two return types.
367        * We assume that thenStatement_result and elseStatement_result are InstanceDatas
368        */
369      public TypeData forIfThenElseStatementOnly(IfThenElseStatement that, TypeData testExpression_result, 
370                                                 TypeData thenStatement_result, TypeData elseStatement_result) {
371        if (testExpression_result != null && assertFound(testExpression_result, that.getTestExpression())) {
372          if (!testExpression_result.isInstanceType()) {
373            _addError("This if-then-else statement's conditional expression must be a boolean value. Instead, it is a " +
374                      "class or interface name", 
375                      that);
376          }
377          else if (!testExpression_result.getSymbolData().isBooleanType(LanguageLevelConverter.OPT.javaVersion())) {
378            _addError("This if-then-else statement's conditional expression must be a boolean value. Instead, its type is "
379                        + testExpression_result.getName(), that.getTestExpression());
380          }
381        }
382    
383        if (testExpression_result == null || thenStatement_result == null || elseStatement_result == null) return null;
384         
385        //     We don't throw an error here because if the then and else branches return incompatible types,
386        //     there must have already been an error thrown in forValueReturnStatementOnly
387        //     that indicates that one of the return statements is returning the wrong type.
388        SymbolData result = getCommonSuperType(thenStatement_result.getSymbolData(), elseStatement_result.getSymbolData());
389        if (result==null) {return null;}
390        return result.getInstanceData();
391      } 
392    
393      /** First, visit the condition expression of the while statement with a special visitor that
394        * makes sure no assignment is done.
395        * Then, visit the condition expression with the ExpressionTypeChecker which will do all the
396        * normal expression stuff.
397        * Then, visit the body with this visitor.
398        * Be very careful about maintaing the various scopes here.
399        */
400      public TypeData forWhileStatement(WhileStatement that) {
401        Boolean expOk = Boolean.TRUE;
402        if (that.getCondition() instanceof Expression) {
403          Expression exp = that.getCondition();
404          // Assignment cannot be used in this expression
405          expOk = exp.visit(new NoAssignmentAllowedInExpression("the condition expression of a while statement"));
406        }
407        
408        // Visit the condition expression with an expression type checker and
409        // then update list of what was assigned, because it will always be visited so it is in the same scope as the 
410        // enclosing body.
411        ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, 
412                                                              _vars, _thrown);
413        final TypeData condition_result = that.getCondition().visit(etc);
414        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
415    
416        //Use a new visitor for the body of the while statement--it is a different lexical scope, so we want to track the
417        //variables seperately.
418        BodyTypeChecker btc = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, 
419                                                     cloneVariableDataList(_vars), _thrown);
420        final TypeData codeRes = that.getCode().visit(btc);
421        unassignVariableDatas(btc.thingsThatHaveBeenAssigned);
422        if (expOk.booleanValue()) {return forWhileStatementOnly(that, condition_result, codeRes);}
423        return null;
424      }
425        
426      /** Make sure that the condition statement of the while returns type boolean. */
427      public TypeData forWhileStatementOnly(WhileStatement that, TypeData condition_result, TypeData codeRes) {
428        if (condition_result != null && assertFound(condition_result, that.getCondition())) {
429          if (! condition_result.isInstanceType()) {
430            _addError("This while-statement's conditional expression must be a boolean value. Instead, it is a class or " +
431                        "interface name", that);
432          }
433          else if (!condition_result.getSymbolData().isBooleanType(LanguageLevelConverter.OPT.javaVersion())) {
434            _addError("This while-statement's conditional expression must be a boolean value. Instead, its type is " + 
435                      condition_result.getName(), that.getCondition());
436          }
437        }
438        return null;
439      }
440      
441      /** First, visit the body of the do statement with a body type checker.
442        * Then, visit the condition expression of the do statement with a special visitor that
443        * makes sure no assignment is done.
444        * Then, visit the condition expression with the ExpressionTypeChecker which will do all the
445        * normal expression stuff.
446        * Be very careful about maintaing the various scopes here.
447        */
448      public TypeData forDoStatement(DoStatement that) {
449        //Use a new visitor for the body of the do statement--it is a different lexical scope, so we want to track the
450        //variables seperately.
451        BodyTypeChecker btc = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, 
452                                                     cloneVariableDataList(_vars), _thrown);
453        final TypeData codeRes = that.getCode().visit(btc);
454        unassignVariableDatas(btc.thingsThatHaveBeenAssigned);
455        
456        Boolean expOk = Boolean.TRUE;
457        if (that.getCondition() instanceof Expression) {
458          Expression exp = that.getCondition();
459          // Assignment cannot be used in this expression
460          expOk = exp.visit(new NoAssignmentAllowedInExpression("the condition expression of a do statement"));
461        }
462    
463        // Visit the condition statement with a new ExpressionTypeChecker, then update the thingsThatHaveBeenAssigned list, since it is in the same scope as the body.
464        ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
465        final TypeData condition_result = that.getCondition().visit(etc);
466        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
467    
468        if (expOk.booleanValue()) {return forDoStatementOnly(that, codeRes, condition_result);}
469        return null;
470        
471      }
472    
473    
474      /**Make sure that the condition statement of the while returns type boolean. */
475      public TypeData forDoStatementOnly(DoStatement that, TypeData codeRes, TypeData condition_result) {
476        if (condition_result != null && assertFound(condition_result, that.getCondition())) {
477          if (!condition_result.isInstanceType()) {
478            _addError("This do-statement's conditional expression must be a boolean value. Instead, it is a class or interface name", that.getCondition());
479          }
480          else if (!condition_result.getSymbolData().isBooleanType(LanguageLevelConverter.OPT.javaVersion())) {
481            _addError("This do-statement's conditional expression must be a boolean value. Instead, its type is " + condition_result.getName(), that.getCondition());
482          }
483        }
484        if (codeRes == null) {return null;}
485        return codeRes.getInstanceData();
486      }
487      
488      /*Handle the switch statement(explained within the method)*/
489      public TypeData forSwitchStatement(SwitchStatement that) {
490        Expression exp = that.getTest();
491        //make sure no assignments are made in the switch stmt expression
492        exp.visit(new NoAssignmentAllowedInExpression("the switch expression of a switch statement"));
493    
494        //Visit the test with this visitor, because it is in the scope of the method
495        ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
496        final TypeData testRes = that.getTest().visit(etc);
497        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
498        
499        //The test result of a switch statement must be either an int or a char, according to the JLS.
500        if (testRes == null || !assertFound(testRes, exp)) {return null;}
501        if (!(_isAssignableFrom(SymbolData.INT_TYPE, testRes.getSymbolData()) || _isAssignableFrom(SymbolData.CHAR_TYPE, testRes.getSymbolData()))) {
502          _addError("The switch expression must be either an int or a char.  You have used a " + testRes.getSymbolData().getName(), that.getTest());
503        }
504        
505        final TypeData[] cases_result = makeArrayOfRetType(that.getCases().length);
506        BodyTypeChecker[] btcs = new BodyTypeChecker[that.getCases().length];
507        HashSet<Integer> labels = new HashSet<Integer>();
508        LinkedList<VariableData> variablesAssigned = new LinkedList<VariableData>();
509        boolean seenDefault = false;
510        boolean hadCaseReturn = false;
511        
512        /**
513         * Loop over all the cases, type-checking them and then checking that no labels are duplicated
514         * and only one default statement is present.
515         */
516        for (int i = 0; i < that.getCases().length; i++) {
517          SwitchCase sc = that.getCases()[i];
518          btcs[i] = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, cloneVariableDataList(_vars), _thrown);
519          cases_result[i] = sc.visit(btcs[i]);
520          if (sc instanceof LabeledCase) {
521            LabeledCase lc = (LabeledCase) sc;
522            //Get the label, make sure it is an int or char, and then put it in our hash set.
523              Integer toCheck = null;
524              if (lc.getLabel() instanceof CharLiteral)  { 
525                toCheck = (int) ((CharLiteral) lc.getLabel()).getValue();
526              }
527              if (lc.getLabel() instanceof IntegerLiteral) {
528                toCheck = ((IntegerLiteral) lc.getLabel()).getValue();
529              }
530              if (toCheck != null) {
531                if (labels.contains(toCheck))
532                  _addError("You cannot have two switch cases with the same label " + toCheck, lc.getLabel());
533                else labels.add(toCheck);
534              }
535          }
536          else {
537            if (seenDefault) _addError("A switch statement can only have one default case", sc);
538            seenDefault = true;
539          }
540          
541          // Compare the variables assigned, and let variablesAssigned store the variables that have been assigned in every 
542          // case that returns or breaks up to this one and are also assigned in this one
543          // if we're in the last case, we treat it as a break even though that may not happen explicitly
544    
545          if (cases_result[i] != null || (i == cases_result.length - 1)) { 
546            if (! hadCaseReturn) {
547              variablesAssigned = btcs[i].thingsThatHaveBeenAssigned; 
548              hadCaseReturn = true;
549            }
550            else {
551              Iterator<VariableData> iter = variablesAssigned.iterator();
552              while (iter.hasNext()) {
553                if (!btcs[i].thingsThatHaveBeenAssigned.contains(iter.next())) {iter.remove();}
554              }
555            }
556          }
557          
558          //Now, change any VariableDatas that were given a value in the case statement back to having been unassigned
559          unassignVariableDatas(btcs[i].thingsThatHaveBeenAssigned);
560        }
561    
562        //Now assign a value to all variables that were assigned in each case branch, if there was a default case
563        if (seenDefault) {
564          for (VariableData vd : variablesAssigned) vd.gotValue();
565        }
566        return forSwitchStatementOnly(that, testRes, cases_result, seenDefault);
567    }
568    
569      /** Here, we follow the following rules for determining what to return:
570        * If there is not a default block, the statement does not return.
571        * If the result from any of the blocks is NOT_FOUND, the statement does not return.  (NOT_FOUND signifies that a 
572        * break statement was seen). If the last block does not return, then the statement does not return.
573        */
574       public TypeData forSwitchStatementOnly(SwitchStatement that, TypeData testRes, TypeData[] cases_result, 
575                                              boolean sawDefault) {
576         
577         /**If we did not see a default block, this statement cannot be guaranteed to return*/
578         if (!sawDefault) return null;
579         
580         /**If any of the blocks are NOT_FOUND, then the statement does not return.*/
581         for (int i = 0; i<cases_result.length; i++) {
582           if (cases_result[i] != null && cases_result[i].getSymbolData() == SymbolData.NOT_FOUND) {return null;}
583         }
584         
585         /**If the last block does not return, then the statement also does not return. */
586         if (cases_result[cases_result.length-1] == null) return null;
587         
588         return _bodyData.getMethodData().getReturnType().getInstanceData();
589      }
590      
591      
592      /** Make sure that the label for this LabeledCase is correct.  The label must be a constant expression of type int or 
593        * char.  Then delegate to the super class to handle the braced body of the switch case. */
594       public TypeData forLabeledCase(LabeledCase that) {
595         ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, 
596                                                               _vars, _thrown);
597        final TypeData label_result = that.getLabel().visit(etc);
598        thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
599        Expression exp = that.getLabel();
600        
601        if (label_result == null || !assertFound(label_result, exp)) return null;
602        
603        //we allow constant expressions of the form -5 or 5, but nothing else.
604        if (!(exp instanceof LexicalLiteral || exp instanceof NumericUnaryExpression && 
605              ((NumericUnaryExpression) exp).getValue() instanceof LexicalLiteral)) {
606          _addError("The labels of a switch statement must be constants.  You are using a more complicated expression of" +
607                    " type " + label_result.getSymbolData().getName(), 
608                    that.getLabel());
609        }
610        else if (!_isAssignableFrom(SymbolData.INT_TYPE, label_result.getSymbolData())) {
611          _addError("The labels of a switch statement must be constants of int or char type.  You specified a constant of" +
612                    " type " + label_result.getSymbolData().getName(), 
613                    that.getLabel());
614        }
615        
616        return forSwitchCase(that);
617      }
618      
619      /** Delegate handling this default case to its superclass. */
620      public TypeData forDefaultCase(DefaultCase that) { return forSwitchCase(that); }
621      
622      /** Visit the Braced Body of this SwitchCase, and return the result. */
623      public TypeData forSwitchCase(SwitchCase that) {
624        final TypeData codeRes = that.getCode().visit(this);
625        
626        //If the case falls through (i.e. returns null) but has some statements in it, then there is an error.
627        //We only want to allow fall through for multiple labels, of the form:
628        /** 'a':
629         *  'b':
630         *   return 5;
631         */
632        
633        if (codeRes == null && that.getCode().getStatements().length > 0) {
634          _addError("You must end a non-empty switch case with a break or return statement at the Advanced level", that);
635        }
636        return codeRes;
637      }
638      
639      /* Visit the block, and update with what it assigns.  Return the result of visiting the block. */
640      public TypeData forBlock(Block that) {
641        BlockData bd = _bodyData.getNextBlock();
642        if (bd == null) 
643          throw new RuntimeException("Internal Program Error: Enclosing body does not contain this block." +
644                                                     "  Please report this bug");
645        
646        BodyTypeChecker btc = createANewInstanceOfMe(bd, _file, _package, _importedFiles, _importedPackages, 
647                                                     cloneVariableDataList(_vars), _thrown);
648        TypeData statements_result = that.getStatements().visit(btc);
649        thingsThatHaveBeenAssigned.addAll(btc.thingsThatHaveBeenAssigned);
650        return statements_result;
651      }
652      
653      
654      /*Try to resolve the type and make sure it can be referenced from this context (i.e. is accessible).*/
655      public TypeData forTypeOnly(Type that) {
656        Data sd = getSymbolData(that.getName(), _data, that);
657        while (sd != null && !LanguageLevelVisitor.isJavaLibraryClass(sd.getSymbolData().getName())) {
658          if (!checkAccess(that, sd.getMav(), sd.getName(), sd.getSymbolData(), _bodyData.getSymbolData(), "class")) {
659            return null;
660          }
661          sd = sd.getOuterData();
662        }
663        return null;
664      }
665      
666      /** Makes sure that no super class of any exception is caught before the current exception's catch block. */
667      protected void checkDuplicateExceptions(TryCatchStatement that) {
668        // Make sure that the user isn't throwing duplicate exceptions
669        LinkedList<SymbolData> catchBlockExceptions = new LinkedList<SymbolData>();
670        CatchBlock[] catchBlocks = that.getCatchBlocks();
671        for (int i = 0; i < catchBlocks.length; i++) {
672          catchBlockExceptions.addLast(getSymbolData(catchBlocks[i].getException().getDeclarator().getType().getName(),
673                                                     _data, catchBlocks[i].getException()));
674        }
675        for (int i = 0; i < catchBlockExceptions.size(); i++) {
676          for (int j = i+1; j < catchBlockExceptions.size(); j++) {
677            if (catchBlockExceptions.get(j) != null && catchBlockExceptions.get(j).isSubClassOf(catchBlockExceptions.get(i))) {
678              _addError("Exception " + catchBlockExceptions.get(j).getName() + 
679                        " has already been caught", catchBlocks[j].getException());
680            }
681          }
682        }
683      }
684      
685      /** Check if the two given SymbolDatas have a common super type.  If so, return it, else return null. */
686      protected SymbolData getCommonSuperType(SymbolData s1, SymbolData s2) {
687        if ((s1 == null) && (s2 == null)) {
688          return null;
689        }
690        
691        if (s1 == SymbolData.NOT_FOUND && s2 != null) {return SymbolData.NOT_FOUND;}
692        if (s2 == SymbolData.NOT_FOUND && s1 != null) {return SymbolData.NOT_FOUND;}
693        
694        if (s1 == null && s1 != SymbolData.NOT_FOUND) { return s2; }
695        if (s2 == null && s1 != SymbolData.NOT_FOUND) {return s1;}
696        if (s1==null || s2==null) {return null;}
697        if (s1 == SymbolData.EXCEPTION) { return s2; }
698        if (s2 == SymbolData.EXCEPTION) { return s1; }
699        
700        // See if s1 and s2 have a common super class.
701        SymbolData sd = getCommonSuperTypeBaseCase(s1, s2);
702        if (sd != null ) { return sd; }
703        sd = getCommonSuperTypeBaseCase(s2, s1);
704        if (sd != null) { return sd; }
705        
706        //If s1's superClass is null, then we have gone all the way through the superclass hierarchy without finding a matching class.
707        if (s1.getSuperClass() == null) {
708          //return null;
709          //since we know that Object should be the super class of everything, return Object.
710          return getSymbolData("java.lang.Object", _data, new NullLiteral(SourceInfo.NONE));
711        }
712        
713        // Recur on the super class chain.   
714        sd = getCommonSuperType(s1.getSuperClass(), s2);
715        if (sd != null) {
716          return sd;
717        }
718        
719        // Recur on each interface.
720        for (SymbolData currSd : s1.getInterfaces()) {
721          sd = getCommonSuperType(currSd, s2);
722          if (sd != null) {
723            return sd;
724          }
725        }
726        return null;
727      }
728    
729    
730      /** @return true if the symbol data is the generic SymbolData.EXCEPTIOn class or if it extends java.lang.Throwable*/
731      protected boolean isException(SymbolData sd) {
732        return sd == SymbolData.EXCEPTION || 
733          sd.isSubClassOf(getSymbolData("java.lang.Throwable", new NullLiteral(SourceInfo.NONE), false, false));
734      }
735      
736      /** Returns the least restrictive type returned by the try block and catch blocks.  Returns null
737        * if this try-catch statement doesn't necessarily return a value.
738        */
739      protected InstanceData tryCatchLeastRestrictiveType(InstanceData tryBlockRes, InstanceData[] catchBlocksRes, 
740                                                          InstanceData finallyBlock_result) {
741      // Return the common superclass or null if there exists a block that doesn't return a value(except the finally block) 
742        if (tryBlockRes == null || tryBlockRes == SymbolData.NOT_FOUND.getInstanceData()) 
743          return finallyBlock_result;
744        TypeData leastRestrictiveType = tryBlockRes;
745        for (int i = 0; i < catchBlocksRes.length; i++) {
746          if (catchBlocksRes[i] == null) return finallyBlock_result;
747          if (catchBlocksRes[i] != SymbolData.NOT_FOUND.getInstanceData() && 
748              _isAssignableFrom(catchBlocksRes[i].getSymbolData(), leastRestrictiveType.getSymbolData())) {
749            leastRestrictiveType = catchBlocksRes[i];
750          }
751        }
752    
753        SymbolData result;
754        if (leastRestrictiveType == null && finallyBlock_result == null) return null;
755        else if (leastRestrictiveType == null) result = getCommonSuperType(null, finallyBlock_result.getSymbolData());
756        else if (finallyBlock_result == null) result = getCommonSuperType(leastRestrictiveType.getSymbolData(), null);
757        else result = getCommonSuperType(leastRestrictiveType.getSymbolData(), finallyBlock_result.getSymbolData()); 
758       
759        if (result != null) return result.getInstanceData();
760        return null;
761      }
762      
763      /** Return true if the Exception is unchecked, and false otherwise.
764        * An exception is unchecked if it does not extend either java.lang.RuntimeException or java.lang.Error,
765        * and is not declared to be thrown by the enclosing method.
766        * @param sd  The SymbolData of the Exception we are checking.
767        * @param that  The JExpression passed to getSymbolData for error purposes.
768        */
769      public boolean isUncaughtCheckedException(SymbolData sd, JExpression that) {
770        if (isCheckedException(sd, that)) {
771          MethodData md = _bodyData.getMethodData();
772          for (int i = 0; i<md.getThrown().length; i++) {
773            //If the Exception matches an exception declared to be thrown by the enclosing method, it is not unchecked.
774            if (sd.isSubClassOf(getSymbolData(md.getThrown()[i], _data, that))) {return false;}
775          }
776          return true;
777        }
778        return false;
779      }
780    
781      /** Make sure that every exception that is caught could have been thrown in the try statement */
782      protected void makeSureCaughtStuffWasThrown(TryCatchStatement that, SymbolData[] caught_array, LinkedList<Pair<SymbolData, JExpression>> thrown) {
783        // Make sure every Exception that is caught could actually be thrown
784        for (int i = 0; i < caught_array.length; i++) {
785          SymbolData currCaughtSD = caught_array[i];
786    //      System.err.println("currCaughtSD = " +  currCaughtSD + " isChecked = " + isCheckedException(currCaughtSD, that));
787          boolean foundThrownException = false;
788          if (isCheckedException(currCaughtSD, that) && 
789              ! currCaughtSD.getName().equals("java.lang.Exception") &&
790              ! currCaughtSD.getName().equals("java.lang.Throwable")) {
791    //        System.err.println("Checking thrown");
792            for (Pair<SymbolData, JExpression> p : thrown) {
793              SymbolData sd = p.getFirst();
794              if (sd.isSubClassOf(currCaughtSD)) {
795                foundThrownException = true;
796              }
797            }
798            if (!foundThrownException) {
799    //          System.err.println("Calling _addError for " +  currCaughtSD);
800              _addError("The exception " + currCaughtSD.getName() + 
801                        " is never thrown in the body of the corresponding try block", 
802                        that.getCatchBlocks()[i]);
803            }
804          } 
805        }
806      }
807      
808      /** Make sure that every Exception in thrown is either in caught or in the list of what can be thrown from where we are.
809        * Also make sure that every Exception that is declared to be thrown or caught is actually thrown.
810        * @param that  The TryCatchStatement we are currently working with
811        * @param caught_array  The SymbolData[] of exceptions that are explicitely caught.
812        * @param thrown  The LinkedList of SymbolData of exceptions that are thrown.  This will be modified.
813        */
814      protected void compareThrownAndCaught(TryCatchStatement that, SymbolData[] caught_array, 
815                                            LinkedList<Pair<SymbolData, JExpression>> thrown) {
816        LinkedList<SymbolData> caught = new LinkedList<SymbolData>();
817        for (int i = 0; i<caught_array.length; i++) {
818          caught.addLast(caught_array[i]);
819        }
820    
821        //Make sure that every Exception in thrown is either caught or in the list of what can be thrown
822        for (Pair<SymbolData, JExpression> p : thrown) {
823          SymbolData sd = p.getFirst();
824          JExpression j = p.getSecond();
825          if (isUncaughtCheckedException(sd, j)) {
826            boolean foundCatchBlock = false;
827            for (SymbolData currCaughtSD : caught) {
828              if (sd.isSubClassOf(currCaughtSD)) {
829                foundCatchBlock = true;
830              }
831            }
832            // Check if this exception is a checked exception and is not declared to be thrown by the enclosing method
833            //This is a checked exception.  It should have been caught.
834            if (! foundCatchBlock) {
835              handleUncheckedException(sd, j);
836            }
837          }
838        }
839        
840        makeSureCaughtStuffWasThrown(that, caught_array, thrown);
841      }
842    
843      /** Assumes that tryBlockRes, catchBlocksRes, and finallyBlock_result are InstanceDatas. */
844      public TypeData forTryCatchFinallyStatementOnly(TryCatchFinallyStatement that, TypeData tryBlockRes, TypeData[] catchBlocksRes, TypeData finallyBlock_result) {
845        checkDuplicateExceptions(that);
846        
847        //we know ids are instance datas, but we have to do this to cast them properly.
848        InstanceData[] ids = new InstanceData[catchBlocksRes.length];
849        for (int i = 0; i<ids.length; i++) {
850          if (catchBlocksRes[i] != null) {
851            ids[i]=catchBlocksRes[i].getInstanceData();
852          }
853          else {ids[i]=null;}
854        }
855        
856        /**Make sure null pointer exceptions don't happen.*/
857        if (tryBlockRes == null && finallyBlock_result==null) {return tryCatchLeastRestrictiveType(null, ids, null);}
858        if (tryBlockRes == null) {return tryCatchLeastRestrictiveType(null, ids, finallyBlock_result.getInstanceData());}
859        if (finallyBlock_result == null) {return tryCatchLeastRestrictiveType(tryBlockRes.getInstanceData(), ids, null);}
860    
861        return tryCatchLeastRestrictiveType(tryBlockRes.getInstanceData(), ids, finallyBlock_result.getInstanceData());
862      }
863     
864      /*Visit the try block, catch blocks, and finally block.  Add any exceptions that are not caught to thrown.*/ 
865      public TypeData forTryCatchFinallyStatement(TryCatchFinallyStatement that) {
866        
867        BodyTypeChecker btc = new TryCatchBodyTypeChecker(_bodyData, _file, _package, _importedFiles, _importedPackages, cloneVariableDataList(_vars), new LinkedList<Pair<SymbolData, JExpression>>());
868        final TypeData tryBlockRes = that.getTryBlock().visit(btc);
869    
870        unassignVariableDatas(btc.thingsThatHaveBeenAssigned);
871        
872        BodyTypeChecker[] catchTCs = new BodyTypeChecker[that.getCatchBlocks().length];
873        LinkedList<LinkedList<VariableData>> catchVars = new LinkedList<LinkedList<VariableData>>();
874        CatchBlock[] catchBlocks = that.getCatchBlocks();
875        final TypeData[] catchBlocksRes = makeArrayOfRetType(catchBlocks.length);
876        final SymbolData[] caughtExceptions = new SymbolData[catchBlocks.length];
877    
878        for (int i = 0; i < catchBlocks.length; i++) {
879          catchTCs[i] = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, cloneVariableDataList(_vars), _thrown);
880          catchBlocksRes[i] = catchBlocks[i].visit(catchTCs[i]);
881          unassignVariableDatas(catchTCs[i].thingsThatHaveBeenAssigned);
882          catchVars.addLast(catchTCs[i].thingsThatHaveBeenAssigned);
883          caughtExceptions[i] = getSymbolData(catchBlocks[i].getException().getDeclarator().getType().getName(), _data, catchBlocks[i]);
884        }
885    
886        BodyTypeChecker btcFinally = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, cloneVariableDataList(_vars), _thrown);
887        TypeData finallyBlock_result = that.getFinallyBlock().visit(btcFinally);
888        //leave anything that was assigned in the finally block assigned.  It is always visited.
889        
890        //Give values to anything assigned in the try and catch blocks.
891        reassignLotsaVariableDatas(btc.thingsThatHaveBeenAssigned, catchVars);
892    
893        //If the finallyBlock didn't end abruptly, need to check thrown and caught
894        
895        if (finallyBlock_result == null) {
896          compareThrownAndCaught(that, caughtExceptions, btc._thrown);
897        }
898        
899        else { /**It is like thrown is empty--any exceptions in it don't need to be caught.*/
900          _thrown = new LinkedList<Pair<SymbolData, JExpression>>();
901        }
902        
903        if (finallyBlock_result == SymbolData.NOT_FOUND.getInstanceData()) {
904          finallyBlock_result = null;
905        }
906        
907        // Add the exceptions thrown by btc to our thrown list.
908        if (this instanceof TryCatchBodyTypeChecker) {
909          _thrown.addAll(btc._thrown);
910        }
911        
912        return forTryCatchFinallyStatementOnly(that, tryBlockRes, catchBlocksRes, finallyBlock_result);
913      }
914      
915      
916      /** Resolves the type of the exception, and visits the body, making sure the exception variable
917        * is in scope.
918        */
919      public TypeData forCatchBlock(CatchBlock that) {
920        VariableDeclarator dec = that.getException().getDeclarator();
921        SymbolData exception_result = getSymbolData(dec.getType().getName(), _data, dec.getType());
922        
923        BlockData bd = _bodyData.getNextBlock();
924        if (bd == null) { throw new RuntimeException("Internal Program Error: Enclosing body does not contain this block.  Please report this bug"); }
925        VariableData vd = bd.getVar(dec.getName().getText());
926        if (vd == null) { throw new RuntimeException("Internal Program Error: Catch block does not contain its exception variable.  Please report this bug"); }
927        LinkedList<VariableData> newVars = cloneVariableDataList(_vars);
928        newVars.addLast(vd);
929        BodyTypeChecker btc = createANewInstanceOfMe(bd, _file, _package, _importedFiles, _importedPackages, newVars, _thrown);
930        TypeData block_result = that.getBlock().getStatements().visit(btc);
931        thingsThatHaveBeenAssigned.addAll(btc.thingsThatHaveBeenAssigned);
932        return forCatchBlockOnly(that, exception_result, block_result);
933      }
934      
935      /*Return the result of visiting the body*/
936      public TypeData forCatchBlockOnly(CatchBlock that, SymbolData exception_result, TypeData block_result) {
937        return block_result;
938      }
939      
940      /**Assumes that tryBlockRes, catchBlocksRes, and finallyBlock_result are InstanceDatas*/
941      public TypeData forNormalTryCatchStatementOnly(NormalTryCatchStatement that, TypeData tryBlockRes, TypeData[] catchBlocksRes) {
942        checkDuplicateExceptions(that);
943        InstanceData[] ids = new InstanceData[catchBlocksRes.length];
944        for (int i = 0; i<catchBlocksRes.length; i++) {
945          ids[i]=(InstanceData) catchBlocksRes[i];
946    
947        }
948          
949        return tryCatchLeastRestrictiveType((InstanceData) tryBlockRes, ids, null);
950      }
951      
952      /*no finally block*/
953      public TypeData forNormalTryCatchStatement(NormalTryCatchStatement that) {
954        BodyTypeChecker btc = new TryCatchBodyTypeChecker(_bodyData, _file, _package, _importedFiles, _importedPackages, cloneVariableDataList(_vars), new LinkedList<Pair<SymbolData, JExpression>>());
955        final TypeData tryBlockRes = that.getTryBlock().visit(btc);
956        unassignVariableDatas(btc.thingsThatHaveBeenAssigned);
957    
958        LinkedList<LinkedList<VariableData>> catchVars = new LinkedList<LinkedList<VariableData>>();
959        BodyTypeChecker[] catchTCs = new BodyTypeChecker[that.getCatchBlocks().length];
960    
961        CatchBlock[] catchBlocks = that.getCatchBlocks();
962        final TypeData[] catchBlocksRes = makeArrayOfRetType(catchBlocks.length);
963        final SymbolData[] caughtExceptions = new SymbolData[catchBlocks.length];
964        for (int i = 0; i < catchBlocks.length; i++) {
965          catchTCs[i] = createANewInstanceOfMe(_bodyData, _file, _package, _importedFiles, _importedPackages, cloneVariableDataList(_vars), _thrown);
966          catchBlocksRes[i] = catchBlocks[i].visit(catchTCs[i]);
967          unassignVariableDatas(catchTCs[i].thingsThatHaveBeenAssigned);
968          catchVars.addLast(catchTCs[i].thingsThatHaveBeenAssigned);
969          caughtExceptions[i] = getSymbolData(catchBlocks[i].getException().getDeclarator().getType().getName(), _data, catchBlocks[i]);
970        }
971        
972        //Give values to anything assigned in the try and catch blocks.
973        reassignLotsaVariableDatas(btc.thingsThatHaveBeenAssigned, catchVars);
974        
975        compareThrownAndCaught(that, caughtExceptions, btc._thrown);    
976    
977        // Add the exceptions thrown by btc to our thrown list.
978        if (this instanceof TryCatchBodyTypeChecker) {
979          _thrown.addAll(btc._thrown);
980        }   
981        return forNormalTryCatchStatementOnly(that, tryBlockRes, catchBlocksRes);
982      }
983      
984      
985      /* A special visitor that does not allow assignment in any expressions*/
986      private class NoAssignmentAllowedInExpression extends JExpressionIFAbstractVisitor<Boolean> {
987        String _location;
988        private NoAssignmentAllowedInExpression(String location) { _location = location; }
989      
990        /** Most expressions do not involve assignment. */
991        public Boolean defaultCase(JExpressionIF that) { return Boolean.TRUE; }
992      
993        /* Throw an appropriate error*/
994        public Boolean forIncrementExpression(IncrementExpression that) {
995          _addError("You cannot use an increment or decrement expression in " + _location +  " at any language level", that);
996          return Boolean.FALSE;
997        }
998      
999        /*Throw an appropriate error*/
1000        public Boolean forAssignmentExpression(AssignmentExpression that) {
1001          _addError("You cannot use an assignment expression in " + _location +  " at any language level", that);
1002          return Boolean.FALSE;
1003        }
1004        
1005        /*Throw an appropriate error*/
1006        public Boolean forSimpleAssignmentExpression(SimpleAssignmentExpression that) {
1007          _addError("You cannot use an assignment expression in " + _location +  " at any language level" + ".  Perhaps you meant to compare two values with '=='", that);
1008          return Boolean.FALSE;
1009        }
1010    
1011      }
1012      
1013       /** Test the methods in the above class. */
1014      public static class BodyTypeCheckerTest extends TestCase {
1015        
1016        private BodyTypeChecker _bbtc;
1017        
1018        private BodyData _bd1;
1019        private BodyData _bd2;
1020        
1021        private SymbolData _sd1;
1022        private SymbolData _sd2;
1023        private SymbolData _sd3;
1024        private SymbolData _sd4;
1025        private SymbolData _sd5;
1026        private SymbolData _sd6;
1027        private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
1028        private ModifiersAndVisibility _protectedMav = 
1029          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
1030        private ModifiersAndVisibility _privateMav = 
1031          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
1032        private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
1033        private ModifiersAndVisibility _abstractMav = 
1034          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
1035        private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"}); 
1036        
1037        public BodyTypeCheckerTest() { this("");  }
1038        public BodyTypeCheckerTest(String name) { super(name); }
1039        
1040        public void setUp() {
1041          _sd1 = new SymbolData("i.like.monkey");
1042          _sd2 = new SymbolData("i.like.giraffe");
1043          _sd3 = new SymbolData("zebra");
1044          _sd4 = new SymbolData("u.like.emu");
1045          _sd5 = new SymbolData("");
1046          _sd6 = new SymbolData("cebu");
1047    
1048          _bd1 = new MethodData("methodName1", 
1049                                _packageMav, 
1050                                new TypeParameter[0], 
1051                                SymbolData.INT_TYPE, 
1052                                new VariableData[] { new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, null), new VariableData(SymbolData.BOOLEAN_TYPE) },
1053                                new String[0],
1054                                _sd1,
1055                                null); // no SourceInfo
1056          ((MethodData)_bd1).getParams()[0].setEnclosingData(_bd1);                      
1057          ((MethodData)_bd1).getParams()[1].setEnclosingData(_bd1);                      
1058    
1059          _bd2 = new MethodData("methodName2", 
1060                                _packageMav, 
1061                                new TypeParameter[0], 
1062                                SymbolData.VOID_TYPE, 
1063                                new VariableData[] { new VariableData(SymbolData.INT_TYPE) },
1064                                new String[0],
1065                                _sd1,
1066                                null); // no SourceInfo);
1067           ((MethodData)_bd2).getParams()[0].setEnclosingData(_bd2);
1068                                
1069          errors = new LinkedList<Pair<String, JExpressionIF>>();
1070          LanguageLevelConverter.symbolTable.clear();
1071          LanguageLevelConverter._newSDs.clear();
1072          _bd1.addEnclosingData(_sd1);
1073          _bd1.addVars(((MethodData)_bd1).getParams());
1074          _bd2.addVars(((MethodData)_bd2).getParams());
1075          _bbtc = new BodyTypeChecker(_bd1, new File(""), "", new LinkedList<String>(), new LinkedList<String>(), 
1076                                      new LinkedList<VariableData>(), new LinkedList<Pair<SymbolData,JExpression>>());
1077          LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
1078          _bbtc._importedPackages.addFirst("java.lang");
1079        }
1080        
1081        public void testForUninitializedVariableDeclaratorOnly() {
1082          VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, false, _bd1);
1083          _bd1.addVar(vd1);
1084          UninitializedVariableDeclarator uvd = new UninitializedVariableDeclarator(SourceInfo.NONE, 
1085                                                                                    new PrimitiveType(SourceInfo.NONE, "int"), 
1086                                                                                    new Word(SourceInfo.NONE, "Mojo"));
1087          uvd.visit(_bbtc);
1088          assertTrue("_vars should contain Mojo.", _bbtc._vars.contains(vd1));
1089        }
1090        
1091        public void testForInitializedVariableDeclaratorOnly() {
1092          _bbtc.symbolTable.put("int", SymbolData.INT_TYPE);
1093          VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, true, _bd1);
1094          _bd1.addVar(vd1);
1095          InitializedVariableDeclarator ivd = new InitializedVariableDeclarator(SourceInfo.NONE, 
1096                                                                                new PrimitiveType(SourceInfo.NONE, "int"), 
1097                                                                                new Word(SourceInfo.NONE, "Mojo"), 
1098                                                                                new IntegerLiteral(SourceInfo.NONE, 1));
1099          ivd.visit(_bbtc);
1100          assertEquals("There should be no errors.", 0, errors.size());
1101          assertTrue("_vars should contain Mojo.", _bbtc._vars.contains(vd1));
1102          ivd = new InitializedVariableDeclarator(SourceInfo.NONE, 
1103                                                  new PrimitiveType(SourceInfo.NONE, "int"), 
1104                                                  new Word(SourceInfo.NONE, "Santa's Little Helper"), 
1105                                                  new IntegerLiteral(SourceInfo.NONE, 1));
1106          try {
1107            ivd.visit(_bbtc);
1108            fail("Should have thrown a RuntimeException because there's no field named Santa's Little Helper.");
1109          }
1110          catch (RuntimeException re) {
1111            assertEquals("The error message should be correct.", "Internal Program Error: The field or variable Santa's Little Helper was not found in this block.  Please report this bug.", re.getMessage());
1112          }
1113        }
1114        
1115        public void testForBracedBodyOnly() {
1116          // Test one that works.
1117          BracedBody bb1 = new BracedBody(SourceInfo.NONE,
1118                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1119                                                                                     new IntegerLiteral(SourceInfo.NONE, 1))});
1120          TypeData sd = bb1.visit(_bbtc);
1121          assertEquals("There should be no errors", 0, errors.size());
1122          assertEquals("Should return int type", SymbolData.INT_TYPE.getInstanceData(), sd);
1123          BracedBody bb2 = new BracedBody(SourceInfo.NONE,
1124                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1125                                                                                     new CharLiteral(SourceInfo.NONE, 'e'))});
1126         //test another one that works.
1127          sd = bb2.visit(_bbtc);
1128          assertEquals("There should be no errors", 0, errors.size());
1129          assertEquals("Should return char type", SymbolData.CHAR_TYPE.getInstanceData(), sd);
1130          BracedBody bb3 = new BracedBody(SourceInfo.NONE,
1131                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1132                                                                                     new IntegerLiteral(SourceInfo.NONE, 1)),
1133                                                            new ValueReturnStatement(SourceInfo.NONE,
1134                                                                                     new CharLiteral(SourceInfo.NONE, 'e'))});
1135          //test one that should throw an error: unreachable return statement.                                                                                          
1136          sd = bb3.visit(_bbtc);
1137          assertEquals("There should be one error", 1, errors.size());
1138          assertEquals("The error message should be correct", "Unreachable statement.", errors.get(0).getFirst());
1139          assertEquals("Should return int type", SymbolData.INT_TYPE.getInstanceData(), sd);
1140          
1141          BracedBody bb4 = new BracedBody(SourceInfo.NONE,
1142                                          new BodyItemI[0]);
1143          //test empty body.  should return null.
1144          sd = bb4.visit(_bbtc);
1145          assertEquals("There should still be one error", 1, errors.size());
1146          assertEquals("The error message should still be be correct", "Unreachable statement.", errors.get(0).getFirst());
1147          assertEquals("Should return null", null, sd);
1148        }
1149        
1150        public void testForVoidReturnStatementOnly() {
1151          _bbtc._bodyData = _bd2; //this body data has a void return type
1152    
1153          //test one that works
1154          BracedBody bb1 = new BracedBody(SourceInfo.NONE, 
1155                                          new BodyItemI[] { new VoidReturnStatement(SourceInfo.NONE)});
1156    
1157          TypeData sd = bb1.visit(_bbtc);
1158    
1159          assertEquals("There should be no errors.", 0, errors.size());
1160          assertEquals("Should return void type.", SymbolData.VOID_TYPE.getInstanceData(), sd);
1161    
1162          //test with a method that doesn't return void.
1163          _bbtc._bodyData = _bd1;
1164          sd = bb1.visit(_bbtc);
1165          assertEquals("There should be one error", 1, errors.size());
1166          assertEquals("Should return int type", SymbolData.INT_TYPE.getInstanceData(), sd);
1167          assertEquals("Error message should be correct", "Cannot return void when the method's expected return type is not void.", errors.get(0).getFirst());
1168    
1169        }
1170       
1171        public void testforValueReturnStatementOnly() {
1172          //value return statement returns something that is not a subclass the method return type
1173          BracedBody bb1 = new BracedBody(SourceInfo.NONE,
1174                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1175                                                                                     new BooleanLiteral(SourceInfo.NONE, true))});
1176          TypeData sd = bb1.visit(_bbtc);
1177          assertEquals("There should be one error", 1, errors.size());
1178          assertEquals("Should return boolean type", SymbolData.BOOLEAN_TYPE.getInstanceData(), sd);
1179          assertEquals("Error message should be correct", 
1180                       "This method expected to return type: \"int\" but here returned type: \"boolean\"", errors.get(0).getFirst());
1181          
1182          //value return statement returns something that is assignable from the method return type
1183          BracedBody bb2 = new BracedBody(SourceInfo.NONE,
1184                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1185                                                                                     new CharLiteral(SourceInfo.NONE, 'c'))});
1186          sd = bb2.visit(_bbtc);
1187          assertEquals("There should be still be one error", 1, errors.size());
1188          assertEquals("Should return char type", SymbolData.CHAR_TYPE.getInstanceData(), sd);
1189          assertEquals("Error message should still be correct", "This method expected to return type: \"int\" but here returned type: \"boolean\"", errors.get(0).getFirst());
1190          
1191          
1192          //method returns void
1193          _bbtc._bodyData = _bd2; //this body data has a void return type
1194          
1195          BracedBody bb3 = new BracedBody(SourceInfo.NONE,
1196                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1197                                                                                     new IntegerLiteral(SourceInfo.NONE, 1))});
1198    
1199          sd = bb3.visit(_bbtc);
1200          assertEquals("There should be two errors", 2, errors.size());
1201          assertEquals("Should return void type", SymbolData.VOID_TYPE.getInstanceData(), sd);
1202          assertEquals("Error message should be correct", "Cannot return a value when the method's expected return type is void.", errors.get(1).getFirst());
1203    
1204          // Test where the return value is a class name.
1205          BracedBody bb4 = new BracedBody(SourceInfo.NONE,
1206                                          new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1207                                                                                     new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int")))});
1208    
1209          sd = bb4.visit(_bbtc);
1210          assertEquals("There should be 3 errors", 3, errors.size());
1211          assertEquals("Should return int type", SymbolData.INT_TYPE.getInstanceData(), sd);
1212          assertEquals("Error message should be correct", "You cannot return a class or interface name.  Perhaps you meant to say int.class or to create an instance", errors.getLast().getFirst());
1213    
1214        }
1215        
1216        public void testForIfThenElseStatementOnly() {
1217          //test if the expression is not of boolean type
1218          IfThenElseStatement ites1 = new IfThenElseStatement(SourceInfo.NONE,
1219                                                              new IntegerLiteral(SourceInfo.NONE, 1),
1220                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)),
1221                                                              new ValueReturnStatement(SourceInfo.NONE, new CharLiteral(SourceInfo.NONE, 'j')));
1222    
1223          TypeData sd = ites1.visit(_bbtc);
1224          assertEquals("There should be one error", 1, errors.size());
1225          assertEquals("Error message should be correct", "This if-then-else statement's conditional expression must be a boolean value. Instead, its type is int", errors.get(0).getFirst());
1226    
1227          assertEquals("Should return integer type", SymbolData.INT_TYPE.getInstanceData(), sd);
1228                                                        
1229          
1230          //test if the branches do not return subtypes of each other
1231          IfThenElseStatement ites2 = new IfThenElseStatement(SourceInfo.NONE,
1232                                                              new BooleanLiteral(SourceInfo.NONE, true),
1233                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)),
1234                                                              new ValueReturnStatement(SourceInfo.NONE, new BooleanLiteral(SourceInfo.NONE, true)));
1235    
1236          sd = ites2.visit(_bbtc);
1237          assertEquals("There should be two errors", 2, errors.size());
1238          
1239          assertEquals("Should return Object type", "java.lang.Object", sd.getName());
1240          assertEquals("Error message should be correct", 
1241                       "This method expected to return type: \"int\" but here returned type: \"boolean\"", 
1242                       errors.get(1).getFirst());                                                          
1243    
1244          //test if they do return subtypes of each other
1245          IfThenElseStatement ites3 = new IfThenElseStatement(SourceInfo.NONE,
1246                                                              new BooleanLiteral(SourceInfo.NONE, true),
1247                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)),
1248                                                              new ValueReturnStatement(SourceInfo.NONE, new CharLiteral(SourceInfo.NONE, 'f')));
1249    
1250          sd = ites3.visit(_bbtc);
1251          assertEquals("There should still be two errors", 2, errors.size());
1252          assertEquals("Should return int type", SymbolData.INT_TYPE.getInstanceData(), sd);
1253          
1254          //test if neither branch returns
1255          IfThenElseStatement ites4 = new IfThenElseStatement(SourceInfo.NONE,
1256                                                              new BooleanLiteral(SourceInfo.NONE, true),
1257                                                              new EmptyStatement(SourceInfo.NONE),
1258                                                              new EmptyStatement(SourceInfo.NONE));
1259    
1260          sd = ites4.visit(_bbtc);
1261          assertEquals("There should still be two errors", 2, errors.size());
1262          assertEquals("Should return null type", null, sd);
1263          
1264          //test if only one branch returns      
1265          IfThenElseStatement ites5 = new IfThenElseStatement(SourceInfo.NONE,
1266                                                              new BooleanLiteral(SourceInfo.NONE, true),
1267                                                              new EmptyStatement(SourceInfo.NONE),
1268                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 3)));
1269    
1270          sd = ites5.visit(_bbtc);
1271          assertEquals("There should still be two errors", 2, errors.size());
1272          assertEquals("Should return null type", null, sd);      
1273    
1274          
1275          // Test for the word "boolean" as the condition.
1276          IfThenElseStatement ites6 = new IfThenElseStatement(SourceInfo.NONE,
1277                                                              new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "boolean")),
1278                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)),
1279                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)));
1280                                                              
1281          sd = ites6.visit(_bbtc);
1282          assertEquals("There should be 3 errors", 3, errors.size());
1283          
1284          assertEquals("Should return Integer type", SymbolData.INT_TYPE.getInstanceData(), sd);
1285          assertEquals("Error message should be correct", 
1286                       "This if-then-else statement's conditional expression must be a boolean value. Instead, it is a class or interface name", 
1287                       errors.get(2).getFirst());                                                          
1288    }
1289        
1290        public void testForBlock() {
1291          //Check that a block can reference fields in its enclosing method.
1292          Block b = new Block(SourceInfo.NONE, 
1293                              new BracedBody(SourceInfo.NONE,
1294                                             new BodyItemI[] { new ValueReturnStatement(SourceInfo.NONE,
1295                                                                                        new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")))}));
1296          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1297          LinkedList<VariableData> vars = new LinkedList<VariableData>();
1298          vars.addLast(new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, _bd1));
1299          _bbtc._vars = vars;
1300          TypeData sd = b.visit(_bbtc);
1301          assertEquals("There should not be any errors.", 0, errors.size());
1302          assertEquals("Should return int type.", SymbolData.INT_TYPE.getInstanceData(), sd);
1303        }
1304        
1305        public void testForIfThenStatementOnly() {
1306          SymbolData sd1 = SymbolData.BOOLEAN_TYPE;
1307          SymbolData sd2 = SymbolData.INT_TYPE;
1308    
1309          IfThenStatement its = new IfThenStatement(SourceInfo.NONE, 
1310                                                    new NullLiteral(SourceInfo.NONE), 
1311                                                    new EmptyStatement(SourceInfo.NONE));
1312          
1313    
1314          //test a correct condition type
1315          assertEquals("sd1 is boolean type, so should not add error. Returns null.", null, 
1316                       _bbtc.forIfThenStatementOnly(its, sd1.getInstanceData(), null));
1317          assertEquals("No errors should have been added", 0, errors.size());
1318          
1319          //test an incorrect condition type
1320          assertEquals("sd2 is not boolean type, so should add error. Returns null.", null, 
1321                       _bbtc.forIfThenStatementOnly(its, sd2.getInstanceData(), null));
1322          assertEquals("Should now be one error.", 1, errors.size());
1323          assertEquals("Error message should be correct.", "This if-then-statement's conditional expression must be a boolean value. Instead, its type is int", errors.getLast().getFirst());
1324          
1325          //test "bool" as a condition
1326          assertEquals("sd1 is not an instance, so should add error. Returns null.", null, 
1327                       _bbtc.forIfThenStatementOnly(its, sd1, null));
1328          assertEquals("Should now be 2 errors.", 2, errors.size());
1329          assertEquals("Error message should be correct.", "This if-then-statement's conditional expression must be a boolean value. Instead, it is a class or interface name", errors.getLast().getFirst());
1330        }
1331       
1332        public void testForIfThenStatement() {
1333          //Test that the proper variable assignment happens.
1334          //here, a variable is only assigned in the then branch, so it should not be set after it returns.
1335          Expression te = new LessThanExpression(SourceInfo.NONE, 
1336                                                 new SimpleNameReference(SourceInfo.NONE, 
1337                                                                         new Word(SourceInfo.NONE, "j")),
1338                                                 new IntegerLiteral(SourceInfo.NONE, 5));
1339          Statement ts = 
1340            new ExpressionStatement(SourceInfo.NONE, 
1341                                    new SimpleAssignmentExpression(SourceInfo.NONE, 
1342                                                                   new SimpleNameReference(SourceInfo.NONE, 
1343                                                                                           new Word(SourceInfo.NONE, "i")), 
1344                                                                   new IntegerLiteral(SourceInfo.NONE, 10)));
1345          IfThenStatement ift = new IfThenStatement(SourceInfo.NONE, te, ts);
1346          
1347          PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
1348          UninitializedVariableDeclarator uvd = 
1349            new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
1350          FormalParameter param = 
1351            new FormalParameter(SourceInfo.NONE, 
1352                                new UninitializedVariableDeclarator(SourceInfo.NONE, intt, 
1353                                                                    new Word(SourceInfo.NONE, "j")), false);
1354          BracedBody bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] { 
1355            new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1356          
1357          ConcreteMethodDef cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1358                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1359                                                         new ReferenceType[0], bb);
1360    
1361          VariableData vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1362          VariableData vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1363          MethodData md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1364                                         new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1365          
1366          vd1.setEnclosingData(md1);
1367          vd2.setEnclosingData(md1);
1368          md1.addVar(vd1);
1369          md1.addVar(vd2);
1370          
1371          LinkedList<VariableData> vars = new LinkedList<VariableData>();
1372          vars.addLast(vd1);
1373          vars.addLast(vd2);
1374          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, 
1375                                      new LinkedList<Pair<SymbolData, JExpression>>());
1376          _bbtc._bodyData = md1;
1377          _bbtc._data = md1;
1378          
1379          
1380          
1381          ift.visit(_bbtc);
1382          assertTrue("vd1 should be assigned", vd1.hasValue());
1383          assertFalse("vd2 should not be assigned", vd2.hasValue());
1384    
1385          
1386          //Here, a variable is assigned before the if, so it should still have a value after the if.
1387    
1388          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1389          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
1390          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1391                                         new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1392    
1393          vd1.setEnclosingData(md1);
1394          vd2.setEnclosingData(md1);
1395          md1.addVar(vd1);
1396          md1.addVar(vd2);
1397          
1398          vars = new LinkedList<VariableData>();
1399          vars.addLast(vd1);
1400          vars.addLast(vd2);
1401          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, 
1402                                      new LinkedList<Pair<SymbolData, JExpression>>());
1403          _bbtc._bodyData = md1;
1404          _bbtc._data = md1;
1405    
1406          ift.visit(_bbtc);
1407          assertTrue("vd1 should be assigned", vd1.hasValue());
1408          assertTrue("vd2 should also be assigned", vd2.hasValue());
1409     
1410          
1411          //test that if a variable is assigned in a branch of the if, and then returned, it is okay.
1412          te = new LessThanExpression(SourceInfo.NONE, 
1413                                      new SimpleNameReference(SourceInfo.NONE, 
1414                                                              new Word(SourceInfo.NONE, "j")),
1415                                      new IntegerLiteral(SourceInfo.NONE, 5));
1416          Statement assignStatement = 
1417            new ExpressionStatement(SourceInfo.NONE, 
1418                                    new SimpleAssignmentExpression(SourceInfo.NONE, 
1419                                                                   new SimpleNameReference(SourceInfo.NONE, 
1420                                                                                           new Word(SourceInfo.NONE, "i")), 
1421                                                                   new IntegerLiteral(SourceInfo.NONE, 10)));
1422          Statement returnStatement = 
1423            new ValueReturnStatement(SourceInfo.NONE, 
1424                                     new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")));
1425          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement, returnStatement}));
1426          ift = new IfThenStatement(SourceInfo.NONE, te, ts);
1427          
1428          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1429          
1430          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1431                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1432                                       new ReferenceType[0], bb);
1433    
1434          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1435          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1436          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1437                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1438          
1439          vd1.setEnclosingData(md1);
1440          vd2.setEnclosingData(md1);
1441          md1.addVar(vd1);
1442          md1.addVar(vd2);
1443          
1444          vars = new LinkedList<VariableData>();
1445          vars.addLast(vd1);
1446          vars.addLast(vd2);
1447          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1448          _bbtc._bodyData = md1;
1449          _bbtc._data = md1;
1450          
1451          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1452          
1453          ift.visit(_bbtc);
1454          assertTrue("vd1 should be assigned", vd1.hasValue());
1455          assertFalse("vd2 should not be assigned", vd2.hasValue());
1456          assertEquals("There should be no errors", 0, errors.size());
1457          errors = new LinkedList<Pair<String, JExpressionIF>>();
1458          
1459          // Test that an assignment in the if-expression throws an error
1460          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1461            new IntegerLiteral(SourceInfo.NONE, 5));
1462          ts = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1463          ift = new IfThenStatement(SourceInfo.NONE, te, ts);
1464          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1465          
1466          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1467                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1468                                                         new ReferenceType[0], bb);
1469    
1470          vd1 = new VariableData("b", _packageMav, SymbolData.BOOLEAN_TYPE, true, null);
1471          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1472          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1473                                         new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1474          
1475          vd1.setEnclosingData(md1);
1476          vd2.setEnclosingData(md1);
1477    
1478          md1.addVar(vd1);
1479          md1.addVar(vd2);
1480          
1481          vars = new LinkedList<VariableData>();
1482          vars.addLast(vd1);
1483          vars.addLast(vd2);
1484          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1485          _bbtc._bodyData = md1;
1486          _bbtc._data = md1;
1487          
1488          te = new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "b")),
1489            new BooleanLiteral(SourceInfo.NONE, true));
1490          ts = new ExpressionStatement(SourceInfo.NONE, 
1491                                       new SimpleAssignmentExpression(SourceInfo.NONE, 
1492                                                                      new SimpleNameReference(SourceInfo.NONE, 
1493                                                                                              new Word(SourceInfo.NONE, "i")), 
1494                                                                      new IntegerLiteral(SourceInfo.NONE, 10)));
1495          ift = new IfThenStatement(SourceInfo.NONE, te, ts);
1496          
1497          ift.visit(_bbtc);
1498          assertEquals("There should now be one error", 1, errors.size());
1499          assertEquals("Error message should be correct", "You cannot use an assignment expression in the conditional " +
1500                       "expression of an if-then statement at any language level.  Perhaps you meant to compare two " +
1501                       "values with '=='",
1502                       errors.get(0).getFirst());
1503          
1504          
1505        }
1506        
1507        public void testForIfThenElseStatement() {
1508          
1509          //Test that the proper variable assignment happens.
1510          //here, a variable is only assigned in the then branch, so it should not be set after it returns.
1511          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1512            new IntegerLiteral(SourceInfo.NONE, 5));
1513          Statement ts = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1514    
1515          IfThenElseStatement ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, new EmptyStatement(SourceInfo.NONE));
1516          
1517          PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
1518          UninitializedVariableDeclarator uvd = new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
1519          FormalParameter param = new FormalParameter(SourceInfo.NONE, new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "j")), false);
1520          BracedBody bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1521          
1522          ConcreteMethodDef cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1523                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1524                                                         new ReferenceType[0], bb);
1525    
1526          VariableData vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1527          VariableData vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1528          MethodData md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1529                                         new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1530          
1531          vd1.setEnclosingData(md1);
1532          vd2.setEnclosingData(md1);
1533    
1534          md1.addVar(vd1);
1535          md1.addVar(vd2);
1536          
1537          LinkedList<VariableData> vars = new LinkedList<VariableData>();
1538          vars.addLast(vd1);
1539          vars.addLast(vd2);
1540          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1541          _bbtc._bodyData = md1;
1542          _bbtc._data = md1;      
1543          
1544          ift.visit(_bbtc);
1545          assertTrue("vd1 should be assigned", vd1.hasValue());
1546          assertFalse("vd2 should not be assigned", vd2.hasValue());
1547          
1548          //test that if a variable is only assigned in the else case that it is not assigned afterwards
1549          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1550            new IntegerLiteral(SourceInfo.NONE, 5));
1551          Statement assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1552          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
1553          ift = new IfThenElseStatement(SourceInfo.NONE, te, new EmptyStatement(SourceInfo.NONE), ts);
1554          
1555          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1556          
1557          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1558                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1559                                       new ReferenceType[0], bb);
1560                                       
1561          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1562          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1563          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1564                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1565          
1566          vd1.setEnclosingData(md1);
1567          vd2.setEnclosingData(md1);
1568    
1569          md1.addVar(vd1);
1570          md1.addVar(vd2);
1571          
1572          vars = new LinkedList<VariableData>();
1573          vars.addLast(vd1);
1574          vars.addLast(vd2);
1575          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1576          _bbtc._bodyData = md1;
1577          _bbtc._data = md1;
1578          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1579          
1580          ift.visit(_bbtc);
1581          assertTrue("vd1 should be assigned", vd1.hasValue());
1582          assertFalse("vd2 should not be assigned", vd2.hasValue());
1583          assertEquals("There should be no errors", 0, errors.size());
1584          
1585          //Here, a variable is assigned before the if, so it should still have a value after the if.
1586    
1587          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1588          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
1589          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1590                                         new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1591          
1592          vd1.setEnclosingData(md1);
1593          vd2.setEnclosingData(md1);
1594    
1595          md1.addVar(vd1);
1596          md1.addVar(vd2);
1597          
1598          vars = new LinkedList<VariableData>();
1599          vars.addLast(vd1);
1600          vars.addLast(vd2);
1601          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1602          _bbtc._bodyData = md1;
1603          _bbtc._data = md1;
1604          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1605    
1606          ift.visit(_bbtc);
1607          assertTrue("vd1 should be assigned", vd1.hasValue());
1608          assertTrue("vd2 should also be assigned", vd2.hasValue());
1609     
1610          
1611          //test that if a variable is assigned in a branch of the if, and then returned, it is okay.
1612          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1613            new IntegerLiteral(SourceInfo.NONE, 5));
1614          assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1615          Statement returnStatement = new ValueReturnStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")));
1616          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement, returnStatement}));
1617          ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, new EmptyStatement(SourceInfo.NONE));
1618          
1619          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1620          
1621          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1622                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1623                                       new ReferenceType[0], bb);
1624    
1625          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1626          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1627          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1628                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1629          
1630          vd1.setEnclosingData(md1);
1631          vd2.setEnclosingData(md1);
1632    
1633          md1.addVar(vd1);
1634          md1.addVar(vd2);
1635          
1636          vars = new LinkedList<VariableData>();
1637          vars.addLast(vd1);
1638          vars.addLast(vd2);
1639          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1640          _bbtc._bodyData = md1;
1641          _bbtc._data = md1;
1642          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1643    
1644          
1645          ift.visit(_bbtc);
1646          assertTrue("vd1 should be assigned", vd1.hasValue());
1647          assertFalse("vd2 should not be assigned", vd2.hasValue());
1648          assertEquals("There should be no errors", 0, errors.size());
1649          errors = new LinkedList<Pair<String, JExpressionIF>>();
1650    
1651          
1652          //test that if a variable is assigned in the then case that it cannot be used in the else case.
1653          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1654            new IntegerLiteral(SourceInfo.NONE, 5));
1655          assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1656          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
1657          ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, new ExpressionStatement(SourceInfo.NONE, new EqualsExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word (SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 32))));
1658          
1659          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1660          
1661          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1662                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1663                                       new ReferenceType[0], bb);
1664                                       
1665          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1666          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1667          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1668                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1669          
1670          vd1.setEnclosingData(md1);
1671          vd2.setEnclosingData(md1);
1672    
1673          md1.addVar(vd1);
1674          md1.addVar(vd2);
1675          
1676          vars = new LinkedList<VariableData>();
1677          vars.addLast(vd1);
1678          vars.addLast(vd2);
1679          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1680          _bbtc._bodyData = md1;
1681          _bbtc._data = md1;
1682          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1683           
1684         
1685          ift.visit(_bbtc);
1686          assertTrue("vd1 should be assigned", vd1.hasValue());
1687          assertFalse("vd2 should not be assigned", vd2.hasValue());
1688          assertEquals("There should be one error", 1, errors.size());
1689          assertEquals("The error message should be correct", "You cannot use i because it may not have been given a value", errors.get(0).getFirst());
1690          
1691          //test that if a variable is assigned in both cases that it is assigned afterwards
1692          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1693            new IntegerLiteral(SourceInfo.NONE, 5));
1694          assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1695          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
1696          ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, ts);
1697          
1698          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1699          
1700          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1701                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1702                                       new ReferenceType[0], bb);
1703                                       
1704          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1705          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1706          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1707                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1708          
1709          vd1.setEnclosingData(md1);
1710          vd2.setEnclosingData(md1);
1711    
1712          md1.addVar(vd1);
1713          md1.addVar(vd2);
1714          
1715          vars = new LinkedList<VariableData>();
1716          vars.addLast(vd1);
1717          vars.addLast(vd2);
1718          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1719          _bbtc._bodyData = md1;
1720          _bbtc._data = md1;
1721          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1722          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1723          
1724          
1725          ift.visit(_bbtc);
1726          assertTrue("vd1 should be assigned", vd1.hasValue());
1727          assertTrue("vd2 should be assigned", vd2.hasValue());
1728          assertEquals("There should be one error", 1, errors.size());
1729          
1730          
1731          //Test that if assignment is used in the conditional expression, an error is thrown
1732          te = new PlusAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 5));
1733          assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));      
1734          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
1735          ift = new IfThenElseStatement(SourceInfo.NONE, te, new EmptyStatement(SourceInfo.NONE), ts);
1736          
1737          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1738          
1739          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1740                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1741                                       new ReferenceType[0], bb);
1742                                       
1743          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1744          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
1745          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1746                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1747          
1748          vd1.setEnclosingData(md1);
1749          vd2.setEnclosingData(md1);
1750    
1751          md1.addVar(vd1);
1752          md1.addVar(vd2);
1753          
1754          vars = new LinkedList<VariableData>();
1755          vars.addLast(vd1);
1756          vars.addLast(vd2);
1757          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1758          _bbtc._bodyData = md1;
1759          _bbtc._data = md1;
1760          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1761          
1762          
1763          ift.visit(_bbtc);
1764          assertEquals("There should now be two errors", 2, errors.size());
1765          assertEquals("The error message should be correct", "You cannot use an assignment expression in the conditional expression of an if-then-else statement at any language level", errors.get(1).getFirst());
1766          
1767          //test that if one branch returns a value but the other is a break or continue that SymbolData.NOT_FOUND is returned.
1768          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1769            new IntegerLiteral(SourceInfo.NONE, 5));
1770          returnStatement = new ValueReturnStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")));
1771          ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {returnStatement}));
1772          BreakStatement bs = new UnlabeledBreakStatement(SourceInfo.NONE);
1773          ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, bs);
1774          
1775          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), ift});
1776          
1777          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1778                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1779                                       new ReferenceType[0], bb);
1780                                       
1781          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1782          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
1783          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1784                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1785          
1786          vd1.setEnclosingData(md1);
1787          vd2.setEnclosingData(md1);
1788    
1789          md1.addVar(vd1);
1790          md1.addVar(vd2);
1791          
1792          vars = new LinkedList<VariableData>();
1793          vars.addLast(vd1);
1794          vars.addLast(vd2);
1795          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1796          _bbtc._bodyData = md1;
1797          _bbtc._data = md1;
1798          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1799    
1800          assertEquals("Should return SymbolData.NOT_FOUND", SymbolData.NOT_FOUND.getInstanceData(), ift.visit(_bbtc));
1801          
1802          assertEquals("There should still be two errors", 2, errors.size());      
1803        }
1804        
1805        public void testForForStatement() {
1806          //Test that the proper variable assignment happens.
1807          //here, a variable is only assigned in the for init, so it should not be set after it returns.
1808          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1809            new IntegerLiteral(SourceInfo.NONE, 5));
1810    
1811          UnparenthesizedExpressionList sel = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10))});
1812          ForStatement fs = new ForStatement(SourceInfo.NONE, sel, te, new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[0]), new EmptyStatement(SourceInfo.NONE));
1813          //      IfThenElseStatement ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, new EmptyStatement(SourceInfo.NONE));
1814          
1815          PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
1816          UninitializedVariableDeclarator uvd = new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
1817          FormalParameter param = new FormalParameter(SourceInfo.NONE, new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "j")), false);
1818          BracedBody bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), fs});
1819          
1820          ConcreteMethodDef cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1821                                                         intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1822                                                         new ReferenceType[0], bb);
1823                                                         
1824          VariableData vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1825          VariableData vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1826          MethodData md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1827                                          new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1828          
1829          vd1.setEnclosingData(md1);
1830          vd2.setEnclosingData(md1);
1831    
1832          md1.addVar(vd1);
1833          md1.addVar(vd2);
1834          
1835          LinkedList<VariableData> vars = new LinkedList<VariableData>();
1836          vars.addLast(vd1);
1837          vars.addLast(vd2);
1838          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1839          _bbtc._bodyData = md1;
1840          _bbtc._data = md1;      
1841    
1842          fs.visit(_bbtc);
1843          assertTrue("vd1 should be assigned", vd1.hasValue());
1844          assertFalse("vd2 should not be assigned", vd2.hasValue());
1845          assertEquals("There should be no errors", 0, errors.size());
1846          
1847          //test that if a variable is testForForStdeclared in the for init that it has a value in the scope of the for statement, but not afterwards
1848          te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
1849            new IntegerLiteral(SourceInfo.NONE, 5));
1850          VariableDeclaration vd = new VariableDeclaration (SourceInfo.NONE, _publicMav, new VariableDeclarator[] { new InitializedVariableDeclarator(SourceInfo.NONE, new PrimitiveType(SourceInfo.NONE, "int"), new Word(SourceInfo.NONE, "i"), new IntegerLiteral(SourceInfo.NONE, 10))});
1851          UnparenthesizedExpressionList sel2 = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {te});
1852          fs = new ForStatement(SourceInfo.NONE, sel, te, sel2, new ExpressionStatement(SourceInfo.NONE, te));
1853                
1854          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {fs});
1855          
1856          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1857                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1858                                       new ReferenceType[0], bb);
1859                                       
1860          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1861          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1862          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1863                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1864          
1865          vd1.setEnclosingData(md1);
1866          vd2.setEnclosingData(md1);
1867    
1868          md1.addVar(vd1);
1869          md1.addVar(vd2);
1870          
1871          vars = new LinkedList<VariableData>();
1872          vars.addLast(vd1);
1873          vars.addLast(vd2);
1874          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1875          _bbtc._bodyData = md1;
1876          _bbtc._data = md1;
1877          
1878          fs.visit(_bbtc);
1879          assertTrue("vd1 should be assigned", vd1.hasValue());
1880          assertFalse("vd2 should not be assigned", vd2.hasValue());
1881          assertEquals("There should be no errors", 0, errors.size());
1882          
1883          //here, a variable is only assigned in the for init and the for body, so it should not be set after it returns.
1884          Statement ts = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));
1885    //      te = new Expression(SourceInfo.NONE, new ExpressionPiece[] { new Word(SourceInfo.NONE, "j"),
1886    //        new Operator(SourceInfo.NONE, "<"), new IntegerLiteral(SourceInfo.NONE, 5)});
1887          sel = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10))});
1888          fs = new ForStatement(SourceInfo.NONE, sel, new EmptyForCondition(SourceInfo.NONE), new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[0]), new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {ts})));
1889          //      IfThenElseStatement ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, new EmptyStatement(SourceInfo.NONE));
1890          
1891          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), fs});
1892          
1893          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1894                                                         intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1895                                                         new ReferenceType[0], bb);
1896                                                         
1897          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1898          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1899          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1900                                          new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1901          
1902          vd1.setEnclosingData(md1);
1903          vd2.setEnclosingData(md1);
1904    
1905          md1.addVar(vd1);
1906          md1.addVar(vd2);
1907          
1908          vars = new LinkedList<VariableData>();
1909          vars.addLast(vd1);
1910          vars.addLast(vd2);
1911          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1912          _bbtc._bodyData = md1;
1913          _bbtc._data = md1;      
1914          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
1915          
1916          fs.visit(_bbtc);
1917          assertTrue("vd1 should be assigned", vd1.hasValue());
1918          assertFalse("vd2 should not be assigned", vd2.hasValue());
1919          assertEquals("There should be no errors", 0, errors.size());
1920    
1921          //here, a variable is assigned before the for init, so it should still be set after it returns.
1922    //      te = new Expression(SourceInfo.NONE, new ExpressionPiece[] { new Word(SourceInfo.NONE, "j"),
1923    //        new Operator(SourceInfo.NONE, "<"), new IntegerLiteral(SourceInfo.NONE, 5)});
1924          sel = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10))});
1925          fs = new ForStatement(SourceInfo.NONE, sel, new EmptyForCondition(SourceInfo.NONE), new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[0]), new EmptyStatement(SourceInfo.NONE));
1926          //      IfThenElseStatement ift = new IfThenElseStatement(SourceInfo.NONE, te, ts, new EmptyStatement(SourceInfo.NONE));
1927          
1928          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE,  _packageMav, new UninitializedVariableDeclarator[]{uvd}), fs});
1929          
1930          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1931                                                         intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1932                                                         new ReferenceType[0], bb);
1933                                                         
1934          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1935          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
1936          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1937                                          new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1938          
1939          vd1.setEnclosingData(md1);
1940          vd2.setEnclosingData(md1);
1941    
1942          md1.addVar(vd1);
1943          md1.addVar(vd2);
1944          
1945          vars = new LinkedList<VariableData>();
1946          vars.addLast(vd1);
1947          vars.addLast(vd2);
1948          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1949          _bbtc._bodyData = md1;
1950          _bbtc._data = md1;      
1951          
1952          fs.visit(_bbtc);
1953          assertTrue("vd1 should be assigned", vd1.hasValue());
1954          assertTrue("vd2 should be assigned", vd2.hasValue());
1955          assertEquals("Should be 0 errors", 0, errors.size());
1956          
1957    //      make sure that assignment is not allowed in the conditional of the for statement
1958          te = new PlusAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")), new IntegerLiteral(SourceInfo.NONE, 5));
1959          vd = new VariableDeclaration (SourceInfo.NONE, _publicMav, new VariableDeclarator[] { new InitializedVariableDeclarator(SourceInfo.NONE, new PrimitiveType(SourceInfo.NONE, "int"), new Word(SourceInfo.NONE, "i"), new IntegerLiteral(SourceInfo.NONE, 10))});
1960          sel2 = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {te});
1961          fs = new ForStatement(SourceInfo.NONE, sel, te, sel2, new EmptyStatement(SourceInfo.NONE));
1962                
1963          bb = new BracedBody(SourceInfo.NONE, new BodyItemI[] {fs});
1964          
1965          cmd1 = new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0], 
1966                                       intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param}, 
1967                                       new ReferenceType[0], bb);
1968                                       
1969          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
1970          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
1971          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1972                               new VariableData[] {vd1}, new String[0], _sd1, cmd1);
1973          
1974          vd1.setEnclosingData(md1);
1975          vd2.setEnclosingData(md1);
1976    
1977          md1.addVar(vd1);
1978          md1.addVar(vd2);
1979          
1980          vars = new LinkedList<VariableData>();
1981          vars.addLast(vd1);
1982          vars.addLast(vd2);
1983          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
1984          _bbtc._bodyData = md1;
1985          _bbtc._data = md1;
1986          
1987          te = new PositivePrefixIncrementExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")));
1988          vd = new VariableDeclaration (SourceInfo.NONE, _publicMav, new VariableDeclarator[] { new InitializedVariableDeclarator(SourceInfo.NONE, new PrimitiveType(SourceInfo.NONE, "int"), new Word(SourceInfo.NONE, "i"), new IntegerLiteral(SourceInfo.NONE, 10))});
1989          sel2 = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {te});
1990          fs = new ForStatement(SourceInfo.NONE, sel, te, sel2, new EmptyStatement(SourceInfo.NONE));
1991    
1992          fs.visit(_bbtc);
1993          assertEquals("There should be 1 error", 1, errors.size());
1994          assertEquals("The error message should be correct", "You cannot use an increment or decrement expression in the conditional expression of a for-statement at any language level", errors.get(0).getFirst());
1995          
1996          
1997        }
1998        
1999        public void testForWhileStatement() {
2000          //Test that a variable without a value before the while statement, that is given a value in the body of the while statement, still doesn't have a value afterwards
2001          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
2002            new IntegerLiteral(SourceInfo.NONE, 5));
2003    
2004    
2005          Statement assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));      
2006    
2007          Statement ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
2008          WhileStatement ws = new WhileStatement(SourceInfo.NONE, te, ts);
2009          
2010          VariableData vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
2011          VariableData vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
2012          
2013          MethodData md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
2014                                         new VariableData[] {vd1}, new String[0], _sd1, null);
2015          
2016          vd1.setEnclosingData(md1);
2017          vd2.setEnclosingData(md1);
2018    
2019          md1.addVar(vd1);
2020          md1.addVar(vd2);
2021          
2022          LinkedList<VariableData> vars = new LinkedList<VariableData>();
2023          vars.addLast(vd1);
2024          vars.addLast(vd2);
2025          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
2026          _bbtc._bodyData = md1;
2027          _bbtc._data = md1;
2028          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2029          
2030          
2031          ws.visit(_bbtc);
2032          assertTrue("vd1 should be assigned", vd1.hasValue());
2033          assertFalse("vd2 should not be assigned", vd2.hasValue());
2034    
2035          
2036          //Test that a variable with a value before the while statement, that is given a value in the body of the while statement, still has a value afterwards
2037          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
2038          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
2039          
2040          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
2041                                         new VariableData[] {vd1}, new String[0], _sd1, null);
2042          
2043          vd1.setEnclosingData(md1);
2044          vd2.setEnclosingData(md1);
2045    
2046          md1.addVar(vd1);
2047          md1.addVar(vd2);
2048          
2049          vars = new LinkedList<VariableData>();
2050          vars.addLast(vd1);
2051          vars.addLast(vd2);
2052          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
2053          _bbtc._bodyData = md1;
2054          _bbtc._data = md1;
2055          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2056          
2057          
2058          ws.visit(_bbtc);
2059          assertTrue("vd1 should be assigned", vd1.hasValue());
2060          assertTrue("vd2 should be assigned", vd2.hasValue());
2061    
2062         
2063          //Test that assignment is not allowed in the condition expression of the while
2064          te = new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 5));
2065          ws = new WhileStatement(SourceInfo.NONE, te, ts);
2066    
2067          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
2068          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
2069          
2070          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
2071                                         new VariableData[] {vd1}, new String[0], _sd1, null);
2072          
2073          vd1.setEnclosingData(md1);
2074          vd2.setEnclosingData(md1);
2075    
2076          md1.addVar(vd1);
2077          md1.addVar(vd2);
2078          
2079          vars = new LinkedList<VariableData>();
2080          vars.addLast(vd1);
2081          vars.addLast(vd2);
2082          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
2083          _bbtc._bodyData = md1;
2084          _bbtc._data = md1;
2085          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2086    
2087          
2088          ws.visit(_bbtc);
2089          assertEquals("There should be 1 error", 1, errors.size());
2090          assertEquals("The error message should be correct", "You cannot use an assignment expression in the condition expression of a while statement at any language level.  Perhaps you meant to compare two values with '=='", errors.get(0).getFirst());
2091          
2092          
2093    
2094        }
2095        
2096        public void testForWhileStatementOnly() {
2097          //Test that a boolean condition expression results in no error
2098          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
2099            new IntegerLiteral(SourceInfo.NONE, 5));
2100    
2101          
2102          Statement assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));      
2103    
2104          Statement ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
2105          WhileStatement ws = new WhileStatement(SourceInfo.NONE, te, ts);
2106          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2107    
2108          assertEquals("Should return null", null, _bbtc.forWhileStatementOnly(ws, SymbolData.BOOLEAN_TYPE.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()));
2109          assertEquals("There should be no errors", 0, errors.size());
2110    
2111          //Test that a non-boolean condition expression throws an error
2112          assertEquals("Should return null", null, _bbtc.forWhileStatementOnly(ws, SymbolData.INT_TYPE.getInstanceData(), SymbolData.DOUBLE_TYPE.getInstanceData()));
2113          assertEquals("There should be 1 error", 1, errors.size());
2114          assertEquals("Error message should be correct", "This while-statement's conditional expression must be a boolean value. Instead, its type is int", errors.get(0).getFirst());
2115     
2116          //Test "boolean" as a condition
2117          assertEquals("Should return null", null, _bbtc.forWhileStatementOnly(ws, SymbolData.BOOLEAN_TYPE, SymbolData.DOUBLE_TYPE.getInstanceData()));
2118          assertEquals("There should be 2 error", 2, errors.size());
2119          assertEquals("Error message should be correct", "This while-statement's conditional expression must be a boolean value. Instead, it is a class or interface name", errors.getLast().getFirst());
2120        }
2121        
2122        public void testForForStatementOnly() {
2123          
2124          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
2125            new IntegerLiteral(SourceInfo.NONE, 5));
2126    
2127          UnparenthesizedExpressionList sel = new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10))});
2128          ForStatement fs = new ForStatement(SourceInfo.NONE, sel, new NullLiteral(SourceInfo.NONE), new UnparenthesizedExpressionList(SourceInfo.NONE, new Expression[0]), new EmptyStatement(SourceInfo.NONE));
2129      
2130          
2131          //Test that a boolean condition results in no error
2132          assertEquals("Should return null", null, _bbtc.forForStatementOnly(fs, SymbolData.INT_TYPE, SymbolData.BOOLEAN_TYPE.getInstanceData(), SymbolData.INT_TYPE, SymbolData.INT_TYPE));
2133          assertEquals("There should be no errors", 0, errors.size());
2134          
2135                       
2136          //Test that a non-boolean condition expression throws an error             
2137          assertEquals("Should return null", null, _bbtc.forForStatementOnly(fs, SymbolData.INT_TYPE, SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.INT_TYPE, SymbolData.CHAR_TYPE));
2138          assertEquals("Should be 1 error", 1, errors.size());
2139          assertEquals("The error message should be correct", "This for-statement's conditional expression must be a boolean value. Instead, its type is double", errors.get(0).getFirst());
2140    
2141          //Test "boolean" as the condition             
2142          assertEquals("Should return null", null, _bbtc.forForStatementOnly(fs, SymbolData.INT_TYPE, SymbolData.BOOLEAN_TYPE, SymbolData.INT_TYPE, SymbolData.CHAR_TYPE));
2143          assertEquals("Should be 2 error", 2, errors.size());
2144          assertEquals("The error message should be correct", "This for-statement's conditional expression must be a boolean value. Instead, it is a class or interface name", errors.getLast().getFirst());
2145        }
2146        
2147        public void testForDoStatement() {
2148          //Test that a variable without a value before the do statement, that is given a value in the body of the while statement, still doesn't have a value afterwards
2149          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
2150            new IntegerLiteral(SourceInfo.NONE, 5));
2151    
2152    
2153          Statement assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));      
2154    
2155          Statement ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
2156          DoStatement ds = new DoStatement(SourceInfo.NONE, ts, te);
2157          
2158          VariableData vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
2159          VariableData vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, false, null);
2160          
2161          MethodData md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
2162                                         new VariableData[] {vd1}, new String[0], _sd1, null);
2163          
2164          vd1.setEnclosingData(md1);
2165          vd2.setEnclosingData(md1);
2166    
2167          md1.addVar(vd1);
2168          md1.addVar(vd2);
2169          
2170          LinkedList<VariableData> vars = new LinkedList<VariableData>();
2171          vars.addLast(vd1);
2172          vars.addLast(vd2);
2173          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
2174          _bbtc._bodyData = md1;
2175          _bbtc._data = md1;
2176          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2177          
2178          
2179          ds.visit(_bbtc);
2180          assertTrue("vd1 should be assigned", vd1.hasValue());
2181          assertFalse("vd2 should not be assigned", vd2.hasValue());
2182    
2183          
2184          //Test that a variable with a value before the do statement, that is given a value in the body of the do statement, still has a value afterwards
2185          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
2186          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
2187          
2188          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
2189                                         new VariableData[] {vd1}, new String[0], _sd1, null);
2190          
2191          vd1.setEnclosingData(md1);
2192          vd2.setEnclosingData(md1);
2193    
2194          md1.addVar(vd1);
2195          md1.addVar(vd2);
2196          
2197          vars = new LinkedList<VariableData>();
2198          vars.addLast(vd1);
2199          vars.addLast(vd2);
2200          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
2201          _bbtc._bodyData = md1;
2202          _bbtc._data = md1;
2203          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2204          
2205          
2206          ds.visit(_bbtc);
2207          assertTrue("vd1 should be assigned", vd1.hasValue());
2208          assertTrue("vd2 should be assigned", vd2.hasValue());
2209    
2210         
2211          //Test that assignment is not allowed in the condition expression of the do
2212          te = new PlusAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 5));
2213          ds = new DoStatement(SourceInfo.NONE, ts, te);
2214    
2215          vd1 = new VariableData("j", _packageMav, SymbolData.INT_TYPE, true, null);
2216          vd2 = new VariableData("i", _packageMav, SymbolData.INT_TYPE, true, null);
2217          
2218          md1 = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
2219                                         new VariableData[] {vd1}, new String[0], _sd1, null);
2220          
2221          vd1.setEnclosingData(md1);
2222          vd2.setEnclosingData(md1);
2223    
2224          md1.addVar(vd1);
2225          md1.addVar(vd2);
2226          
2227          vars = new LinkedList<VariableData>();
2228          vars.addLast(vd1);
2229          vars.addLast(vd2);
2230          _bbtc = new BodyTypeChecker(md1, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, vars, new LinkedList<Pair<SymbolData, JExpression>>());
2231          _bbtc._bodyData = md1;
2232          _bbtc._data = md1;
2233          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2234          
2235          
2236          ds.visit(_bbtc);
2237          assertEquals("There should be 1 error", 1, errors.size());
2238          assertEquals("The error message should be correct", "You cannot use an assignment expression in the condition expression of a do statement at any language level", errors.get(0).getFirst());
2239          
2240        }
2241        
2242        public void testForDoStatementOnly() {
2243          Expression te = new LessThanExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
2244            new IntegerLiteral(SourceInfo.NONE, 5));
2245    
2246          
2247          Statement assignStatement = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 10)));      
2248    
2249          Statement ts = new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {assignStatement}));
2250          DoStatement ds = new DoStatement(SourceInfo.NONE, ts, te);
2251          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
2252    
2253          //Test that a boolean condition results in no error
2254          assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), _bbtc.forDoStatementOnly(ds, SymbolData.INT_TYPE, SymbolData.BOOLEAN_TYPE.getInstanceData()));
2255          assertEquals("There should be no errors", 0, errors.size());
2256    
2257          //test that a non-boolean condition expression throws an error
2258          assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), _bbtc.forDoStatementOnly(ds, SymbolData.INT_TYPE, SymbolData.DOUBLE_TYPE.getInstanceData()));
2259          assertEquals("Should be 1 error", 1, errors.size());
2260          assertEquals("The error message should be correct", "This do-statement's conditional expression must be a boolean value. Instead, its type is double", errors.get(0).getFirst());
2261    
2262          //test "bool" as the condition
2263          assertEquals("Should return double", SymbolData.DOUBLE_TYPE.getInstanceData(), _bbtc.forDoStatementOnly(ds, SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.BOOLEAN_TYPE));
2264          assertEquals("Should be 2 errors", 2, errors.size());
2265          assertEquals("The error message should be correct", "This do-statement's conditional expression must be a boolean value. Instead, it is a class or interface name", errors.getLast().getFirst());
2266        }
2267        
2268    
2269       public void testForSwitchStatementOnly() {
2270         //if we did not see a default block, should return null
2271         SwitchStatement ss = new SwitchStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 1), new SwitchCase[0]);
2272         assertEquals("Should return null--no default block", null, _bbtc.forSwitchStatementOnly(ss, 
2273                                                                                                 SymbolData.CHAR_TYPE.getInstanceData(), 
2274                                                                                                 new TypeData[] {SymbolData.INT_TYPE}, 
2275                                                                                                 false));
2276         
2277         //if any of the blocks are NOT FOUND, should return null
2278         assertEquals("Should return null--has a not-found block", null, _bbtc.forSwitchStatementOnly(ss, 
2279                                                                                                 SymbolData.CHAR_TYPE.getInstanceData(), 
2280                                                                                                 new TypeData[] {SymbolData.NOT_FOUND, SymbolData.INT_TYPE}, 
2281                                                                                                 true));
2282         
2283         assertEquals("Should return null--has a not-found block", null, _bbtc.forSwitchStatementOnly(ss, 
2284                                                                                                 SymbolData.CHAR_TYPE.getInstanceData(), 
2285                                                                                                 new TypeData[] {SymbolData.INT_TYPE, SymbolData.NOT_FOUND}, 
2286                                                                                                 true));
2287                      
2288         
2289         //if last block does not return, statement does not return
2290         assertEquals("Should return null--last block is null", null, _bbtc.forSwitchStatementOnly(ss, 
2291                                                                                                 SymbolData.CHAR_TYPE.getInstanceData(), 
2292                                                                                                 new TypeData[] {SymbolData.INT_TYPE, SymbolData.CHAR_TYPE, null}, 
2293                                                                                                 true));
2294                                                                                                 
2295         
2296         //if all 3 conditions are false, statement does return
2297         assertEquals("Should NOT return null", SymbolData.INT_TYPE.getInstanceData(), _bbtc.forSwitchStatementOnly(ss, 
2298                                                                                                 SymbolData.CHAR_TYPE.getInstanceData(), 
2299                                                                                                 new TypeData[] {SymbolData.INT_TYPE, SymbolData.CHAR_TYPE, null, SymbolData.CHAR_TYPE}, 
2300                                                                                                 true));
2301                                                                                                 
2302        }
2303     
2304        public void testForSwitchStatement() {
2305          _bbtc._vars.addLast(new VariableData("dan", _publicMav, SymbolData.INT_TYPE, true, _bbtc._bodyData));
2306          
2307          //assignment in switch expression should throw error
2308          SwitchStatement ss = new SwitchStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new IntegerLiteral(SourceInfo.NONE, 5)), new SwitchCase[0]);
2309          assertEquals("Should return null", null, ss.visit(_bbtc));
2310          assertEquals("Should be 1 error", 1, errors.size());
2311          assertEquals("Error message should be correct", "You cannot use an assignment expression in the switch expression of a switch statement at any language level.  Perhaps you meant to compare two values with '=='", errors.getLast().getFirst());
2312          
2313          //non int or char value in switch expression
2314          ss = new SwitchStatement(SourceInfo.NONE, new DoubleLiteral(SourceInfo.NONE, 4.2), new SwitchCase[0]);
2315          assertEquals("Should return null", null, ss.visit(_bbtc));
2316          assertEquals("Should be 2 error", 2, errors.size());
2317          assertEquals("Error message should be correct", "The switch expression must be either an int or a char.  You have used a double", errors.getLast().getFirst());
2318    
2319          //two switch cases with the same label
2320          UnbracedBody emptyBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[0]);
2321    
2322          LabeledCase l1 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), emptyBody);
2323          LabeledCase l2 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), emptyBody);
2324          LabeledCase l3 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 7), emptyBody);
2325    
2326          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {l1, l2, l3});
2327          assertEquals("Should return null", null, ss.visit(_bbtc));
2328          assertEquals("Should be 3 errors", 3, errors.size());
2329          assertEquals("Error message should be correct", "You cannot have two switch cases with the same label 5", errors.getLast().getFirst());
2330          
2331          //two default cases
2332          DefaultCase dc1 = new DefaultCase(SourceInfo.NONE, emptyBody);
2333          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {dc1, dc1});
2334          assertEquals("Should return null", null, ss.visit(_bbtc));
2335          assertEquals("Should be 4 errors", 4, errors.size());
2336          assertEquals("Error message should be correct", "A switch statement can only have one default case", errors.getLast().getFirst());
2337    
2338          //x is assigned
2339          VariableData xData = new VariableData("x", _publicMav, SymbolData.INT_TYPE, false, _bbtc._bodyData);
2340          _bbtc._vars.addLast(xData);
2341    
2342          ExpressionStatement assignX = new ExpressionStatement(SourceInfo.NONE, new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "x")), new IntegerLiteral(SourceInfo.NONE, 5)));
2343          UnbracedBody returnBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {assignX, new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5))});
2344          UnbracedBody breakBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {assignX, new UnlabeledBreakStatement(SourceInfo.NONE)});
2345          UnbracedBody breakNoAssignBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new UnlabeledBreakStatement(SourceInfo.NONE)});
2346          UnbracedBody fallThroughBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {assignX});
2347          UnbracedBody fallThroughNoAssignBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[0]);
2348          
2349          SwitchCase c1 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), returnBody);
2350          SwitchCase c2 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 6), breakBody);
2351          SwitchCase c3 = new DefaultCase(SourceInfo.NONE, breakBody);
2352          
2353          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {c1, c2, c3});
2354          
2355          assertEquals("Should return null", null, ss.visit(_bbtc));
2356          assertEquals("Should still be 4 errors", 4, errors.size());
2357          assertTrue("x has been assigned", xData.hasValue());
2358          
2359          //x is assigned -- the first block falls through
2360          xData.lostValue();
2361          
2362          c1 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), fallThroughNoAssignBody);
2363          c2 = new DefaultCase(SourceInfo.NONE, breakBody);
2364          c3 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 6), breakBody);
2365          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {c1, c2, c3});
2366         
2367          assertEquals("Should return null", null, ss.visit(_bbtc));
2368          assertEquals("Should still be 4 errors", 4, errors.size());
2369          assertTrue("x has been assigned", xData.hasValue());
2370          
2371          //x is not assigned -- the second block does not fall through
2372          xData.lostValue();
2373          
2374          c1 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), fallThroughNoAssignBody);
2375          c2 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 6), breakNoAssignBody);
2376          c3 = new DefaultCase(SourceInfo.NONE, breakBody);
2377          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {c1, c2, c3});
2378         
2379          assertEquals("Should return null", null, ss.visit(_bbtc));
2380          assertEquals("Should still be 4 errors", 4, errors.size());
2381          assertFalse("x has not been assigned", xData.hasValue());
2382          
2383          //x is not assigned -- there is no default case
2384          xData.lostValue();
2385          
2386          c1 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), fallThroughNoAssignBody);
2387          c2 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 6), fallThroughNoAssignBody);
2388          c3 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 7), breakBody);
2389          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {c1, c2, c3});
2390         
2391          assertEquals("Should return null", null, ss.visit(_bbtc));
2392          assertEquals("Should still be 4 errors", 4, errors.size());
2393          assertFalse("x has not been assigned", xData.hasValue());
2394          
2395          //x is assigned -- the last case is always executed--but an error is added, because it falls through.
2396          xData.lostValue();
2397          
2398          c1 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), fallThroughNoAssignBody);
2399          c2 = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 6), fallThroughNoAssignBody);
2400          c3 = new DefaultCase(SourceInfo.NONE, fallThroughBody);
2401          ss = new SwitchStatement(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), new SwitchCase[] {c1, c2, c3});
2402         
2403          assertEquals("Should return null", null, ss.visit(_bbtc));
2404          assertEquals("Should be 5 errors", 5, errors.size());
2405          assertEquals("The error message should be correct", "You must end a non-empty switch case with a break or return statement at the Advanced level", errors.getLast().getFirst());
2406          assertTrue("x has been assigned", xData.hasValue());
2407          
2408        }
2409        
2410        public void testForLabeledCase() {
2411          symbolTable.put("java.lang.String", new SymbolData("java.lang.String"));
2412          UnbracedBody emptyBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[0]);
2413          //Test a label that is okay
2414          LabeledCase lc = new LabeledCase(SourceInfo.NONE, new CharLiteral(SourceInfo.NONE, 'e'), emptyBody);
2415          assertEquals("Should return null", null, lc.visit(_bbtc));
2416          assertEquals("There should be no errors", 0, errors.size());
2417    
2418          lc = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 27), emptyBody);
2419          assertEquals("Should return null", null, lc.visit(_bbtc));
2420          assertEquals("There should be no errors", 0, errors.size());
2421          
2422          //Test that a braced body that returns something is handled correctly
2423          UnbracedBody nonEmptyBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5))});
2424          lc = new LabeledCase(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 27), nonEmptyBody);
2425          TypeData result = lc.visit(_bbtc);
2426          assertEquals("There should be no errors", 0, errors.size());
2427          assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), result);
2428          assertEquals("There should be no errors", 0, errors.size());
2429          
2430          
2431          //Test some that are not:
2432          
2433          //label that is a more complex expression: length greater than 1
2434          lc = new LabeledCase(SourceInfo.NONE, new PlusExpression(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5), new IntegerLiteral(SourceInfo.NONE, 42)), emptyBody);
2435          assertEquals("Should return null", null, lc.visit(_bbtc));
2436          assertEquals("There should be 1 error", 1, errors.size());
2437          assertEquals("The error message should be correct", "The labels of a switch statement must be constants.  You are using a more complicated expression of type int", errors.getLast().getFirst());
2438    
2439          //label that is a more complex expression: something other than a literal of length 1
2440          _bbtc._vars.addLast(new VariableData("dan", _publicMav, SymbolData.INT_TYPE, true, _bbtc._bodyData));
2441          lc = new LabeledCase(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "dan")), emptyBody);
2442          assertEquals("Should return null", null, lc.visit(_bbtc));
2443          assertEquals("There should now be 2 errors", 2, errors.size());
2444          assertEquals("The error message should be correct", "The labels of a switch statement must be constants.  You are using a more complicated expression of type int", errors.getLast().getFirst());
2445                             
2446          //and a literal whose type is not int or char
2447          lc = new LabeledCase(SourceInfo.NONE, new StringLiteral(SourceInfo.NONE, "hi!"), emptyBody);
2448          assertEquals("Should return null", null, lc.visit(_bbtc));
2449          assertEquals("There should now be 3 errors", 3, errors.size());
2450          assertEquals("The error message should be correct", "The labels of a switch statement must be constants of int or char type.  You specified a constant of type java.lang.String", errors.getLast().getFirst());
2451    
2452        }
2453        
2454        public void testForDefaultCase() {
2455          UnbracedBody emptyBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[0]);
2456          UnbracedBody returnBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5))});
2457          UnbracedBody breakBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new UnlabeledBreakStatement(SourceInfo.NONE)});
2458          
2459          //an empty body
2460          DefaultCase dc = new DefaultCase(SourceInfo.NONE, emptyBody);
2461          assertEquals("Should return null", null, dc.visit(_bbtc));
2462          assertEquals("There should be no errors", 0, errors.size());
2463    
2464          //a body with a return statement
2465          dc = new DefaultCase(SourceInfo.NONE, returnBody);
2466          assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), dc.visit(_bbtc));
2467          assertEquals("There should be no errors", 0, errors.size());
2468           
2469          //a body with a break
2470          dc = new DefaultCase(SourceInfo.NONE, breakBody);
2471          assertEquals("Should return NOT_FOUND", SymbolData.NOT_FOUND, dc.visit(_bbtc));
2472          assertEquals("There should be no errors", 0, errors.size());
2473        }
2474        
2475        public void testForSwitchCase() {
2476          UnbracedBody emptyBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[0]);
2477          UnbracedBody returnBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5))});
2478          UnbracedBody breakBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new UnlabeledBreakStatement(SourceInfo.NONE)});
2479          UnbracedBody nonEmptyBody = new UnbracedBody(SourceInfo.NONE, new BodyItemI[] {new EmptyStatement(SourceInfo.NONE)});
2480         
2481          //empty body
2482          DefaultCase dc = new DefaultCase(SourceInfo.NONE, emptyBody);
2483          assertEquals("Should return null", null, _bbtc.forSwitchCase(dc));
2484          assertEquals("There should be no errors", 0, errors.size());
2485    
2486          //return body
2487          dc = new DefaultCase(SourceInfo.NONE, returnBody);
2488          assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), _bbtc.forSwitchCase(dc));
2489          assertEquals("There should be no errors", 0, errors.size());
2490           
2491          //break body
2492          dc = new DefaultCase(SourceInfo.NONE, breakBody);
2493          assertEquals("Should return NOT_FOUND", SymbolData.NOT_FOUND, _bbtc.forSwitchCase(dc));
2494          assertEquals("There should be no errors", 0, errors.size());
2495          
2496          //non-empty body that does not return: fall-through
2497          dc = new DefaultCase(SourceInfo.NONE, nonEmptyBody);
2498          assertEquals("Should return null", null, _bbtc.forSwitchCase(dc));
2499          assertEquals("There should be one error", 1, errors.size());
2500          assertEquals("The error message should be correct", "You must end a non-empty switch case with a break or return statement at the Advanced level", errors.getLast().getFirst());
2501    
2502        }
2503    
2504        public void testCreateANewInstanceOfMe() {
2505          //make sure that the correct type of visitor is returned
2506          BodyTypeChecker btc = _bbtc.createANewInstanceOfMe(_bbtc._bodyData, _bbtc._file, _bbtc._package, _bbtc._importedFiles, _bbtc._importedPackages, _bbtc._vars, _bbtc._thrown);
2507          assertTrue("Should be an instance of BodyTypeChecker", btc instanceof BodyTypeChecker);
2508          assertFalse("Should not be an instance of ConstructorBodyTypeChecker", btc instanceof ConstructorBodyTypeChecker);
2509    
2510        }
2511        
2512        public void testCheckDuplicateExceptions() {
2513          BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
2514          Block b = new Block(SourceInfo.NONE, emptyBody);
2515    
2516          NormalTryCatchStatement ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[0]);
2517          TryCatchFinallyStatement tcfs = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], b);
2518          _bbtc.checkDuplicateExceptions(ntcs);
2519          _bbtc.checkDuplicateExceptions(tcfs);
2520          assertEquals("Should be no errors", 0, errors.size());
2521          
2522          UninitializedVariableDeclarator uvd1 = 
2523            new UninitializedVariableDeclarator(SourceInfo.NONE, 
2524                                                new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Exception", new Type[0]), 
2525                                                new Word(SourceInfo.NONE, "e"));
2526          UninitializedVariableDeclarator uvd2 = 
2527            new UninitializedVariableDeclarator(SourceInfo.NONE, 
2528                                                new ClassOrInterfaceType(SourceInfo.NONE, "RuntimeException", new Type[0]), 
2529                                                new Word(SourceInfo.NONE, "e"));
2530          UninitializedVariableDeclarator uvd3 =
2531            new UninitializedVariableDeclarator(SourceInfo.NONE, 
2532                                                new ClassOrInterfaceType(SourceInfo.NONE, "IOException", new Type[0]), 
2533                                                new Word(SourceInfo.NONE, "e"));
2534    
2535          FormalParameter fp1 = new FormalParameter(SourceInfo.NONE, uvd1, false);
2536          FormalParameter fp2 = new FormalParameter(SourceInfo.NONE, uvd2, false);
2537          FormalParameter fp3 = new FormalParameter(SourceInfo.NONE, uvd3, false);
2538          
2539          LanguageLevelVisitor llv = 
2540            new LanguageLevelVisitor(new File(""), 
2541                                     "", 
2542                                     null, // enclosingClassName for top level traversal
2543                                     new LinkedList<String>(), 
2544                                     new LinkedList<String>(), 
2545                                     new HashSet<String>(), 
2546                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
2547                                     new LinkedList<Command>());
2548          
2549          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
2550          llv._errorAdded=false;
2551    //      LanguageLevelConverter.symbolTable = llv.symbolTable = new Symboltable();
2552          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
2553          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
2554    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
2555          llv._classesInThisFile = new HashSet<String>();
2556    
2557          llv._importedFiles.addLast("java.io.IOException");
2558          SymbolData e = llv.getQualifiedSymbolData("java.lang.Exception", SourceInfo.NONE);
2559          SymbolData re = llv.getQualifiedSymbolData("java.lang.RuntimeException", SourceInfo.NONE);
2560          SymbolData ioe = llv.getQualifiedSymbolData("java.io.IOException", SourceInfo.NONE);
2561          
2562          assert symbolTable.containsKey("java.lang.Exception");
2563          assert symbolTable.containsKey("java.lang.RuntimeException");
2564          assert symbolTable.containsKey("java.io.IOException");
2565          assert symbolTable.contains(e);
2566          assert symbolTable.contains(re);
2567          assert symbolTable.contains(ioe);
2568          
2569          CatchBlock c1 = new CatchBlock(SourceInfo.NONE, fp1, b);
2570          CatchBlock c2 = new CatchBlock(SourceInfo.NONE, fp2, b);
2571          CatchBlock c3 = new CatchBlock(SourceInfo.NONE, fp3, b);
2572          _bbtc._importedFiles.addLast("java.io.IOException");
2573          
2574          // Just one exception, no error
2575          ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[] {c1});
2576          _bbtc.checkDuplicateExceptions(ntcs);
2577          assertEquals("Should be no errors", 0, errors.size());
2578          
2579          // Second exception is subclass of 1st exception: should throw error
2580          ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[]{c1, c2});
2581          _bbtc.checkDuplicateExceptions(ntcs);
2582    //      System.out.println("First error is: " + errors.get(0));
2583          assertEquals("Should be one error", 1, errors.size());
2584          assertEquals("Error message should be correct", "Exception java.lang.RuntimeException has already been caught", errors.get(0).getFirst());
2585    
2586          // Two exceptions, unrelated.  no error
2587          ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[]{c2, c3});
2588          _bbtc.checkDuplicateExceptions(ntcs);
2589          assertEquals("Should still be one error", 1, errors.size());
2590          
2591          // 2nd and 3rd exceptions subclasses of 1st exception: should throw 2 errors, but one is a duplicate 
2592          ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[]{c1, c2, c3});
2593          _bbtc.checkDuplicateExceptions(ntcs);
2594    
2595          assertEquals("Should be two errors", 2, errors.size());
2596          assertEquals("2nd Error message should be correct", "Exception java.lang.RuntimeException has already been caught", errors.get(0).getFirst());
2597          assertEquals("3rd Error message should be correct", "Exception java.io.IOException has already been caught", errors.get(1).getFirst());
2598          
2599          // 1st exception subclass of 2nd exception: should be no error
2600          ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[]{c2, c1});
2601          _bbtc.checkDuplicateExceptions(ntcs);
2602          assertEquals("Should still be two errors", 2, errors.size());
2603        }
2604        
2605        public void testTryCatchLeastRestrictiveType() {
2606    
2607          InstanceData[] sdArray = new InstanceData[] {SymbolData.BYTE_TYPE.getInstanceData(), SymbolData.INT_TYPE.getInstanceData(), SymbolData.SHORT_TYPE.getInstanceData()};
2608          assertEquals("Should return long type", SymbolData.LONG_TYPE.getInstanceData(), _bbtc.tryCatchLeastRestrictiveType(SymbolData.LONG_TYPE.getInstanceData(), sdArray, null));
2609          assertEquals("Should return Object", "java.lang.Object", _bbtc.tryCatchLeastRestrictiveType(SymbolData.SHORT_TYPE.getInstanceData(), sdArray, SymbolData.BOOLEAN_TYPE.getInstanceData()).getName());
2610          assertEquals("Should return double type", SymbolData.DOUBLE_TYPE.getInstanceData(), _bbtc.tryCatchLeastRestrictiveType(SymbolData.SHORT_TYPE.getInstanceData(), sdArray, SymbolData.DOUBLE_TYPE.getInstanceData()));
2611          assertEquals("Should return null", null, _bbtc.tryCatchLeastRestrictiveType(null, sdArray, null));
2612          assertEquals("Should return int type", SymbolData.INT_TYPE.getInstanceData(), _bbtc.tryCatchLeastRestrictiveType(SymbolData.SHORT_TYPE.getInstanceData(), sdArray, null));
2613          assertEquals("Should return long type", SymbolData.LONG_TYPE.getInstanceData(), _bbtc.tryCatchLeastRestrictiveType(null, sdArray, SymbolData.LONG_TYPE.getInstanceData()));
2614          
2615          sdArray = new InstanceData[] {null, SymbolData.INT_TYPE.getInstanceData()};
2616          assertEquals("Should return null", null, _bbtc.tryCatchLeastRestrictiveType(SymbolData.INT_TYPE.getInstanceData(), sdArray, null));
2617          assertEquals("Should return short", SymbolData.SHORT_TYPE.getInstanceData(), _bbtc.tryCatchLeastRestrictiveType(SymbolData.INT_TYPE.getInstanceData(), sdArray, SymbolData.SHORT_TYPE.getInstanceData()));
2618          
2619          SymbolData sd = new SymbolData("java.lang.Object");
2620          SymbolData sd2 = new SymbolData("java.lang.String");
2621    //      sd.setIsContinuation(false);
2622    //      sd2.setIsContinuation(false);
2623    //      symbolTable.put("java.lang.Object", sd);
2624    //      symbolTable.put("java.lang.String", sd2);
2625          sd2.setSuperClass(sd);
2626          
2627          assertEquals("Should return Object", sd.getInstanceData(), _bbtc.tryCatchLeastRestrictiveType(sd2.getInstanceData(), new InstanceData[]{sd.getInstanceData(), sd2.getInstanceData()}, null));
2628        }
2629        
2630        public void testHandleMethodInvocation() {
2631          //handleMethodInvocation(MethodData md, JExpression jexpr) 
2632          MethodData md = new MethodData("Fun", _publicMav, new TypeParameter[0], _sd1, 
2633                                         new VariableData[0], 
2634                                         new String[0], 
2635                                         _sd1,
2636                                         null);
2637          
2638          MethodData md2 = new MethodData("InTheSun", _publicMav, new TypeParameter[0], _sd1,
2639                                          new VariableData[0],
2640                                          new String[] {"java.lang.RuntimeException", "java.io.IOException"},
2641                                          _sd1,
2642                                          null);
2643                                          
2644          NullLiteral nl = new NullLiteral(SourceInfo.NONE);
2645    
2646          _bbtc._importedFiles.addLast("java.io.IOException");
2647          // TODO: create LL constructor specifically for testing that only takes file name.
2648          LanguageLevelVisitor llv = 
2649            new LanguageLevelVisitor(new File(""), "", 
2650                                     null /* enclosingClassName */, 
2651                                     new LinkedList<String>(), 
2652                                     new LinkedList<String>(), 
2653                                     new HashSet<String>(), 
2654                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
2655                                     new LinkedList<Command>());
2656          
2657          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
2658          llv._errorAdded = false;
2659    //      LanguageLevelConverter.symbolTable.clear();  // done in setUp()
2660          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
2661          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
2662    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
2663          llv._classesInThisFile = new HashSet<String>();
2664    
2665          llv._importedFiles.addLast("java.io.IOException");
2666    
2667    
2668          SymbolData re = llv.getSymbolData("java.lang.RuntimeException", SourceInfo.NONE, true);
2669          SymbolData ioe = llv.getSymbolData("java.io.IOException", SourceInfo.NONE, true);
2670          
2671          assert symbolTable.containsKey("java.lang.RuntimeException");
2672          assert symbolTable.containsKey("java.io.IOException");
2673          assert symbolTable.contains(re);
2674          assert symbolTable.contains(ioe);
2675    //      symbolTable.put("java.lang.RuntimeException", re);
2676    //      symbolTable.put("java.io.IOException", ioe);
2677    
2678          
2679          _bbtc.handleMethodInvocation(md, nl);
2680          assertEquals("There should be no exceptions in _thrown", 0, _bbtc._thrown.size());
2681          
2682          _bbtc.handleMethodInvocation(md2, nl);
2683          assertEquals("There should be 2 exceptions in _thrown", 2, _bbtc._thrown.size());
2684          assertEquals("The first exception should be java.lang.RuntimeException", re, _bbtc._thrown.get(0).getFirst());
2685          assertEquals("The second exception should be java.lang.IOException", ioe, _bbtc._thrown.get(1).getFirst());
2686        }
2687        
2688        public void testForThrowStatement() {
2689          LanguageLevelVisitor llv = 
2690            new LanguageLevelVisitor(new File(""), 
2691                                     "", 
2692                                     null, // enclosingClassName for top level traversal
2693                                     new LinkedList<String>(), 
2694                                     new LinkedList<String>(), 
2695                                     new HashSet<String>(), 
2696                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
2697                                     new LinkedList<Command>());
2698          
2699          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
2700          llv._errorAdded=false;
2701    //      LanguageLevelConverter.symbolTable = llv.symbolTable = new Symboltable();
2702          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
2703          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
2704    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
2705          llv._classesInThisFile = new HashSet<String>();
2706    
2707          SymbolData re = llv.getSymbolData("java.lang.RuntimeException", SourceInfo.NONE, true);
2708          assert symbolTable.containsKey("java.lang.RuntimeException");
2709          assert symbolTable.contains(re);
2710          
2711    //      symbolTable.put("java.lang.RuntimeException", re);
2712          
2713          VariableData vd = new VariableData("myException", _publicMav, re, true, _bbtc._bodyData);
2714          _bbtc._vars.addLast(vd);
2715          Expression e = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "myException"));
2716          ThrowStatement ts = new ThrowStatement(SourceInfo.NONE, e);
2717          
2718          assertEquals("Should return EXCEPTION", SymbolData.EXCEPTION.getInstanceData(), ts.visit(_bbtc));
2719          
2720          assertEquals("There should be 1 exception in _thrown", 1, _bbtc._thrown.size());
2721          assertEquals("The exception should be java.lang.RuntimeException", re, _bbtc._thrown.get(0).getFirst());
2722    
2723        }
2724        
2725        public void testMakeSureCaughtStuffWasThrown() {
2726          //TryCatchStatement that, SymbolData[] caught_array, LinkedList<Pair<SymbolData, JExpression>> thrown) {
2727          BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
2728          Block b = new Block(SourceInfo.NONE, emptyBody);
2729    
2730          PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
2731          UninitializedVariableDeclarator uvd = new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
2732          FormalParameter param = new FormalParameter(SourceInfo.NONE, new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "j")), false);
2733    
2734          NormalTryCatchStatement ntcs =
2735            new NormalTryCatchStatement(SourceInfo.NONE, b,
2736                                        new CatchBlock[] {new CatchBlock(SourceInfo.NONE,  param, b)});
2737          SymbolData javaLangThrowable =  _bbtc.getSymbolData("java.lang.Throwable", ntcs, false, true); 
2738                                         // new SymbolData("java.lang.Throwable");
2739          _bbtc.symbolTable.put("java.lang.Throwable", javaLangThrowable);
2740          SymbolData exception = new SymbolData("my.crazy.exception");
2741          exception.setSuperClass(javaLangThrowable);
2742          SymbolData exception2 = new SymbolData("A&M.beat.Rice.in.BaseballException");
2743          exception2.setSuperClass(javaLangThrowable);
2744          SymbolData exception3 = new SymbolData("aegilha");
2745          exception3.setSuperClass(javaLangThrowable);
2746          LinkedList<Pair<SymbolData, JExpression>> thrown = new LinkedList<Pair<SymbolData, JExpression>>();
2747    
2748          
2749          _bbtc.makeSureCaughtStuffWasThrown(ntcs, new SymbolData[0], thrown);
2750          assertEquals("There should be no errors", 0, errors.size());
2751          
2752          Pair<SymbolData, JExpression> p = new Pair<SymbolData, JExpression>(exception, ntcs);
2753          thrown.addLast(p);
2754          _bbtc.makeSureCaughtStuffWasThrown(ntcs, new SymbolData[]{exception}, thrown);
2755          assertEquals("There should still be no errors", 0, errors.size());
2756          
2757          thrown.remove(p);
2758          
2759          _bbtc.makeSureCaughtStuffWasThrown(ntcs, new SymbolData[] {exception2}, thrown);
2760    //      System.err.println("thrown = " + thrown);
2761    //      System.err.println("errors = " + errors);
2762          assertEquals("There should be one error", 1, errors.size());
2763          assertEquals("The error message should be correct", "The exception A&M.beat.Rice.in.BaseballException is never thrown in the body of the corresponding try block", errors.get(0).getFirst());
2764        }
2765        
2766        public void testIsCheckedException() {
2767          SymbolData th = new SymbolData("java.lang.Throwable");
2768          th.setIsContinuation(false);
2769          SymbolData r = new SymbolData("java.lang.Error");
2770          r.setIsContinuation(false);
2771          r.setSuperClass(th);
2772          SymbolData ex = new SymbolData("java.lang.Exception");
2773          ex.setIsContinuation(false);
2774          ex.setSuperClass(th);
2775          SymbolData re = new SymbolData("java.lang.RuntimeException");
2776          re.setIsContinuation(false);
2777          re.setSuperClass(ex);
2778          symbolTable.put("java.lang.Throwable", th);
2779          symbolTable.put("java.lang.RuntimeException", re);
2780          symbolTable.put("java.lang.Error", r);
2781          symbolTable.put("java.lang.Exception", ex);
2782          SymbolData e1 = new SymbolData("exception1");
2783          e1.setSuperClass(ex);
2784          SymbolData e2 = new SymbolData("exception2");
2785          e2.setSuperClass(re);
2786          SymbolData e3 = new SymbolData("exception3");
2787          e3.setSuperClass(r);
2788          
2789          NullLiteral nl = new NullLiteral(SourceInfo.NONE);
2790          
2791          assertTrue("Does not subclass RuntimeException or Error", _bbtc.isCheckedException(e1, nl));
2792          assertFalse("Subclasses java.lang.RuntimeException", _bbtc.isCheckedException(e2, nl));
2793          assertFalse("Subclasses java.lang.Error", _bbtc.isCheckedException(e3, nl));
2794          
2795        }
2796        
2797        public void testIsUncheckedException() {
2798          //Check that extending RuntimeException or Error works as expected
2799          SymbolData th = new SymbolData("java.lang.Throwable");
2800          th.setIsContinuation(false);
2801          SymbolData r = new SymbolData("java.lang.Error");
2802          r.setIsContinuation(false);
2803          r.setSuperClass(th);
2804          SymbolData ex = new SymbolData("java.lang.Exception");
2805          ex.setIsContinuation(false);
2806          ex.setSuperClass(th);
2807          SymbolData re = new SymbolData("java.lang.RuntimeException");
2808          re.setIsContinuation(false);
2809          re.setSuperClass(ex);
2810          symbolTable.put("java.lang.Throwable", th);
2811          symbolTable.put("java.lang.RuntimeException", re);
2812          symbolTable.put("java.lang.Error", r);
2813          symbolTable.put("java.lang.Exception", ex);
2814    
2815          SymbolData e1 = new SymbolData("exception1");
2816          e1.setIsContinuation(false);
2817          e1.setSuperClass(ex);
2818          symbolTable.put("exception1", e1);
2819          SymbolData e2 = new SymbolData("exception2");
2820          e2.setSuperClass(re);
2821          SymbolData e3 = new SymbolData("exception3");
2822          e3.setSuperClass(r);
2823          SymbolData e4 = new SymbolData("exception4");
2824          e4.setSuperClass(e1);
2825          
2826          NullLiteral nl = new NullLiteral(SourceInfo.NONE);
2827          
2828          assertTrue("Does not subclass RuntimeException or Error or anything in the method data", _bbtc.isUncaughtCheckedException(e1, nl));
2829          assertFalse("Subclasses java.lang.RuntimeException", _bbtc.isUncaughtCheckedException(e2, nl));
2830          assertFalse("Subclasses java.lang.Error", _bbtc.isUncaughtCheckedException(e3, nl));
2831          
2832          //What if you throw something the method data announces that it throws?
2833          _bbtc._bodyData.getMethodData().setThrown(new String[] {"exception1"});
2834          assertFalse("Is in method data", _bbtc.isUncaughtCheckedException(e1, nl));
2835          
2836          assertFalse("Superclass is in method data", _bbtc.isUncaughtCheckedException(e4, nl));
2837          
2838          
2839        }
2840        
2841        public void testHandleUncheckedException() {
2842          JExpression j = new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myMethod"), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i"))}));
2843          
2844          _bbtc.handleUncheckedException(new SymbolData("i.have.a.shoe"), j);
2845          assertEquals("There should be one error", 1, errors.size());
2846          assertEquals("The error message should be correct", "The method myMethod is declared to throw the exception i.have.a.shoe which needs to be caught or declared to be thrown", errors.get(0).getFirst()); 
2847          Expression e = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "myException"));
2848          j = new ThrowStatement(SourceInfo.NONE, e);
2849          _bbtc.handleUncheckedException(new SymbolData("you.have.a.pot"), j);
2850          assertEquals("There should be two errors", 2, errors.size());
2851          assertEquals("The error message should be correct", "This statement throws the exception you.have.a.pot which needs to be caught or declared to be thrown", errors.get(1).getFirst());
2852    
2853        }
2854        
2855        public void testCompareThrownAndCaught() {
2856          
2857          JExpression j = 
2858            new SimpleMethodInvocation(SourceInfo.NONE, 
2859                                       new Word(SourceInfo.NONE, "myMethod"), 
2860                                       new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i"))}));
2861          
2862          BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
2863          Block b = new Block(SourceInfo.NONE, emptyBody);
2864    
2865          PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
2866          UninitializedVariableDeclarator uvd = 
2867            new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
2868          FormalParameter param = 
2869            new FormalParameter(SourceInfo.NONE, 
2870                                new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "j")), false);
2871    
2872          NormalTryCatchStatement ntcs = 
2873            new NormalTryCatchStatement(SourceInfo.NONE, 
2874                                        b, 
2875                                        new CatchBlock[] {new CatchBlock(SourceInfo.NONE,  param, b)});
2876    
2877          SymbolData javaLangThrowable =  _bbtc.getSymbolData("java.lang.Throwable", ntcs, false, true);
2878    //      System.err.println("**** In symbol table, java.lang.Throwable = " + symbolTable.get("java.lang.Throwable"));
2879          assertEquals("There should be no errors", 0, errors.size());
2880          javaLangThrowable.setPackage("java.lang");  // Don't know why it is not properly set already
2881          _bbtc.symbolTable.put("java.lang.Throwable", javaLangThrowable);
2882     
2883    //      System.err.println("***Name for java.lang.Throwable = " + javaLangThrowable.getName());
2884    //      System.err.println("***notRightPackage for java.lang.Throwable = " + _bbtc.notRightPackage(javaLangThrowable));
2885    //      System.err.println("***Package for java.lang.Throwable = " + javaLangThrowable.getPackage());
2886                            
2887          SymbolData exception = new SymbolData("my.crazy.exception");
2888          exception.setSuperClass(javaLangThrowable);
2889          SymbolData exception2 = new SymbolData("A&M.beat.Rice.in.BaseballException");
2890          exception2.setSuperClass(javaLangThrowable);
2891          SymbolData exception3 = new SymbolData("aegilha");
2892          exception3.setSuperClass(exception2);
2893          SymbolData[] caught_array = new SymbolData[] { exception, exception2 };
2894          LinkedList<Pair<SymbolData, JExpression>> thrown = new LinkedList<Pair<SymbolData, JExpression>>();
2895          thrown.addLast(new Pair<SymbolData, JExpression>(exception, j));
2896          thrown.addLast(new Pair<SymbolData, JExpression>(exception2, ntcs));
2897          thrown.addLast(new Pair<SymbolData, JExpression>(exception3, ntcs));
2898          
2899          assertEquals("There should be no errors", 0, errors.size());
2900          _bbtc.compareThrownAndCaught(ntcs, caught_array, thrown);
2901          for (int i = 0; i < errors.size(); i++) 
2902    //        System.err.println("Error " + i + ":\n" + errors.get(i).getFirst());
2903          assertEquals("There should be no errors", 0, errors.size());
2904          
2905          _bbtc.compareThrownAndCaught(ntcs, new SymbolData[] {exception2}, thrown);
2906          assertEquals("There should be one error", 1, errors.size());
2907          assertEquals("The error message should be correct", "The method myMethod is declared to throw the exception my.crazy.exception which needs to be caught or declared to be thrown", errors.get(0).getFirst());
2908    
2909        }
2910        
2911        public void testForBracedBody() {
2912          LanguageLevelVisitor llv = 
2913            new LanguageLevelVisitor(new File(""), 
2914                                     "",
2915                                     null, // enclosingClassName for top level traversal
2916                                     new LinkedList<String>(), 
2917                                     new LinkedList<String>(), 
2918                                     new HashSet<String>(), 
2919                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
2920                                     new LinkedList<Command>());
2921          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
2922          llv._errorAdded=false;
2923    //      LanguageLevelConverter.symbolTable = llv.symbolTable = new Symboltable();
2924          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
2925          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
2926    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
2927          llv._classesInThisFile = new HashSet<String>();
2928    
2929          // preload symbolTable
2930          SymbolData throwable = llv.getQualifiedSymbolData("java.lang.Throwable");
2931          SymbolData exception = llv.getQualifiedSymbolData("java.lang.Exception");
2932          SymbolData string = llv.getQualifiedSymbolData("java.lang.String");
2933          SymbolData eb = llv.getQualifiedSymbolData("java.util.prefs.BackingStoreException");
2934          SymbolData re = llv.getQualifiedSymbolData("java.lang.RuntimeException");
2935          
2936          assert symbolTable.contains(throwable);
2937          assert symbolTable.contains(exception);
2938          assert symbolTable.contains(string);
2939    
2940    //      System.err.println("Interfaces for java.lang.RuntimeException = " + re.getInterfaces());
2941          //Make sure it is okay to have something else other than an uncaught exception in a braced body.
2942          BracedBody plainBody = 
2943            new BracedBody(SourceInfo.NONE, new BodyItemI[] {new UnlabeledBreakStatement(SourceInfo.NONE)});
2944          plainBody.visit(_bbtc);
2945          assertEquals("There should be no errors", 0, errors.size());
2946    
2947          //Make sure it is okay to throw a Runtime Exception in a braced body, without catching it.
2948          BracedBody runtimeBB = new BracedBody(SourceInfo.NONE, 
2949                                         new BodyItemI[] { 
2950            new ThrowStatement(SourceInfo.NONE, 
2951                               new SimpleNamedClassInstantiation(SourceInfo.NONE, 
2952                                             new ClassOrInterfaceType(SourceInfo.NONE, 
2953                                                                     "java.lang.RuntimeException", 
2954                                                                     new Type[0]), 
2955                                                                 new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])))});
2956          runtimeBB.visit(_bbtc);
2957          assertEquals("There should be no errors", 0, errors.size());
2958          
2959          //Make sure it is okay to have a uncaught exception in a braced body, if the method is declared to throw it.
2960          BracedBody bb = new BracedBody(SourceInfo.NONE, 
2961                                         new BodyItemI[] { 
2962            new ThrowStatement(SourceInfo.NONE, 
2963            new SimpleNamedClassInstantiation(SourceInfo.NONE, 
2964                                             new ClassOrInterfaceType(SourceInfo.NONE, 
2965                                                                     "java.util.prefs.BackingStoreException", 
2966                                                                     new Type[0]), 
2967                                              new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new StringLiteral(SourceInfo.NONE, "wee")})))});
2968    
2969          _bbtc._bodyData.getMethodData().setThrown(new String[]{"java.util.prefs.BackingStoreException"});
2970          _bbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
2971    
2972          bb.visit(_bbtc);
2973          assertEquals("There should still be no errors", 0, errors.size());
2974          
2975          //make sure it is not okay to have a unchecked exception in a braced body if the method is not declared to throw it.
2976          _bbtc._bodyData.getMethodData().setThrown(new String[0]);
2977          _bbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
2978          
2979          bb.visit(_bbtc);
2980    
2981          assertEquals("There should be one error", 1, errors.size());
2982          assertEquals("The error message should be correct", "This statement throws the exception java.util.prefs.BackingStoreException which needs to be caught or declared to be thrown", errors.get(0).getFirst());
2983          
2984          //make sure that it is not okay to invoke a method that throws an exception if the enclosing method is not declared to throw it.
2985          MethodData badMethod = new MethodData("throwsException", 
2986                                                _packageMav, 
2987                                                new TypeParameter[0], 
2988                                                SymbolData.INT_TYPE, 
2989                                                new VariableData[0],
2990                                                new String[] {"java.util.prefs.BackingStoreException"},
2991                                                _sd1,
2992                                                null);
2993          _bbtc._bodyData.getSymbolData().addMethod(badMethod);                                      
2994          _bbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
2995          BracedBody bbMethod = 
2996            new BracedBody(SourceInfo.NONE, 
2997                           new BodyItemI[] { 
2998            new ExpressionStatement(SourceInfo.NONE, 
2999                                    new SimpleMethodInvocation(SourceInfo.NONE, 
3000                                                               new Word(SourceInfo.NONE, "throwsException"), 
3001                                                               new ParenthesizedExpressionList(SourceInfo.NONE, 
3002                                                                                               new Expression[0])))});
3003          bbMethod.visit(_bbtc);
3004          assertEquals("There should be two errors", 2, errors.size());
3005          assertEquals("The error message should be correct", 
3006                       "The method throwsException is declared to throw the exception java.util.prefs.BackingStoreException" + 
3007                       " which needs to be caught or declared to be thrown", errors.getLast().getFirst());
3008          
3009          //if enclosing method is delared to throw it, should be okay:
3010          _bbtc._bodyData.getMethodData().setThrown(new String[] {"java.util.prefs.BackingStoreException"});
3011          bbMethod.visit(_bbtc);
3012          assertEquals("There should still be two errors", 2, errors.size());
3013          
3014    
3015          //make sure that it is not okay to invoke a constructor that throws an exception if the enclosing method is not declared to throw it
3016          _bbtc._bodyData.getMethodData().setThrown(new String[0]);
3017          _sd3.setMav(_publicMav);
3018          _sd3.setIsContinuation(false);
3019          _bbtc.symbolTable.put(_sd3.getName(), _sd3);
3020          MethodData constructor = new MethodData("zebra", _publicMav, new TypeParameter[0], _sd3, new VariableData[0], new String[] {"java.util.prefs.BackingStoreException"}, _sd3, null);
3021          _sd3.addMethod(constructor);
3022          BracedBody bbConstr = new BracedBody(SourceInfo.NONE, new BodyItemI[]{new ExpressionStatement(SourceInfo.NONE, new SimpleNamedClassInstantiation(SourceInfo.NONE, new ClassOrInterfaceType(SourceInfo.NONE, _sd3.getName(), new Type[0]), new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])))});
3023          _bbtc._thrown = new LinkedList<Pair<SymbolData, JExpression>>();
3024          bbConstr.visit(_bbtc);
3025          assertEquals("There should be three errors", 3, errors.size());
3026          assertEquals("The error message should be correct", "The constructor for the class zebra is declared to throw the exception java.util.prefs.BackingStoreException which needs to be caught or declared to be thrown.", errors.getLast().getFirst());
3027          
3028    
3029          //if enclosing method is delared to throw it, should be okay:
3030          _bbtc._bodyData.getMethodData().setThrown(new String[] {"java.util.prefs.BackingStoreException"});
3031          bbConstr.visit(_bbtc);
3032          assertEquals("There should still be three errors", 3, errors.size());
3033    
3034          
3035        }
3036        
3037        public void testForTryCatchFinallyStatement() {
3038          LanguageLevelVisitor llv = 
3039            new LanguageLevelVisitor(new File(""), 
3040                                     "", 
3041                                     null, // enclosingClassName for top level traversal
3042                                     new LinkedList<String>(), 
3043                                     new LinkedList<String>(), 
3044                                     new HashSet<String>(), 
3045                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
3046                                     new LinkedList<Command>());
3047          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
3048          llv._errorAdded = false;
3049    //      LanguageLevelConverter.symbolTable = llv.symbolTable = symbolTable;
3050    //      LanguageLevelConverter._newSDs = new Hashtable<SymbolData, LanguageLevelVisitor>();
3051          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
3052          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
3053    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
3054          llv._classesInThisFile = new HashSet<String>();
3055    
3056          // preload symbolTable
3057          SymbolData throwable = llv.getQualifiedSymbolData("java.lang.Throwable");
3058          SymbolData exception = llv.getQualifiedSymbolData("java.lang.Exception");
3059          SymbolData string = llv.getQualifiedSymbolData("java.lang.String");
3060          SymbolData eb = llv.getSymbolData("java.util.prefs.BackingStoreException", SourceInfo.NONE, true);
3061          SymbolData re = llv.getSymbolData("java.lang.RuntimeException", SourceInfo.NONE, true);
3062          
3063          assert symbolTable.contains(throwable);
3064          assert symbolTable.contains(exception);
3065          assert symbolTable.contains(string);
3066          
3067          BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
3068          BracedBody bb = new BracedBody(SourceInfo.NONE, 
3069                                         new BodyItemI[] { 
3070            new ThrowStatement(SourceInfo.NONE, 
3071            new SimpleNamedClassInstantiation(SourceInfo.NONE, 
3072                                             new ClassOrInterfaceType(SourceInfo.NONE, 
3073                                                                     "java.util.prefs.BackingStoreException", 
3074                                                                     new Type[0]), 
3075                                              new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[]{new StringLiteral(SourceInfo.NONE, "arg")})))});
3076          
3077          Block b = new Block(SourceInfo.NONE, bb);
3078          Block b2 = new Block(SourceInfo.NONE, emptyBody);
3079        
3080          _bbtc._bodyData.getMethodData().setThrown(new String[0]);
3081          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3082          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3083          
3084          //Test that an empty finally block behaves as expected
3085          TryCatchFinallyStatement tcfs = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], b2);
3086          tcfs.visit(_bbtc);
3087          assertEquals("Should be 1 error", 1, errors.size());
3088          assertEquals("Error message should be correct", 
3089                       "This statement throws the exception java.util.prefs.BackingStoreException which needs to be caught"
3090                         + " or declared to be thrown",
3091                       errors.getLast().getFirst());
3092                       
3093          //Test that a finally block where only one branch ends abruptly acts as expected
3094          IfThenElseStatement ites1 = new IfThenElseStatement(SourceInfo.NONE,
3095                                                              new BooleanLiteral(SourceInfo.NONE, true),
3096                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)),
3097                                                              new EmptyStatement(SourceInfo.NONE));
3098                                                              
3099          BracedBody bb2 = new BracedBody(SourceInfo.NONE, new BodyItemI[] {ites1});
3100          TryCatchFinallyStatement tcfs2 = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], new Block(SourceInfo.NONE, bb2));
3101          _bbtc._bodyData.removeAllBlocks();
3102          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3103          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3104          _bbtc._bodyData.resetBlockIterator();
3105          
3106          TypeData result = tcfs2.visit(_bbtc);  // Duplicates previous error
3107          assertEquals("Should return Exception", SymbolData.EXCEPTION.getInstanceData(), result);
3108          assertEquals("Should still be 1 error", 1, errors.size());
3109          assertEquals("Error message should be correct",
3110                       "This statement throws the exception java.util.prefs.BackingStoreException which needs to be caught"
3111                         + " or declared to be thrown", 
3112                       errors.get(0).getFirst());
3113                                          
3114          //Test that a finally block where both branches end abruptly acts as expected (break)
3115          IfThenElseStatement ites2 = new IfThenElseStatement(SourceInfo.NONE,
3116                                                              new BooleanLiteral(SourceInfo.NONE, false),
3117                                                              new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 4)),
3118                                                              new UnlabeledBreakStatement(SourceInfo.NONE));
3119                                          
3120          BracedBody bb3 = new BracedBody(SourceInfo.NONE, new BodyItemI[] {ites2});
3121          TryCatchFinallyStatement tcfs3 = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], new Block(SourceInfo.NONE, bb3));
3122    
3123          _bbtc._bodyData.removeAllBlocks();
3124          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3125          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3126          _bbtc._bodyData.resetBlockIterator();
3127    
3128          assertEquals("Should return Exception", SymbolData.EXCEPTION.getInstanceData(), tcfs3.visit(_bbtc));
3129          assertEquals("Should still be 1 error", 1, errors.size());
3130          
3131    
3132          //Test that a finally block where both branches end abruptly acts as expected (void return)
3133          _bbtc._bodyData.getMethodData().setReturnType(SymbolData.VOID_TYPE);
3134          IfThenElseStatement ites3 = new IfThenElseStatement(SourceInfo.NONE,
3135                                                              new BooleanLiteral(SourceInfo.NONE, true),
3136                                                              new VoidReturnStatement(SourceInfo.NONE),
3137                                                              new VoidReturnStatement(SourceInfo.NONE));
3138                                                              
3139          BracedBody bb4 = new BracedBody(SourceInfo.NONE, new BodyItemI[] {ites3});
3140          TryCatchFinallyStatement tcfs4 = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], new Block(SourceInfo.NONE, bb4));
3141          _bbtc._bodyData.removeAllBlocks();
3142          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3143          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3144          _bbtc._bodyData.resetBlockIterator();
3145          
3146          result = tcfs4.visit(_bbtc);
3147          assertEquals("Should return SymbolData.VOID_TYPE", SymbolData.VOID_TYPE.getInstanceData(), result);
3148          
3149          assertEquals("Should still still be 1 error", 1, errors.size());
3150    
3151          _bbtc._bodyData.getMethodData().setReturnType(SymbolData.INT_TYPE);
3152    
3153    
3154          //      try {
3155          //         try b
3156          //         finally b2 }
3157          //      finally b2
3158          
3159          //Test that an error is thrown if a try catch statement is nested, an error is thrown but not caught, and finally doesn't return
3160          TryCatchFinallyStatement inner = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], b2);
3161          TryCatchFinallyStatement nested = new TryCatchFinallyStatement(SourceInfo.NONE, 
3162                                                 new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {inner})), 
3163                                                 new CatchBlock[0], b2);
3164                                                 
3165          BlockData innerBD = new BlockData(_bbtc._bodyData);
3166          innerBD.addBlock(new BlockData(innerBD));
3167          innerBD.addBlock(new BlockData(innerBD));
3168    
3169          _bbtc._bodyData.removeAllBlocks();
3170          _bbtc._bodyData.addBlock(innerBD);
3171          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3172          
3173          _bbtc._bodyData.resetBlockIterator();
3174          
3175          nested.visit(_bbtc);  // Duplicates existing error
3176          assertEquals("There should still be 1 errors", 1, errors.size());
3177          assertEquals("Error message should be correct", 
3178                       "This statement throws the exception java.util.prefs.BackingStoreException which needs to be caught"
3179                         + " or declared to be thrown", 
3180                       errors.get(0).getFirst());
3181                                          
3182          //Test that no error is thrown if the exception is caught
3183          UninitializedVariableDeclarator uvd1 = new UninitializedVariableDeclarator(SourceInfo.NONE, new ClassOrInterfaceType(SourceInfo.NONE, "java.util.prefs.BackingStoreException", new Type[0]), new Word(SourceInfo.NONE, "e"));
3184          FormalParameter fp1 = new FormalParameter(SourceInfo.NONE, uvd1, false);
3185          BlockData catchBD = new BlockData(_bbtc._bodyData);
3186          VariableData fpData = new VariableData("e", null, eb, true, catchBD);
3187          catchBD.addVar(fpData);
3188    
3189          CatchBlock cb = new CatchBlock(SourceInfo.NONE, fp1, b2);
3190          TryCatchFinallyStatement nested2 = new TryCatchFinallyStatement(SourceInfo.NONE, new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {inner})), new CatchBlock[] {cb}, b2);
3191          _bbtc._bodyData.removeAllBlocks();
3192          innerBD.resetBlockIterator();
3193          _bbtc._bodyData.addBlock(innerBD);
3194          _bbtc._bodyData.addBlock(catchBD);
3195          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3196          _bbtc._bodyData.resetBlockIterator();
3197    
3198          nested2.visit(_bbtc);
3199          assertEquals("There should still be 1 error", 1, errors.size());
3200          
3201          //Test that no error is thrown if it is a runtime exception
3202          BracedBody reb = new BracedBody(SourceInfo.NONE, 
3203                                         new BodyItemI[] { 
3204            new ThrowStatement(SourceInfo.NONE, 
3205            new SimpleNamedClassInstantiation(SourceInfo.NONE, 
3206                                             new ClassOrInterfaceType(SourceInfo.NONE, 
3207                                                                     "java.lang.RuntimeException", 
3208                                                                     new Type[0]), 
3209                                             new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])))});
3210          
3211          //      try {
3212          //        try {
3213          //          reb
3214          //        }
3215          //        finally b2
3216          //      }
3217          //      finally b2
3218          //      }
3219        
3220          TryCatchFinallyStatement inner3 = new TryCatchFinallyStatement(SourceInfo.NONE, 
3221                                                                         new Block(SourceInfo.NONE, reb), new CatchBlock[0], b2);
3222          TryCatchFinallyStatement nested3 = new TryCatchFinallyStatement(SourceInfo.NONE, 
3223                                                                          new Block(SourceInfo.NONE, 
3224                                                                                    new BracedBody(SourceInfo.NONE, new BodyItemI[] {inner3})), 
3225                                                                          new CatchBlock[0], b2);
3226                                                                                    
3227          _bbtc._bodyData.removeAllBlocks();
3228          innerBD.resetBlockIterator();
3229          _bbtc._bodyData.addBlock(innerBD);
3230          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3231          _bbtc._bodyData.resetBlockIterator();
3232    
3233          nested3.visit(_bbtc);
3234    //      System.err.println("Last error was " + errors.getLast().getFirst());
3235          assertEquals("There should still be 1 error", 1, errors.size());
3236          
3237          //Test that no error is thrown if the method is declared to throw it
3238          _bbtc._bodyData.getMethodData().setThrown(new String[]{"java.util.prefs.BackingStoreException"});
3239          innerBD.resetBlockIterator();
3240          _bbtc._bodyData.resetBlockIterator();
3241          nested.visit(_bbtc);
3242          assertEquals("There should still be 1 error!", 1, errors.size());
3243        }
3244    
3245        public void testForNormalTryCatchStatement() {
3246          LanguageLevelVisitor llv = 
3247            new LanguageLevelVisitor(new File(""), 
3248                                     "", 
3249                                     null, // enclosingClassName for top level traversal
3250                                     new LinkedList<String>(), 
3251                                     new LinkedList<String>(), 
3252                                     new HashSet<String>(), 
3253                                     new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
3254                                     new LinkedList<Command>());
3255          llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
3256          llv._errorAdded=false;
3257    //      LanguageLevelConverter.symbolTable = llv.symbolTable = symbolTable;
3258    //      LanguageLevelConverter._newSDs = new Hashtable<SymbolData, LanguageLevelVisitor>();
3259          llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
3260          llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();      
3261    //      llv._hierarchy = new Hashtable<String, TypeDefBase>();
3262          llv._classesInThisFile = new HashSet<String>();
3263    
3264          // preload symbolTable
3265          SymbolData throwable = llv.getQualifiedSymbolData("java.lang.Throwable");
3266          SymbolData exception = llv.getQualifiedSymbolData("java.lang.Exception");
3267          SymbolData string = llv.getQualifiedSymbolData("java.lang.String");
3268          SymbolData eb = llv.getQualifiedSymbolData("java.util.prefs.BackingStoreException");
3269          SymbolData re = llv.getQualifiedSymbolData("java.lang.RuntimeException");
3270               
3271          assert symbolTable.contains(throwable);
3272          assert symbolTable.contains(exception);
3273          assert symbolTable.contains(string);
3274          
3275          BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
3276          BracedBody bb = new BracedBody(SourceInfo.NONE, 
3277                                         new BodyItemI[] { 
3278            new ThrowStatement(SourceInfo.NONE, 
3279            new SimpleNamedClassInstantiation(SourceInfo.NONE, 
3280                                             new ClassOrInterfaceType(SourceInfo.NONE, 
3281                                                                     "java.util.prefs.BackingStoreException", 
3282                                                                     new Type[0]), 
3283                                              new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[]{new StringLiteral(SourceInfo.NONE, "boo")})))});
3284          
3285          Block b = new Block(SourceInfo.NONE, bb);
3286          Block b2 = new Block(SourceInfo.NONE, emptyBody);
3287        
3288          _bbtc._bodyData.getMethodData().setThrown(new String[0]);
3289          
3290          
3291    //       Test that an empty finally block behaves as expected
3292          NormalTryCatchStatement tcfs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[0]);
3293          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3294          tcfs.visit(_bbtc);
3295          assertEquals("Should be 1 error", 1, errors.size());
3296          assertEquals("Error message should be correct",
3297                       "This statement throws the exception java.util.prefs.BackingStoreException " + 
3298                       "which needs to be caught or declared to be thrown", 
3299    //                   "You are attempting to throw java.util.prefs.BackingStoreException, which does not implement the "
3300    //                     + "Throwable interface",
3301                       errors.getLast().getFirst());
3302                
3303    //      Test that an error is thrown if a try catch statement is nested, an error is thrown but not caught, and finally doesn't return
3304          NormalTryCatchStatement inner = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[0]);
3305          NormalTryCatchStatement nested = new NormalTryCatchStatement(SourceInfo.NONE, new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {inner})), new CatchBlock[0]);
3306          
3307          BlockData innerBD = new BlockData(_bbtc._bodyData);
3308          innerBD.addBlock(new BlockData(innerBD));
3309          innerBD.addBlock(new BlockData(innerBD));
3310    
3311          _bbtc._bodyData.removeAllBlocks();
3312          _bbtc._bodyData.addBlock(innerBD);
3313          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3314          
3315          _bbtc._bodyData.resetBlockIterator();
3316    
3317          nested.visit(_bbtc);
3318          assertEquals("There should still be be 1 error", 1, errors.size());  // Generated error is a duplicate!
3319          assertEquals("Error message should be correct", 
3320    //                   "You are attempting to throw java.util.prefs.BackingStoreException, which does not implement the"
3321    //                     + " Throwable interface",
3322                       "This statement throws the exception java.util.prefs.BackingStoreException " + 
3323                       "which needs to be caught or declared to be thrown", 
3324                       errors.get(0).getFirst());
3325                                          
3326    //      Test that no error is thrown if the exception is caught
3327          UninitializedVariableDeclarator uvd1 = new UninitializedVariableDeclarator(SourceInfo.NONE, new ClassOrInterfaceType(SourceInfo.NONE, "java.util.prefs.BackingStoreException", new Type[0]), new Word(SourceInfo.NONE, "e"));
3328          FormalParameter fp1 = new FormalParameter(SourceInfo.NONE, uvd1, false);
3329          BlockData catchBD = new BlockData(_bbtc._bodyData);
3330          VariableData fpData = new VariableData("e", null, eb, true, catchBD);
3331          catchBD.addVar(fpData);
3332         
3333    
3334          CatchBlock cb = new CatchBlock(SourceInfo.NONE, fp1, b2);
3335          NormalTryCatchStatement nested2 = new NormalTryCatchStatement(SourceInfo.NONE, new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {inner})), new CatchBlock[] {cb});
3336    
3337          _bbtc._bodyData.removeAllBlocks();
3338          innerBD.resetBlockIterator();
3339          _bbtc._bodyData.addBlock(innerBD);
3340          _bbtc._bodyData.addBlock(catchBD);
3341          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3342          _bbtc._bodyData.resetBlockIterator();
3343    
3344          nested2.visit(_bbtc);
3345          assertEquals("There should still be 1 error", 1, errors.size());
3346          
3347    //      Test that no error is thrown if it is a runtime exception
3348          BracedBody reb = new BracedBody(SourceInfo.NONE, 
3349                                         new BodyItemI[] { 
3350            new ThrowStatement(SourceInfo.NONE, 
3351            new SimpleNamedClassInstantiation(SourceInfo.NONE, 
3352                                             new ClassOrInterfaceType(SourceInfo.NONE, 
3353                                                                     "java.lang.RuntimeException", 
3354                                                                     new Type[0]), 
3355                                             new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])))});
3356          
3357          NormalTryCatchStatement inner3 = new NormalTryCatchStatement(SourceInfo.NONE, new Block(SourceInfo.NONE, reb), new CatchBlock[0]);
3358          NormalTryCatchStatement nested3 = new NormalTryCatchStatement(SourceInfo.NONE, new Block(SourceInfo.NONE, new BracedBody(SourceInfo.NONE, new BodyItemI[] {inner3})), new CatchBlock[0]);
3359          
3360          _bbtc._bodyData.removeAllBlocks();
3361          innerBD.resetBlockIterator();
3362          _bbtc._bodyData.addBlock(innerBD);
3363          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3364          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3365          _bbtc._bodyData.resetBlockIterator();
3366    
3367          
3368          nested3.visit(_bbtc);
3369    //      System.err.println("Last error is: " + errors.getLast().getFirst());
3370          assertEquals("There should still be 1 error", 1, errors.size());
3371          
3372          // Test that no error is thrown if the method is declared to throw it
3373          _bbtc._bodyData.getMethodData().setThrown(new String[]{"java.util.prefs.BackingStoreException"});
3374          _bbtc._bodyData.removeAllBlocks();
3375          innerBD.resetBlockIterator();
3376          _bbtc._bodyData.addBlock(innerBD);
3377          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3378          _bbtc._bodyData.addBlock(new BlockData(_bbtc._bodyData));
3379          _bbtc._bodyData.resetBlockIterator();
3380    
3381          nested.visit(_bbtc);
3382          assertEquals("There should still be 1 error!", 1, errors.size());
3383        }
3384      }
3385    }