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 /**Does TypeChecking for the context of a Try-Catch body. Common to all LanguageLevels.*/
049 public class TryCatchBodyTypeChecker extends BodyTypeChecker {
050
051
052 /* Constructor for TryCatchBodyTypeChecker. Delegates the initialization to the BodyTypeChecker
053 * @param bodyData The enclosing BodyData for the context we are type checking.
054 * @param file The File corresponding to the source file.
055 * @param packageName The package name from the source file.
056 * @param importedFiles The names of the files that are specifically imported (through a class import statement) in the source file.
057 * @param importedPackages The names of all the packages that are imported through a package import statement in the source file.
058 * @param vars The list of VariableData that have already been defined (used so we can make sure we don't use a variable before it has been defined).
059 * @param thrown The list of exceptions thrown in this body
060 */
061 public TryCatchBodyTypeChecker(BodyData bodyData, File file, String packageName, LinkedList<String> importedFiles, LinkedList<String> importedPackages, LinkedList<VariableData> vars, LinkedList<Pair<SymbolData, JExpression>> thrown) {
062 super(bodyData, file, packageName, importedFiles, importedPackages, vars, thrown);
063 }
064
065
066 /** Create a new instance of this class for visiting inner bodies. */
067 protected BodyTypeChecker createANewInstanceOfMe(BodyData bodyData, File file, String pakage, LinkedList<String> importedFiles, LinkedList<String> importedPackages, LinkedList<VariableData> vars, LinkedList<Pair<SymbolData, JExpression>> thrown) {
068 return new TryCatchBodyTypeChecker(bodyData, file, pakage, importedFiles, importedPackages, vars, thrown);
069 }
070
071 /** Overwritten here, becuase it is okay for there to be thrown exceptions in the middle of a try catch. */
072 public TypeData forBracedBody(BracedBody that) {
073 final TypeData[] items_result = makeArrayOfRetType(that.getStatements().length);
074 for (int i = 0; i < that.getStatements().length; i++) {
075 items_result[i] = that.getStatements()[i].visit(this);
076 }
077 return forBracedBodyOnly(that, items_result);
078 }
079
080 /** Make sure that every Exception in thrown is either in caught or in the list of what can be thrown from where we are.
081 * Also make sure that every Exception that is declared to be thrown or caught is actually thrown.
082 * Overrides the same method in BodyTypeChecker.
083 * @param that The TryCatchStatement we are currently working with
084 * @param caught_array The SymbolData[] of exceptions that are explicitely caught.
085 * @param thrown The LinkedList of SymbolData of exceptions that are thrown. This will be modified.
086 */
087 protected void compareThrownAndCaught(TryCatchStatement that, SymbolData[] caught_array,
088 LinkedList<Pair<SymbolData, JExpression>> thrown) {
089 LinkedList<Pair<SymbolData, JExpression>> copyOfThrown = new LinkedList<Pair<SymbolData, JExpression>>();
090 for (Pair<SymbolData, JExpression> p : thrown) {
091 copyOfThrown.addLast(p);
092 }
093 //Make sure that every Exception in thrown is either caught or in the list of what can be thrown
094 for (Pair<SymbolData, JExpression> p : copyOfThrown) {
095 SymbolData sd = p.getFirst();
096 // Iterate over the caught array and see if the current thrown exception is a subclass of one of the exceptions.
097 for (SymbolData currCaughtSD : caught_array) {
098 if (sd.isSubClassOf(currCaughtSD) || (!isUncaughtCheckedException(sd, new NullLiteral(SourceInfo.NONE)))) {
099 thrown.remove(p);
100 }
101 }
102 }
103 makeSureCaughtStuffWasThrown(that, caught_array, copyOfThrown);
104 }
105
106 /**
107 * Test the methods declared in the above class.
108 */
109 public static class TryCatchBodyTypeCheckerTest extends TestCase {
110
111 private TryCatchBodyTypeChecker _tcbtc;
112
113 private BodyData _bd1;
114 private BodyData _bd2;
115
116 private SymbolData _sd1;
117 private SymbolData _sd2;
118 private SymbolData _sd3;
119 private SymbolData _sd4;
120 private SymbolData _sd5;
121 private SymbolData _sd6;
122 private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
123 private ModifiersAndVisibility _protectedMav =
124 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
125 private ModifiersAndVisibility _privateMav =
126 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
127 private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
128 private ModifiersAndVisibility _abstractMav =
129 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
130 private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
131
132
133 public TryCatchBodyTypeCheckerTest() { this(""); }
134 public TryCatchBodyTypeCheckerTest(String name) { super(name); }
135
136 public void setUp() {
137 _sd1 = new SymbolData("i.like.monkey");
138 _sd2 = new SymbolData("i.like.giraffe");
139 _sd3 = new SymbolData("zebra");
140 _sd4 = new SymbolData("u.like.emu");
141 _sd5 = new SymbolData("");
142 _sd6 = new SymbolData("cebu");
143
144 _bd1 = new MethodData("monkey",
145 _packageMav,
146 new TypeParameter[0],
147 _sd1,
148 new VariableData[] { new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, null), new VariableData(SymbolData.BOOLEAN_TYPE) },
149 new String[0],
150 _sd1,
151 null); // no SourceInfo
152 ((MethodData) _bd1).getParams()[0].setEnclosingData(_bd1);
153 ((MethodData) _bd1).getParams()[1].setEnclosingData(_bd1);
154
155 errors = new LinkedList<Pair<String, JExpressionIF>>();
156 LanguageLevelConverter.symbolTable.clear();
157 _bd1.addEnclosingData(_sd1);
158 _bd1.addFinalVars(((MethodData)_bd1).getParams());
159 _tcbtc = new TryCatchBodyTypeChecker(_bd1, new File(""), "", new LinkedList<String>(), new LinkedList<String>(), new LinkedList<VariableData>(), new LinkedList<Pair<SymbolData, JExpression>>());
160 LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
161 _tcbtc._importedPackages.addFirst("java.lang");
162 }
163
164
165 public void testCreateANewInstanceOfMe() {
166 //make sure that the correct visitor is returned from createANewInstanceOfMe
167 BodyTypeChecker btc = _tcbtc.createANewInstanceOfMe(_tcbtc._bodyData, _tcbtc._file, _tcbtc._package, _tcbtc._importedFiles, _tcbtc._importedPackages, _tcbtc._vars, _tcbtc._thrown);
168 assertTrue("Should be an instance of ConstructorBodyTypeChecker", btc instanceof TryCatchBodyTypeChecker);
169 }
170
171 public void testForBracedBody() {
172 //make sure it is okay to have a uncaught exception in a braced body
173 BracedBody bb = new BracedBody(SourceInfo.NONE,
174 new BodyItemI[] {
175 new ThrowStatement(SourceInfo.NONE,
176 new SimpleNamedClassInstantiation(SourceInfo.NONE,
177 new ClassOrInterfaceType(SourceInfo.NONE,
178 "java.util.prefs.BackingStoreException",
179 new Type[0]),
180 new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new StringLiteral(SourceInfo.NONE, "arg")})))});
181
182 LanguageLevelVisitor llv =
183 new LanguageLevelVisitor(new File(""),
184 "",
185 null, // enclosingClassName for top level traversal
186 new LinkedList<String>(),
187 new LinkedList<String>(),
188 new HashSet<String>(),
189 new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
190 new LinkedList<Command>());
191 llv.errors = new LinkedList<Pair<String, JExpressionIF>>();
192 llv._errorAdded=false;
193 LanguageLevelConverter.symbolTable.clear();
194 LanguageLevelConverter._newSDs.clear();
195 LanguageLevelConverter.loadSymbolTable();
196 llv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
197 llv.visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();
198 // llv._hierarchy = new Hashtable<String, TypeDefBase>();
199 llv._classesInThisFile = new HashSet<String>();
200
201 SymbolData o = symbolTable.get("java.lang.Object");
202 // o.setIsContinuation(false);
203 // o.setMav(_publicMav);
204 // symbolTable.put("java.lang.Object", o);
205
206 SymbolData string = new SymbolData("java.lang.String");
207 string.setIsContinuation(false);
208 string.setMav(_publicMav);
209 string.setSuperClass(o); // a white lie for this test
210 symbolTable.put("java.lang.String", string);
211
212 SymbolData e = llv.getSymbolData("java.util.prefs.BackingStoreException", SourceInfo.NONE, true);
213
214 bb.visit(_tcbtc);
215 assertEquals("There should be no errors because it's ok to have uncaught exceptions in this visitor",
216 0,
217 errors.size());
218 }
219
220 public void testCompareThrownAndCaught() {
221 BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
222 Block b = new Block(SourceInfo.NONE, emptyBody);
223
224 PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
225 UninitializedVariableDeclarator uvd =
226 new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
227 FormalParameter param =
228 new FormalParameter(SourceInfo.NONE,
229 new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "j")),
230 false);
231
232 NormalTryCatchStatement ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[] {new CatchBlock(SourceInfo.NONE, param, b)});
233
234 SymbolData javaLangThrowable = _tcbtc.getSymbolData("java.lang.Throwable", ntcs, false, true);
235 _tcbtc.symbolTable.put("java.lang.Throwable", javaLangThrowable);
236 SymbolData exception = new SymbolData("my.crazy.exception");
237 exception.setSuperClass(javaLangThrowable);
238 SymbolData exception2 = new SymbolData("A&M.beat.Rice.in.BaseballException");
239 exception2.setSuperClass(javaLangThrowable);
240 SymbolData exception3 = new SymbolData("aegilha");
241 exception3.setSuperClass(exception2);
242 SymbolData[] caught_array = new SymbolData[] { exception, exception2 };
243 LinkedList<Pair<SymbolData, JExpression>> thrown = new LinkedList<Pair<SymbolData, JExpression>>();
244 thrown.addLast(new Pair<SymbolData, JExpression>(exception, ntcs));
245 thrown.addLast(new Pair<SymbolData, JExpression>(exception2, ntcs));
246 thrown.addLast(new Pair<SymbolData, JExpression>(exception3, ntcs));
247
248 _tcbtc.compareThrownAndCaught(ntcs, caught_array, thrown);
249 // System.err.println("thrown = " + thrown);
250 assertTrue("Thrown should have no elements", thrown.isEmpty());
251
252
253 _tcbtc.compareThrownAndCaught(ntcs, new SymbolData[] {exception2}, thrown);
254 assertEquals("There should be one error", 1, errors.size());
255 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());
256
257 }
258 }
259 }