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 import java.util.*;
043 import java.io.*;
044
045 import junit.framework.TestCase;
046
047 /** Class body walking LanguageLevelVisitor for the FullJava Language Level. Builds the symbol table for a .java file
048 * without performing any syntax checking. This file will also be compiled by javac, which will catch the syntax
049 * errors.
050 */
051 public class ClassBodyFullJavaVisitor extends FullJavaVisitor {
052
053 /**The SymbolData corresponding to this class.*/
054 private SymbolData _enclosing;
055
056 /** Deprecated onstructor for ClassBodyFullJavaVisitor.
057 * @param sd The SymbolData that encloses the context we are visiting. Must be non-null.
058 * @param className The name of the enclosing class. Must be non-null and non-empty.
059 * @param file The source file this came from.
060 * @param packageName The package the source file is in
061 * @importedFiles A list of classes that were specifically imported
062 * @param importedPackages A list of package names that were specifically imported
063 * @param classesInThisFile A list of the classes that are yet to be defined in this source file
064 * @param continuations A hashtable corresponding to the continuations (unresolved Symbol Datas) that will need to
065 * be resolved
066 * TODO: coalesce className and enclosingClassName
067 */
068 public ClassBodyFullJavaVisitor(SymbolData sd,
069 String className,
070 File file,
071 String packageName,
072 LinkedList<String> importedFiles,
073 LinkedList<String> importedPackages,
074 HashSet<String> classesInThisFile,
075 Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
076 LinkedList<Command> fixUps) {
077 super(file, packageName, className, importedFiles, importedPackages, classesInThisFile, continuations, fixUps);
078 _enclosing = sd;
079 assert sd != null && className != null && ! className.equals("");
080 }
081
082 /** Preferred constructor for ClassBodyFullJavaVisitor.
083 * @param sd The SymbolData that encloses the context we are visiting. Must be non-null.ty.
084 * @param file The source file this came from.
085 * @param packageName The package the source file is in
086 * @importedFiles A list of classes that were specifically imported
087 * @param importedPackages A list of package names that were specifically imported
088 * @param classesInThisFile A list of the classes that are yet to be defined in this source file
089 * @param continuations A hashtable corresponding to the continuations (unresolved Symbol Datas) that will need to
090 * be resolved
091 * TODO: coalesce className and enclosingClassName
092 */
093 public ClassBodyFullJavaVisitor(SymbolData sd,
094 File file,
095 String packageName,
096 LinkedList<String> importedFiles,
097 LinkedList<String> importedPackages,
098 HashSet<String> classesInThisFile,
099 Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
100 LinkedList<Command> fixUps,
101 HashMap<String, SymbolData> genericTypes) {
102 super(file, packageName, sd.getName(), importedFiles, importedPackages, classesInThisFile, continuations, fixUps,
103 genericTypes);
104 _enclosing = sd;
105 assert sd != null;
106 }
107
108 /* Ignore ForStatement. */
109 public Void forStatementDoFirst(Statement that) { return null; }
110
111 /** Ignore ConcreteMethodDef. */
112
113 /** Ignore AbstractMake sure that this abstract method def is declared to be abstract. */
114 public Void forAbstractMethodDefDoFirst(AbstractMethodDef that) {
115
116 // ModifiersAndVisibility mav = that.getMav();
117 // String[] modifiers = mav.getModifiers();
118 if (! _enclosing.isInterface() && ! _enclosing.hasModifier("abstract")) { // interfaces not yet marked abstract
119 _addError("Abstract methods can only be declared in abstract classes", that);
120 }
121 return super.forAbstractMethodDefDoFirst(that);
122 }
123
124 /*Add an appropriate error*/
125 public Void forInstanceInitializerDoFirst(InstanceInitializer that) {
126 _addError("This open brace must mark the beginning of a method or class body", that);
127 return null;
128 }
129
130 /** Processes a field declaration. Converts the VariableDeclaration to VariableData[]. Adds the variable datas to
131 * the symbol data, and gives an error if two fields have the same names
132 */
133 public Void forVariableDeclarationOnly(VariableDeclaration that) {
134 // System.err.println("forVariableDeclarationOnly called in ClassBodyFullJavaVisitor for " + that);
135 VariableData[] vds = _variableDeclaration2VariableData(that, _enclosing);
136 // System.err.println(" ## generated vds = " + Arrays.toString(vds));
137
138 // Add the variable datas to the symbol data
139 if (! _enclosing.addVars(vds)) {
140 _addAndIgnoreError("You cannot have two fields with the same name. Either you already have a field by that "
141 + "name in this class, or one of your superclasses or interfaces has a field by that name",
142 that);
143 }
144 return null;
145 }
146
147 /** Create a method data corresponding to this method declaration, and then visit the
148 * concrete method def with a new bodybody visitor, passing it the enclosing method data.
149 * Make sure the method name is different from the class name.
150 */
151 public Void forConcreteMethodDef(ConcreteMethodDef that) {
152 forConcreteMethodDefDoFirst(that);
153 if (prune(that)) return null;
154 assert _enclosing != null;
155
156 TypeParameter[] tps = that.getTypeParams();
157
158 // TODO !!! pass genericTypes as a parameter to createMethod and critical submethods. The scope of the
159 // new generic types table includes all of createMethodData processing, notably processing the return type.
160 // Passing an extended generic types table to BodyBodyFullJavaVisitor is insufficient
161
162 // Save a snapshot of _genericTypes
163 HashMap<String, SymbolData> oldGenericTypes = _genericTypes;
164
165 // Rebind _genericTypes to a shallow copy of itself for use in processing this method. The temporary variable copy
166 // gets around a bug in javac in processing the SuppressWarnings statement.
167 @SuppressWarnings("unchecked")
168 HashMap<String, SymbolData> copy = (HashMap<String, SymbolData>) _genericTypes.clone();
169 _genericTypes = copy;
170
171 if (tps != null && tps.length > 0) { // extend genericTypes by new polymorphic method type variable bindings
172 // Utilities.show("forConcreteMethodDef encountered a non-empty type parameters list:\n" + Arrays.toString(tps));
173 // System.err.println("forConcreteMethodDef encountered a non-empty type parameters list:\n" + Arrays.toString(tps));
174 for (TypeParameter tp: tps) {
175 final String typeName = tp.getVariable().getName();
176 final String boundName = tp.getBound().getName();
177 // System.err.println("***** Type variable " + typeName + " is bound to " + boundName);
178 SymbolData boundSD = _identifyType(boundName, that.getSourceInfo(), _enclosingClassName);
179 // System.err.println("***** Corresponding SymbolData is " + boundSD);
180 // Utilities.show("Type variable " + typeName + " is bound to " + boundName + " Corresponding SD is " + boundSD);
181 // TODO: could create a separate unbound type variable singleton class?
182 if (boundSD == null) { // create a dummy SymbolData
183 boundSD = symbolTable.get("java.lang.Object");
184 // System.err.println("Creating dummy SymbolData for bounding type " + typeName + " in inner class " + name);
185 // TODO! !!!!! Create an appropriate fixUp mechanism
186 }
187 // System.err.println("In method " + _enclosing + "." + that.getName().getText() + ", type " + typeName
188 // + " is bound to " + boundSD);
189 _genericTypes.put(typeName, boundSD);
190 }
191 }
192
193 MethodData md = createMethodData(that, _enclosing);
194 String className = getUnqualifiedClassName(_enclosing.getName());
195
196 if (className.equals(md.getName())) {
197 _addAndIgnoreError("Only constructors can have the same name as the class they appear in, and constructors "
198 + "do not have an explicit return type",
199 that);
200 }
201 else _enclosing.addMethod(md);
202 that.getBody().visit(new BodyBodyFullJavaVisitor(md, _file, _package, _enclosingClassName, _importedFiles,
203 _importedPackages,
204 _classesInThisFile, continuations, fixUps,
205 new HashSet<String>(), _genericTypes));
206 _genericTypes = oldGenericTypes;
207 return null;
208 }
209
210 /** Creates a MethodData corresponding to this method declaration. Ensures that the method name is different from the
211 * class name.
212 */
213 public Void forAbstractMethodDef(AbstractMethodDef that) {
214 forAbstractMethodDefDoFirst(that);
215 if (prune(that)) return null;
216
217 assert _enclosing != null;
218
219 // Process type parameters
220 TypeParameter[] tps = that.getTypeParams();
221
222 // TODO !!! pass genericTypes as a parameter to createMethod and critical submethods. The scope of the
223 // new generic types table includes all of createMethodData processing, notably processing the return type.
224 // Passing an extended generic types table to BodyBodyFullJavaVisitor is insufficient
225
226 // Save a snapshot of _genericTypes
227 HashMap<String, SymbolData> oldGenericTypes = _genericTypes;
228
229 // Rebind _genericTypes to a shallow copy of itself for use in processing this method. The temporary variable copy
230 // gets around a bug in javac in processing the SuppressWarnings statement.
231 @SuppressWarnings("unchecked")
232 HashMap<String, SymbolData> copy = (HashMap<String, SymbolData>)_genericTypes.clone();
233 _genericTypes = copy;
234
235 if (tps != null) { // extend genericTypes by new type variable bindings
236 for (TypeParameter tp: tps) {
237 final String typeName = tp.getVariable().getName();
238 final String boundName = tp.getBound().getName();
239 SymbolData boundSD = _identifyType(boundName, that.getSourceInfo(), _enclosingClassName);
240 if (boundSD == null) { // create a dummy SymbolData
241 boundSD = symbolTable.get("java.lang.Object"); // TODO: could create a separate unbound type variable singleton class?
242 // System.err.println("Creating dummy SymbolData for bounding type " + typeName + " in inner class " + name);
243 // TODO! !!!!! Create an appropriate fixUp mechanism
244 }
245 // System.err.println("In method " + _enclosing + "." + that.getName().getText() + ", type " + typeName
246 // + " is bound to " + boundSD);
247 _genericTypes.put(typeName, boundSD);
248 }
249 }
250
251 MethodData md = createMethodData(that, _enclosing);
252 String className = getUnqualifiedClassName(_enclosing.getName());
253 if (className.equals(md.getName())) {
254 _addAndIgnoreError("Only constructors can have the same name as the class they appear in, and constructors do "
255 + "not have an explicit return type",
256 that);
257 }
258 else _enclosing.addMethod(md);
259 _genericTypes = oldGenericTypes;
260 return null;
261 }
262
263 /**Call the method in FullJavaVisitor since it's common to this and FullJavaBodyFullJavaVisitor. */
264 public Void forInnerInterfaceDef(InnerInterfaceDef that) {
265 String relName = that.getName().getText();
266 handleInnerInterfaceDef(that, _enclosing, relName, getQualifiedClassName(_enclosing.getName()) + '.' + relName);
267 return null;
268 }
269
270 /**Call the method in FullJavaVisitor since it's common to this and FullJavaBodyFullJavaVisitor. */
271 public Void forInnerClassDef(InnerClassDef that) {
272 String relName = that.getName().getText();
273 handleInnerClassDef(that, _enclosing, relName, getQualifiedClassName(_enclosing.getName()) + '.' + relName);
274 return null;
275 }
276
277 /** Create a constructor corresponding to the specifications in the ConstructorDef, and then
278 * visit the constructor body, passing the constructor as the enclosing data.
279 */
280 public Void forConstructorDef(ConstructorDef that) {
281 forConstructorDefDoFirst(that);
282 if (prune(that)) return null;
283
284 that.getMav().visit(this);
285 String name = getUnqualifiedClassName(that.getName().getText());
286 if ((that.getName().getText().indexOf('.') != -1 && ! that.getName().getText().equals(_enclosing.getName()))
287 || ! name.equals(getUnqualifiedClassName(_enclosing.getName()))) {
288 _addAndIgnoreError("The constructor return type and class name must match", that);
289 }
290
291 // Turn the thrown exceptions from a ReferenceType[] to a String[]
292 String[] throwStrings = referenceType2String(that.getThrows());
293
294 SymbolData returnType = _enclosing;
295 MethodData md = MethodData.make(name, that.getMav(), new TypeParameter[0], returnType,
296 new VariableData[0], throwStrings, _enclosing, that); // VariableData is dummy
297
298 _checkError(); // reset check flag
299 // Turn the parameters from a FormalParameterList to a VariableData[]
300 VariableData[] vds = formalParameters2VariableData(that.getParameters(), _enclosing);
301 if (! _checkError()) { //if there was an error converting the formalParameters, don't use them.
302 md.setParams(vds);
303 if (!md.addVars(vds)) {
304 _addAndIgnoreError("You cannot have two method parameters with the same name", that);
305 }
306 }
307
308 _enclosing.addMethod(md);
309 that.getStatements().visit(new BodyBodyFullJavaVisitor(md, _file, _package, _enclosingClassName, _importedFiles,
310 _importedPackages, _classesInThisFile, continuations, fixUps,
311 new HashSet<String>()));
312
313 //note that we have seen a constructor.
314 _enclosing.incrementConstructorCount();
315 return null;
316 }
317
318 /** Delegate to method in LanguageLevelVisitor */
319 public Void forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation that) {
320 complexAnonymousClassInstantiationHelper(that, _enclosing); // TODO: the wrong enclosing context?
321 return null;
322 }
323
324 /**Delegate to method in LanguageLevelVisitor */
325 public Void forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation that) {
326 simpleAnonymousClassInstantiationHelper(that, _enclosing);
327 return null;
328 }
329
330 /** Check for problems with modifiers that are specific to method definitions. */
331 public Void forModifiersAndVisibilityDoFirst(ModifiersAndVisibility that) {
332 String[] modifiers = that.getModifiers();
333 // System.err.println("***Checking for bad modifers in " + Arrays.toString(modifiers) + " isAbstact = " +
334 // Utilities.isAbstract(modifiers) + " isStatic = " + Utilities.isStatic(modifiers));
335 if (Utilities.isAbstract(modifiers) && Utilities.isStatic(modifiers)) _badModifiers("static", "abstract", that);
336 return super.forModifiersAndVisibilityDoFirst(that);
337 }
338
339 /** Test the methods that are declared above. */
340 public static class ClassBodyFullJavaVisitorTest extends TestCase {
341
342 private ClassBodyFullJavaVisitor _cbfjv;
343
344 private SymbolData _sd1;
345 private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
346 private ModifiersAndVisibility _protectedMav =
347 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
348 private ModifiersAndVisibility _privateMav =
349 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
350 private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
351 private ModifiersAndVisibility _abstractMav =
352 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
353 private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
354 private ModifiersAndVisibility _staticMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static"});
355 private ModifiersAndVisibility _abstractStaticMav =
356 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract", "static"});
357 private ModifiersAndVisibility _finalStaticMav =
358 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static", "final"});
359
360
361 public ClassBodyFullJavaVisitorTest() { this(""); }
362 public ClassBodyFullJavaVisitorTest(String name) { super(name); }
363
364 public void setUp() {
365 _sd1 = new SymbolData("i.like.monkey"); // creates a continuation
366
367 errors = new LinkedList<Pair<String, JExpressionIF>>();
368 LanguageLevelConverter.symbolTable.clear();
369 LanguageLevelConverter.symbolTable.put("i.like.monkey", _sd1);
370 LanguageLevelConverter._newSDs.clear();
371 visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();
372 // _hierarchy = new Hashtable<String, TypeDefBase>();
373 _cbfjv = new ClassBodyFullJavaVisitor(_sd1,
374 "i.like.monkey",
375 new File(""),
376 "",
377 new LinkedList<String>(),
378 new LinkedList<String>(),
379 new HashSet<String>(),
380 new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
381 new LinkedList<Command>());
382 _cbfjv._classesInThisFile = new HashSet<String>();
383 _cbfjv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(); // no _sd1
384 // _cbfjv._resetNonStaticFields();
385 _cbfjv._importedPackages.addFirst("java.lang");
386
387 _errorAdded = false;
388 }
389
390 public void testForConcreteMethodDefDoFirst() {
391 // Check one that works
392 ConcreteMethodDef cmd = new ConcreteMethodDef(SourceInfo.NONE,
393 _publicMav,
394 new TypeParameter[0],
395 new PrimitiveType(SourceInfo.NONE, "int"),
396 new Word(SourceInfo.NONE, "methodName1"),
397 new FormalParameter[0],
398 new ReferenceType[0],
399 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
400 cmd.visit(_cbfjv);
401 assertEquals("There should not be any errors", 0, errors.size());
402
403 // Check one that doesn't work because it is declared abstract but is actually a concrete method
404 ConcreteMethodDef cmd2 = new ConcreteMethodDef(SourceInfo.NONE,
405 _abstractMav,
406 new TypeParameter[0],
407 new PrimitiveType(SourceInfo.NONE, "double"),
408 new Word(SourceInfo.NONE, "methodName2"),
409 new FormalParameter[0],
410 new ReferenceType[0],
411 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
412 cmd2.visit(_cbfjv);
413 assertEquals("There should be one error", 1, errors.size());
414 assertEquals("The error message should be correct",
415 "Methods that have a braced body cannot be declared \"abstract\"",
416 errors.get(0).getFirst());
417
418 //Check that a static method does not result in an error.
419 ConcreteMethodDef cmd3 = new ConcreteMethodDef(SourceInfo.NONE,
420 _staticMav,
421 new TypeParameter[0],
422 new PrimitiveType(SourceInfo.NONE, "double"),
423 new Word(SourceInfo.NONE, "methodName2"),
424 new FormalParameter[0],
425 new ReferenceType[0],
426 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
427 cmd3.visit(_cbfjv);
428 assertEquals("There should still be one error", 1, errors.size());
429
430
431 }
432
433 public void testForAbstractMethodDefDoFirst() {
434 // Check one that doesn't work
435 AbstractMethodDef amd = new AbstractMethodDef(SourceInfo.NONE,
436 _abstractMav,
437 new TypeParameter[0],
438 new PrimitiveType(SourceInfo.NONE, "int"),
439 new Word(SourceInfo.NONE, "methodName"),
440 new FormalParameter[0],
441 new ReferenceType[0]);
442 amd.visit(_cbfjv);
443 assertEquals("There should be one error.", 1, errors.size());
444 assertEquals("The error message should be correct.", "Abstract methods can only be declared in abstract classes",
445 errors.get(0).getFirst());
446
447 // Check one that works
448 _cbfjv._enclosing.setMav(_abstractMav);
449 AbstractMethodDef amd2 = new AbstractMethodDef(SourceInfo.NONE,
450 _abstractMav,
451 new TypeParameter[0],
452 new PrimitiveType(SourceInfo.NONE, "double"),
453 new Word(SourceInfo.NONE, "methodName"),
454 new FormalParameter[0],
455 new ReferenceType[0]);
456 amd2.visit(_cbfjv);
457 assertEquals("There should still be one error", 1, errors.size());
458
459 // Check that static methods are now allowed at the FullJava level.
460 AbstractMethodDef amd3 = new AbstractMethodDef(SourceInfo.NONE,
461 _abstractStaticMav,
462 new TypeParameter[0],
463 new PrimitiveType(SourceInfo.NONE, "double"),
464 new Word(SourceInfo.NONE, "methodName2"),
465 new FormalParameter[0],
466 new ReferenceType[0]);
467 amd3.visit(_cbfjv);
468 assertEquals("There should be two errors", 2, errors.size());
469 assertEquals("The error message should be correct.",
470 "Illegal combination of modifiers. Can't use static and abstract together.",
471 errors.get(1).getFirst());
472 }
473
474 public void testForInstanceInitializerDoFirst() {
475 InstanceInitializer ii = new InstanceInitializer(SourceInfo.NONE,
476 new Block(SourceInfo.NONE,
477 new BracedBody(SourceInfo.NONE, new BodyItemI[0])));
478 ii.visit(_cbfjv);
479 assertEquals("There should be one error.", 1, errors.size());
480 assertEquals("The error message should be correct.",
481 "This open brace must mark the beginning of a method or class body", errors.get(0).getFirst());
482 }
483
484 public void testForVariableDeclaration() {
485
486 ArrayInitializer ai = new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[0]);
487 TypeVariable tv = new TypeVariable(SourceInfo.NONE, "String");
488 SymbolData _string = LanguageLevelConverter.symbolTable.get("java.lang.String");
489 assertNotNull("java.lang.String already in table", _string);
490 ArrayType at = new ArrayType(SourceInfo.NONE, "String[]", tv);
491
492 VariableDeclarator vd =
493 new UninitializedVariableDeclarator(SourceInfo.NONE, at, new Word(SourceInfo.NONE, "myArray"));
494
495 VariableDeclaration vdecl =
496 new VariableDeclaration(SourceInfo.NONE, _publicMav, new VariableDeclarator[] { vd });
497 assertEquals("There should be no errors", 0, errors.size());
498
499 // System.err.println("*** Beginning traversal of VariableDeclaration with String[]");
500 vdecl.visit(_cbfjv);
501 // System.err.println("Traversal of VariableDeclaration above is complete");
502 assertEquals("There should be no errors", 0, errors.size());
503 // System.err.println("That error is: " + errors.getLast().getFirst());
504
505 SymbolData bob = LanguageLevelConverter.symbolTable.get("java.lang.String[]");
506 // System.err.println("Getting READY to fail");
507 // try { Thread.sleep(1000); } catch (Exception e) { };
508 assertNotNull("bob should not be null", bob);
509 }
510
511 /* These test is shared with BodyIntermediateVisitor, perhaps we could factor it out. */
512
513 public void testForVariableDeclarationOnly() {
514 // Check one that works
515 VariableDeclaration vdecl = new VariableDeclaration(SourceInfo.NONE,
516 _packageMav,
517 new VariableDeclarator[] {
518 new UninitializedVariableDeclarator(SourceInfo.NONE,
519 new PrimitiveType(SourceInfo.NONE, "double"),
520 new Word (SourceInfo.NONE, "field1")),
521 new UninitializedVariableDeclarator(SourceInfo.NONE,
522 new PrimitiveType(SourceInfo.NONE, "boolean"),
523 new Word (SourceInfo.NONE, "field2"))});
524 VariableData vd1 = new VariableData("field1", _packageMav, SymbolData.DOUBLE_TYPE, false, _cbfjv._enclosing);
525 VariableData vd2 = new VariableData("field2", _packageMav, SymbolData.BOOLEAN_TYPE, false, _cbfjv._enclosing);
526 vdecl.visit(_cbfjv);
527 assertEquals("There should not be any errors.", 0, errors.size());
528
529 // System.err.println("_sd1 vars = " + _sd1.getVars());
530 assertTrue("field1 was added.", _sd1.getVars().contains(vd1));
531 assertTrue("field2 was added.", _sd1.getVars().contains(vd2));
532
533 // Check one that doesn't work
534 VariableDeclaration vdecl2 =
535 new VariableDeclaration(SourceInfo.NONE,
536 _packageMav,
537 new VariableDeclarator[] {
538 new UninitializedVariableDeclarator(SourceInfo.NONE,
539 new PrimitiveType(SourceInfo.NONE, "double"),
540 new Word(SourceInfo.NONE, "field3")),
541 new UninitializedVariableDeclarator(SourceInfo.NONE,
542 new PrimitiveType(SourceInfo.NONE, "int"),
543 new Word(SourceInfo.NONE, "field3"))});
544 VariableData vd3 = new VariableData("field3", _packageMav, SymbolData.DOUBLE_TYPE, false, _cbfjv._enclosing);
545 vdecl2.visit(_cbfjv);
546 assertEquals("There should be one error.", 1, errors.size());
547 assertEquals("The error message should be correct",
548 "You cannot have two fields with the same name. Either you already have a field by that name in "
549 + "this class, or one of your superclasses or interfaces has a field by that name",
550 errors.get(0).getFirst());
551 // System.err.println("_sd1 vars = " + _sd1.getVars());
552 assertTrue("field3 was added.", _sd1.getVars().contains(vd3));
553
554 //Check a static field that has not been assigned (won't work)
555 VariableDeclaration vdecl3 = new VariableDeclaration(SourceInfo.NONE,
556 _staticMav,
557 new VariableDeclarator[] {
558 new UninitializedVariableDeclarator(SourceInfo.NONE,
559 new PrimitiveType(SourceInfo.NONE, "double"),
560 new Word (SourceInfo.NONE, "field4"))});
561 // true value for hasAssigned in next line based on default initialization provided by Java. GOOD IDEA?
562 VariableData vd4 = new VariableData("field4", _staticMav, SymbolData.DOUBLE_TYPE, false, _cbfjv._enclosing);
563 vdecl3.visit(_cbfjv);
564 // System.err.println("vd4 = " + vd4);
565 assertEquals("There should still be one error", 1, errors.size());
566 // assertEquals("The error message should be correct", "All static fields must be initialized",
567 // errors.get(1).getFirst());
568 // System.err.println("_sd1 vars = " + _sd1.getVars());
569 assertTrue("field4 was added.", _sd1.getVars().contains(vd4));
570
571 //Check a non-static field that has been assigned. (will work);
572 VariableDeclaration vdecl5 = new VariableDeclaration(SourceInfo.NONE,
573 _publicMav,
574 new VariableDeclarator[] {
575 new InitializedVariableDeclarator(SourceInfo.NONE,
576 new PrimitiveType(SourceInfo.NONE, "double"),
577 new Word(SourceInfo.NONE, "field5"),
578 new DoubleLiteral(SourceInfo.NONE, 2.4))});
579 vdecl5.visit(_cbfjv);
580 VariableData vd5 = new VariableData("field5", _publicMav, SymbolData.DOUBLE_TYPE, true, _cbfjv._enclosing);
581 vd5.setHasInitializer(true);
582 assertEquals("There should still be one error", 1, errors.size());
583 assertTrue("Field 5 was added.", _sd1.getVars().contains(vd5));
584
585 // //check one that overrides the super class's field
586 // VariableDeclaration vdecl6 = new VariableDeclaration(SourceInfo.NONE,
587 // _packageMav,
588 // new VariableDeclarator[] {
589 // new UninitializedVariableDeclarator(SourceInfo.NONE,
590 // new PrimitiveType(SourceInfo.NONE, "double"),
591 // new Word(SourceInfo.NONE, "field6"))});
592 //
593 //
594 // VariableData vd6 = new VariableData("field6", _packageMav, SymbolData.DOUBLE_TYPE, true, _cbfjv._enclosing);
595 // SymbolData myData = new SymbolData("myData");
596 // myData.addVar(vd6);
597 // _cbfjv._enclosing.setSuperClass(myData);
598 // vdecl6.visit(_cbfjv);
599 // assertEquals("There should be two errors.", 2, errors.size());
600 // assertEquals("The error message should be correct",
601 // "You cannot have two fields with the same name. Either you already have a field by that name in "
602 // + "this class, or one of your superclasses or interfaces has a field by that name",
603 // errors.get(1).getFirst());
604
605 }
606
607 public void testFormalParameters2VariableData() {
608 FormalParameter[] fps = new FormalParameter[] {
609 new FormalParameter(SourceInfo.NONE,
610 new UninitializedVariableDeclarator(SourceInfo.NONE,
611 new PrimitiveType(SourceInfo.NONE, "double"),
612 new Word (SourceInfo.NONE, "field1")),
613 false),
614 new FormalParameter(SourceInfo.NONE,
615 new UninitializedVariableDeclarator(SourceInfo.NONE,
616 new PrimitiveType(SourceInfo.NONE, "boolean"),
617 new Word (SourceInfo.NONE, "field2")),
618 false)};
619
620
621 VariableData vd1 = new VariableData("field1", _packageMav, SymbolData.DOUBLE_TYPE, true, _cbfjv._enclosing);
622 VariableData vd2 = new VariableData("field2", _packageMav, SymbolData.BOOLEAN_TYPE, true, _cbfjv._enclosing);
623
624 VariableData[] mVds = new VariableData[] { vd1, vd2 };
625
626 MethodData aMethod = new MethodData("method",
627 _publicMav,
628 new TypeParameter[0],
629 _cbfjv._enclosing,
630 mVds,
631 new String[0],
632 _cbfjv._enclosing,
633 null);
634
635 VariableData[] vds = _cbfjv.formalParameters2VariableData(fps, _cbfjv._enclosing);
636 assertEquals("There should not be any errors.", 0, errors.size());
637 assertEquals("vd1 should be the first entry in vds.", vd1, vds[0]);
638 assertEquals("vd2 should be the second entry in vds.", vd2, vds[1]);
639 }
640
641
642
643
644
645 public void xtestForConcreteMethodDef() {
646 // Test one that works.
647 MethodDef mdef = new ConcreteMethodDef(SourceInfo.NONE,
648 _packageMav,
649 new TypeParameter[0],
650 new PrimitiveType(SourceInfo.NONE, "int"),
651 new Word(SourceInfo.NONE, "methodName"),
652 new FormalParameter[0],
653 new ReferenceType[0],
654 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
655 mdef.visit(_cbfjv);
656 assertEquals("There should not be any errors.", 0, errors.size());
657 // Test one that doesn't work.
658 mdef = new ConcreteMethodDef(SourceInfo.NONE,
659 _packageMav,
660 new TypeParameter[0],
661 new PrimitiveType(SourceInfo.NONE, "int"),
662 new Word(SourceInfo.NONE, "monkey"),
663 new FormalParameter[0],
664 new ReferenceType[0],
665 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
666 mdef.visit(_cbfjv);
667 assertEquals("There should be one error.", 1, errors.size());
668 assertEquals("The error message should be correct.",
669 "Only constructors can have the same name as the class they appear in, and constructors do not have an explicit return type",
670 errors.get(0).getFirst());
671 }
672
673 public void xtestForAbstractMethodDef() {
674 // Test one that works.
675 MethodDef mdef = new AbstractMethodDef(SourceInfo.NONE,
676 _abstractMav,
677 new TypeParameter[0],
678 new PrimitiveType(SourceInfo.NONE, "int"),
679 new Word(SourceInfo.NONE, "methodName"),
680 new FormalParameter[0],
681 new ReferenceType[0]);
682 _cbfjv._enclosing.setMav(_abstractMav);
683 mdef.visit(_cbfjv);
684 assertEquals("There should not be any errors.", 0, errors.size());
685 // Test one that doesn't work.
686 mdef = new AbstractMethodDef(SourceInfo.NONE,
687 _abstractMav,
688 new TypeParameter[0],
689 new PrimitiveType(SourceInfo.NONE, "int"),
690 new Word(SourceInfo.NONE, "monkey"),
691 new FormalParameter[0],
692 new ReferenceType[0]);
693 mdef.visit(_cbfjv);
694 assertEquals("There should be one error.", 1, errors.size());
695 assertEquals("The error message should be correct.",
696 "Only constructors can have the same name as the class they appear in, and constructors do not have an explicit return type",
697 errors.get(0).getFirst());
698 }
699
700
701 public void xtestForInitializedVariableDeclaratorDoFirst() {
702 InitializedVariableDeclarator ivd = new InitializedVariableDeclarator(SourceInfo.NONE,
703 new PrimitiveType(SourceInfo.NONE, "int"),
704 new Word(SourceInfo.NONE, "i"),
705 new IntegerLiteral(SourceInfo.NONE, 2));
706
707 ivd.visit(_cbfjv);
708
709 assertEquals("There should be no errors now", 0, errors.size());
710 }
711
712 public void xtestForInnerClassDef() {
713 SymbolData obj = new SymbolData("java.lang.Object");
714 LanguageLevelConverter.symbolTable.put("java.lang.Object", obj);
715 InnerClassDef cd1 = new InnerClassDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Bart"),
716 new TypeParameter[0], new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]), new ReferenceType[0],
717 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
718 InnerClassDef cd0 = new InnerClassDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Lisa"),
719 new TypeParameter[0], new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]), new ReferenceType[0],
720 new BracedBody(SourceInfo.NONE, new BodyItemI[] {cd1}));
721
722
723 SymbolData sd0 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa", _packageMav, new TypeParameter[0], obj,
724 new ArrayList<SymbolData>(), null);
725 _cbfjv._enclosing.addInnerClass(sd0);
726 sd0.setOuterData(_cbfjv._enclosing);
727 SymbolData sd1 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa$Bart", _packageMav, new TypeParameter[0],
728 obj, new ArrayList<SymbolData>(), null);
729 sd0.addInnerClass(sd1);
730 sd1.setOuterData(sd0);
731
732 sd0.setIsContinuation(true);
733 sd1.setIsContinuation(true);
734
735
736
737 LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa", sd0);
738 // LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa$Bart", sd1);
739
740 cd0.visit(_cbfjv);
741
742 // sd0.setName("Lisa");
743 // sd1.setName("Bart");
744
745 SymbolData sd = _cbfjv._enclosing.getInnerClassOrInterface("Lisa");
746 assertEquals("There should be no errors", 0, errors.size());
747 assertEquals("This symbolData should now have sd0 as an inner class", sd0, sd);
748 assertEquals("sd0 should have the correct outer data", _cbfjv._enclosing, sd0.getOuterData());
749 assertEquals("sd1 should have the correct outer data", sd0, sd1.getOuterData());
750 assertEquals("Sd should now have sd1 as an inner class", sd1, sd.getInnerClassOrInterface("Bart"));
751
752
753 assertEquals("Lisa should have 0 methods", 0, sd0.getMethods().size());
754
755 }
756
757 public void xtestForInnerInterfaceDef() {
758 // SymbolData obj = new SymbolData("java.lang.Object");
759 // LanguageLevelConverter.symbolTable.put("java.lang.Object", obj);
760 InnerInterfaceDef cd1 = new InnerInterfaceDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Bart"),
761 new TypeParameter[0], new ReferenceType[0],
762 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
763
764 InnerInterfaceDef cd0 = new InnerInterfaceDef(SourceInfo.NONE, _packageMav, new Word(SourceInfo.NONE, "Lisa"),
765 new TypeParameter[0], new ReferenceType[0],
766 new BracedBody(SourceInfo.NONE, new BodyItemI[] {cd1}));
767
768 SymbolData sd0 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa", _packageMav, new TypeParameter[0],
769 new ArrayList<SymbolData>(), null);
770 SymbolData sd1 = new SymbolData(_cbfjv._enclosing.getName() + "$Lisa$Bart", _packageMav, new TypeParameter[0],
771 new ArrayList<SymbolData>(), null);
772 sd0.addInnerInterface(sd1);
773 sd0.setIsContinuation(true);
774 sd1.setIsContinuation(true);
775
776 _cbfjv._enclosing.addInnerInterface(sd0);
777 sd0.setOuterData(_cbfjv._enclosing);
778
779 sd0.addInnerInterface(sd1);
780 sd1.setOuterData(sd0);
781
782 //
783 // LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa", sd0);
784 // LanguageLevelConverter.symbolTable.put(_cbfjv._enclosing.getName() + "$Lisa$Bart", sd1);
785
786 cd0.visit(_cbfjv);
787
788 SymbolData sd = _cbfjv._enclosing.getInnerClassOrInterface("Lisa");
789
790 assertEquals("There should be no errors", 0, errors.size());
791 assertEquals("This symbolData should now have sd0 as an inner interface", sd0, sd);
792 assertEquals("sd0 should have the correct outer data", _cbfjv._enclosing, sd0.getOuterData());
793 assertEquals("sd1 should have the correct outer data", sd0, sd1.getOuterData());
794 assertEquals("Sd should now have sd1 as an inner interface", sd1, sd.getInnerClassOrInterface("Bart"));
795 assertTrue("Lisa should be an interface", sd0.isInterface());
796 assertTrue("Bart should be an interface", sd1.isInterface());
797
798
799 }
800
801 public void xtestForConstructorDef() {
802 //this is a ConstructorDef with no formal parameters and no throws
803 ConstructorDef cd = new ConstructorDef(SourceInfo.NONE, new Word(SourceInfo.NONE, "MyClass"), _publicMav, new FormalParameter[0], new ReferenceType[0],
804 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
805
806 //What if constructor name and SymbolData name don't match? Should throw an error.
807 _cbfjv._enclosing = new SymbolData("NotRightName");
808 cd.visit(_cbfjv);
809 assertEquals("Should be 1 error", 1, errors.size());
810 assertEquals("Error message should be correct", "The constructor return type and class name must match", errors.getLast().getFirst());
811
812 //If they are the same, it should work just fine.
813 _cbfjv._enclosing = new SymbolData("MyClass");
814
815 MethodData constructor = new MethodData("MyClass",
816 _publicMav,
817 new TypeParameter[0],
818 _cbfjv._enclosing,
819 new VariableData[0],
820 new String[0],
821 _cbfjv._enclosing,
822 null);
823
824
825 cd.visit(_cbfjv);
826
827
828 assertEquals("Should still be 1 error", 1, errors.size());
829 assertEquals("SymbolData should have 1 method", 1, _cbfjv._enclosing.getMethods().size());
830 assertTrue("SymbolData's constructor should be correct", _cbfjv._enclosing.getMethods().contains(constructor));
831
832 //With a ConstructorDef with more throws and variables, should work okay.
833 FormalParameter fp =
834 new FormalParameter(SourceInfo.NONE,
835 new UninitializedVariableDeclarator(SourceInfo.NONE,
836 new PrimitiveType(SourceInfo.NONE, "int"),
837 new Word(SourceInfo.NONE, "i")),
838 false);
839 ReferenceType rt = new TypeVariable(SourceInfo.NONE, "MyMadeUpException");
840 ConstructorDef cd2 =
841 new ConstructorDef(SourceInfo.NONE,
842 new Word(SourceInfo.NONE, "MyClass"),
843 _publicMav,
844 new FormalParameter[] {fp},
845 new ReferenceType[] {rt},
846 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
847
848 VariableData vd = new VariableData("i", _finalMav, SymbolData.INT_TYPE, true, null);
849 MethodData constructor2 = new MethodData("MyClass", _publicMav, new TypeParameter[0], _cbfjv._enclosing,
850 new VariableData[] {vd},
851 new String[] {"MyMadeUpException"},
852 _cbfjv._enclosing,
853 null);
854
855
856
857 constructor2.addVar(vd);
858 cd2.visit(_cbfjv);
859 vd.setEnclosingData(_cbfjv._enclosing.getMethods().getLast());
860 assertEquals("Should still be 1 error", 1, errors.size());
861 assertEquals("SymbolData should have 2 methods", 2, _cbfjv._enclosing.getMethods().size());
862
863 assertTrue("SymbolData should have new constructor", _cbfjv._enclosing.getMethods().contains(constructor2));
864
865
866 //If two variable names are duplicated, should throw an error.
867 FormalParameter fp2 =
868 new FormalParameter(SourceInfo.NONE,
869 new UninitializedVariableDeclarator(SourceInfo.NONE,
870 new PrimitiveType(SourceInfo.NONE, "double"),
871 new Word(SourceInfo.NONE, "i")),
872 false);
873
874 ConstructorDef cd3 =
875 new ConstructorDef(SourceInfo.NONE,
876 new Word(SourceInfo.NONE, "MyClass"),
877 _publicMav,
878 new FormalParameter[] {fp, fp2},
879 new ReferenceType[] {rt},
880 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
881 cd3.visit(_cbfjv);
882
883 assertEquals("Should now be 2 errors", 2, errors.size());
884 assertEquals("Error message should be correct","You cannot have two method parameters with the same name" ,
885 errors.getLast().getFirst());
886
887 //Test that an error is thrown if the class name and constructor name are packaged differently
888 _cbfjv._enclosing.setName("package.MyClass2");
889 ConstructorDef cd4 =
890 new ConstructorDef(SourceInfo.NONE,
891 new Word(SourceInfo.NONE, "different.MyClass2"),
892 _publicMav,
893 new FormalParameter[0],
894 new ReferenceType[0],
895 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
896 cd4.visit(_cbfjv);
897
898 assertEquals("There should now be 3 errors", 3, errors.size());
899 assertEquals("Error message should be correct", "The constructor return type and class name must match", errors.getLast().getFirst());
900 }
901 public void testDummy() { }
902 }
903 }