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 /**Do the TypeChecking appropriate to the context of a class body. Common to all Language Levels.*/
049 public class InterfaceBodyTypeChecker extends SpecialTypeChecker {
050
051 /**The SymbolData corresponding to this interface.*/
052 private SymbolData _symbolData;
053
054 /* Constructor for InterfaceBodyTypeChecker. Adds all the variables in the symbol data to the list of what can be
055 * seen from this context, since interface fields can always be seen.
056 * @param sd The SymbolData of the interface we are type checking.
057 * @param file The File corresponding to the source file we are checking.
058 * @param packageName The package of the source file.
059 * @param importedFiles A list of the names of the classes that are specifically imported in the source file
060 * @param importedPackages A list of the names of the packages that are imported in the source file.
061 * @param vars A list of the variable datas that can be seen and have been given a value before this context
062 * @param thrown The exceptions that are thrown
063 */
064 public InterfaceBodyTypeChecker(SymbolData sd, File file, String packageName, LinkedList<String> importedFiles, LinkedList<String> importedPackages, LinkedList<VariableData> vars, LinkedList<Pair<SymbolData, JExpression>> thrown) {
065 super(sd, file, packageName, importedFiles, importedPackages, vars, thrown);
066 _vars.addAll(sd.getVars());
067 _symbolData = sd;
068 }
069
070 /**@return the SymbolData corresponding to the enclosing interface*/
071 protected Data _getData() {
072 return _symbolData;
073 }
074
075
076 /** All fields in interfaces must be initialized where they are declared, so throw an error.*/
077 public TypeData forUninitializedVariableDeclarator(UninitializedVariableDeclarator that) {
078 _addError("All fields in interfaces must be initialized", that);
079 return null;
080 }
081
082 /**
083 * Resolve all the stuff that is stored in the AbstractMethodDef. Find the method data
084 * that was created on the first pass to correspond to this method, and make sure that this
085 * method doesn't resolve another method with a different return type.
086 */
087 public TypeData forAbstractMethodDef(AbstractMethodDef that) {
088 final TypeData mavRes = that.getMav().visit(this);
089 final TypeData[] typeParamsRes = makeArrayOfRetType(that.getTypeParams().length);
090 for (int i = 0; i < that.getTypeParams().length; i++) {
091 typeParamsRes[i] = that.getTypeParams()[i].visit(this);
092 }
093 final TypeData resRes = getSymbolData(that.getResult().getName(), _symbolData, that);//that.getResult().visit(this);
094 final TypeData nameRes = that.getName().visit(this);
095 final TypeData[] paramsRes = makeArrayOfRetType(that.getParams().length);
096 for (int i = 0; i<paramsRes.length; i++) {
097 paramsRes[i] = getSymbolData(that.getParams()[i].getDeclarator().getType().getName(), _symbolData, that.getParams()[i]);
098 }
099 final TypeData[] throwsRes = makeArrayOfRetType(that.getThrows().length);
100 for (int i = 0; i < that.getThrows().length; i++) {
101 throwsRes[i] = getSymbolData(that.getThrows()[i].getName(), _symbolData, that.getThrows()[i]);//that.getThrows()[i].visit(this);
102 }
103 // Ensure that this method doesn't override another method with a different return type.
104 MethodData md = _symbolData.getMethod(that.getName().getText(), paramsRes);
105 if (md == null) {
106 throw new RuntimeException("Internal Program Error: Could not find the method " + that.getName().getText() + " in interface " + _symbolData.getName() + ". Please report this bug.");
107 }
108 SymbolData.checkDifferentReturnTypes(md, _symbolData, LanguageLevelConverter.OPT.javaVersion());
109 return resRes;
110 }
111
112
113 /**This error should be thrown in the first pass, but throw it again here, just in case*/
114 public TypeData forConcreteMethodDef(ConcreteMethodDef that) {
115 _addError("Concrete method definitions cannot appear in interfaces", that);
116 return null;
117 }
118
119 /**
120 * Try to resolve the type that is referenced. Check to see if it is accessible from this context.
121 */
122 public TypeData forTypeOnly(Type that) {
123 Data sd = getSymbolData(that.getName(), _symbolData, that);
124 if (sd != null) {sd = sd.getOuterData();}
125 while (sd != null && !LanguageLevelVisitor.isJavaLibraryClass(sd.getSymbolData().getName())) {
126 if (!checkAccess(that, sd.getMav(), sd.getName(), sd.getSymbolData(), _symbolData, "class or interface")) {
127 return null;
128 }
129 sd = sd.getOuterData();
130 }
131 return null;
132 }
133
134
135 /**
136 * Test the methods declared in the above class.
137 */
138 public static class InterfaceBodyTypeCheckerTest extends TestCase {
139
140 private InterfaceBodyTypeChecker _ibbtc;
141
142 private SymbolData _sd1;
143 private SymbolData _sd2;
144 private SymbolData _sd3;
145 private SymbolData _sd4;
146 private SymbolData _sd5;
147 private SymbolData _sd6;
148 private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
149 private ModifiersAndVisibility _protectedMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
150 private ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
151 private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
152 private ModifiersAndVisibility _abstractMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
153 private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
154
155
156 public InterfaceBodyTypeCheckerTest() {
157 this("");
158 }
159 public InterfaceBodyTypeCheckerTest(String name) {
160 super(name);
161 // _file = File.createTempFile("DrJava-test", ".java");
162 // _bv = new BeginnerVisitor(new File(""), "", new LinkedList<String>(), new LinkedList<String>(),
163 // new LinkedList<String>());
164 }
165
166 public void setUp() {
167 _sd1 = new SymbolData("i.like.monkey");
168 _sd2 = new SymbolData("i.like.giraffe");
169 _sd3 = new SymbolData("zebra");
170 _sd4 = new SymbolData("u.like.emu");
171 _sd5 = new SymbolData("");
172 _sd6 = new SymbolData("cebu");
173 errors = new LinkedList<Pair<String, JExpressionIF>>();
174 LanguageLevelConverter.symbolTable.clear();
175 LanguageLevelConverter._newSDs.clear();
176 _ibbtc =
177 new InterfaceBodyTypeChecker(_sd1, new File(""), "", new LinkedList<String>(), new LinkedList<String>(),
178 new LinkedList<VariableData>(), new LinkedList<Pair<SymbolData, JExpression>>());
179 LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
180 _ibbtc._importedPackages.addFirst("java.lang");
181 }
182
183 public void testForUninitializedVariableDeclaratorOnly() {
184 VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, false, _sd1);
185 _sd1.addVar(vd1);
186 UninitializedVariableDeclarator uvd =
187 new UninitializedVariableDeclarator(SourceInfo.NONE,
188 new PrimitiveType(SourceInfo.NONE, "int"),
189 new Word(SourceInfo.NONE, "Mojo"));
190 uvd.visit(_ibbtc);
191 _ibbtc.forUninitializedVariableDeclaratorOnly(uvd, SymbolData.INT_TYPE, null);
192 assertEquals("There should be one error", 1, errors.size());
193 assertEquals("The error message should be correct", "All fields in interfaces must be initialized",
194 errors.get(0).getFirst());
195 }
196
197 public void testForInitializedVariableDeclaratorOnly() {
198 VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, false, _sd1);
199 _sd1.addVar(vd1);
200 InitializedVariableDeclarator ivd =
201 new InitializedVariableDeclarator(SourceInfo.NONE,
202 new PrimitiveType(SourceInfo.NONE, "int"),
203 new Word(SourceInfo.NONE, "Mojo"),
204 new IntegerLiteral(SourceInfo.NONE, 1));
205 ivd.visit(_ibbtc);
206 assertEquals("There should be no errors.", 0, errors.size());
207 assertTrue("_vars should contain Mojo.", _ibbtc._vars.contains(vd1));
208 ivd = new InitializedVariableDeclarator(SourceInfo.NONE,
209 new PrimitiveType(SourceInfo.NONE, "int"),
210 new Word(SourceInfo.NONE, "Santa's Little Helper"),
211 new IntegerLiteral(SourceInfo.NONE, 1));
212 try {
213 ivd.visit(_ibbtc);
214 fail("Should have thrown a RuntimeException because there's no field named Santa's Little Helper.");
215 }
216 catch (RuntimeException re) {
217 assertEquals("The error message should be correct.",
218 "Internal Program Error: The field or variable Santa's Little Helper was not found in this block. Please report this bug.", re.getMessage());
219 }
220 }
221
222 public void testForConcreteMethodDef() {
223 FormalParameter[] fps = new FormalParameter[] {
224 new FormalParameter(SourceInfo.NONE,
225 new UninitializedVariableDeclarator(SourceInfo.NONE,
226 new PrimitiveType(SourceInfo.NONE, "double"),
227 new Word (SourceInfo.NONE, "field1")),
228 false),
229 new FormalParameter(SourceInfo.NONE,
230 new UninitializedVariableDeclarator(SourceInfo.NONE,
231 new PrimitiveType(SourceInfo.NONE, "boolean"),
232 new Word (SourceInfo.NONE, "field2")),
233 false)};
234
235 ConcreteMethodDef cmd =
236 new ConcreteMethodDef(SourceInfo.NONE,
237 _packageMav,
238 new TypeParameter[0],
239 new PrimitiveType(SourceInfo.NONE, "int"),
240 new Word(SourceInfo.NONE, "methodName"),
241 fps,
242 new ReferenceType[0],
243 new BracedBody(SourceInfo.NONE, new BodyItemI[] {
244 new ValueReturnStatement(SourceInfo.NONE,
245 new IntegerLiteral(SourceInfo.NONE, 5))}));
246
247 MethodData md = new MethodData("methodName",
248 _packageMav,
249 new TypeParameter[0],
250 SymbolData.INT_TYPE,
251 new VariableData[] { new VariableData(SymbolData.DOUBLE_TYPE), new VariableData(SymbolData.BOOLEAN_TYPE) },
252 new String[0],
253 _sd1,
254 null); // no SourceInfo
255
256 md.getParams()[0].setEnclosingData(md);
257 md.getParams()[1].setEnclosingData(md);
258
259 _sd1.addMethod(md);
260 // _ibbtc._vars.addLast(new VariableData("field1", _packageMav, SymbolData.DOUBLE_TYPE));
261 cmd.visit(_ibbtc);
262 assertEquals("There should be one error.", 1, errors.size());
263 assertEquals("The error message should be correct", "Concrete method definitions cannot appear in interfaces", errors.get(0).getFirst());
264 }
265
266 public void testForTypeOnly() {
267 Type t = new PrimitiveType(SourceInfo.NONE, "double");
268 t.visit(_ibbtc);
269 assertEquals("There should be no errors", 0, errors.size());
270
271 SymbolData sd = new SymbolData("Adam");
272 sd.setIsContinuation(false);
273 symbolTable.put("Adam", sd);
274 sd.setMav(_publicMav);
275 t = new ClassOrInterfaceType(SourceInfo.NONE, "Adam", new Type[0]);
276 t.visit(_ibbtc);
277 assertEquals("There should still be no errors", 0, errors.size());
278
279 SymbolData innerSd = new SymbolData("Adam$Wulf");
280 innerSd.setIsContinuation(false);
281 sd.addInnerClass(innerSd);
282 innerSd.setOuterData(sd);
283 innerSd.setMav(_publicMav);
284 _ibbtc.symbolTable.put("USaigehgihdsgslghdlighs", innerSd);
285 t = new ClassOrInterfaceType(SourceInfo.NONE, "Adam.Wulf", new Type[0]);
286 t.visit(_ibbtc);
287 assertEquals("There should still be no errors", 0, errors.size());
288
289 innerSd.setMav(_privateMav);
290 t = new ClassOrInterfaceType(SourceInfo.NONE, "Adam.Wulf", new Type[0]);
291 t.visit(_ibbtc);
292 String tcSDName = _ibbtc._symbolData.getName();
293 assertEquals("There should be one error", 1, errors.size());
294 assertEquals("The error message should be correct",
295 "The class or interface Adam.Wulf in Adam.Wulf is private and cannot be accessed from " + tcSDName,
296 errors.get(0).getFirst());
297
298 sd.setMav(_privateMav);
299 innerSd.setMav(_publicMav);
300 t = new ClassOrInterfaceType(SourceInfo.NONE, "Adam.Wulf", new Type[0]);
301 t.visit(_ibbtc);
302 assertEquals("There should be two errors", 2, errors.size());
303 assertEquals("The error message should be correct",
304 "The class or interface Adam in Adam is private and cannot be accessed from " + tcSDName,
305 errors.get(1).getFirst());
306 }
307 }
308 }