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