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 /** Language Level Visitor for the Intermediate Language Level. Enforces constraints during the
048 * first walk of the AST (checking for language specific errors and building the symbol table).
049 * This class enforces things that are common to all contexts reachable within a method body or other body
050 * (not class or interface body) at the Intermediate Language Level).
051 */
052 public class BodyBodyIntermediateVisitor extends IntermediateVisitor {
053
054 /**The MethodData of this method.*/
055 private BodyData _bodyData;
056
057 /** Constructor for BodyBodyElementaryVisitor.
058 * @param bodyData The BodyData that encloses the context we are visiting.
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
065 * to be resolved
066 * @param fixUps A list of commands to be performed after this pass to fixup the symbolTable
067 */
068 public BodyBodyIntermediateVisitor(BodyData bodyData,
069 File file,
070 String packageName,
071 String enclosingClassName,
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 HashSet<String> innerClassesInThisBody) {
078 super(file,
079 packageName,
080 enclosingClassName,
081 importedFiles,
082 importedPackages,
083 classesInThisFile,
084 continuations,
085 fixUps);
086 _bodyData = bodyData;
087 assert _enclosingClassName != null;
088 // _innerClassesInThisBody = innerClassesInThisBody;
089 }
090
091 /** Give an appropriate error */
092 public Void forMethodDefDoFirst(MethodDef that) {
093 _addError("Methods definitions cannot appear within the body of another method or block.", that);
094 return null;
095 }
096
097 /* There is currently no way to differentiate between a block statement and
098 * an instance initializer in a braced body given the general nature of a
099 * braced body. Whenever an instance initialization is visited in a method
100 * body, we must assume that it is a block statement.
101 */
102 public Void forInstanceInitializer(InstanceInitializer that) {
103 return forBlock(that.getCode());
104 }
105
106 /* Visit this Block within the same BlockData with a new BodyBodyIntermediate visitor (to deal with new local scope?)
107 * after making sure no errors need to be thrown.*/
108 public Void forBlock(Block that) {
109 forBlockDoFirst(that);
110 if (prune(that)) return null;
111 // The following code is incomprehensible. Why mutate _bodyData? Why create bd?
112 BlockData bd = new BlockData(_bodyData);
113 _bodyData.addBlock(bd);
114 that.getStatements().visit(new BodyBodyIntermediateVisitor(bd, _file, _package, _enclosingClassName, _importedFiles,
115 _importedPackages, _classesInThisFile, continuations,
116 fixUps, new HashSet<String>()));
117 return forBlockOnly(that);
118 }
119
120 /** Visit the block as in forBlock(), but first add the exception parameter as a variable in that
121 * lock.
122 * TODO: move this method into LanguageLevelVisitor. */
123 public Void forCatchBlock(CatchBlock that) {
124 // System.err.println("***ALARM*** BodyBodyIntermediateVisitor is visiting catch block");
125 forCatchBlockDoFirst(that);
126 if (prune(that)) return null;
127
128 Block b = that.getBlock();
129 forBlockDoFirst(b);
130 if (prune(b)) return null;
131 BlockData bd = new BlockData(_bodyData);
132 _bodyData.addBlock(bd);
133
134 SymbolData enclosing = getQualifiedSymbolData(_enclosingClassName);
135
136 VariableData exceptionVar =
137 formalParameters2VariableData(new FormalParameter[]{ that.getException() }, enclosing)[0]; // !!!!!! Wny not bd?
138 if (prune(that.getException())) return null;
139 bd.addVar(exceptionVar);
140
141 // System.err.println("Visiting augmented catch block with new visitor!");
142 BodyBodyIntermediateVisitor bbijv =
143 new BodyBodyIntermediateVisitor(bd, _file, _package, _enclosingClassName, _importedFiles,
144 _importedPackages, _classesInThisFile, continuations, fixUps,
145 new HashSet<String>());
146 b.getStatements().visit(bbijv);
147 forBlockOnly(b);
148 return forCatchBlockOnly(that);
149 }
150
151 /** Adds the variables that were declared to the body data and make sure that no two variables have the same name.*/
152 public Void forVariableDeclarationOnly(VariableDeclaration that) {
153 if (! _bodyData.addFinalVars(_variableDeclaration2VariableData(that, _bodyData))) {
154 /* Does not allow repeated use of a for loop index variable. TODO: fix this. */
155 // System.err.println("Generating duplicate variable error");
156 _addAndIgnoreError("You cannot have two variables with the same name.", that);
157 }
158 return null;
159 }
160
161 // /** Override method in IntermediateVisitor that throws an error here.*/
162 // public Void forTryCatchStatementDoFirst(TryCatchStatement that) { return null; /* No errors to throw here. */ }
163
164 /** Process a local inner class definition */
165 public Void forInnerClassDef(InnerClassDef that) {
166 // TODO: is this necessarily local?
167 SymbolData enclosingClass = _bodyData.getSymbolData();
168 assert _enclosingClassName != null;
169 assert enclosingClass != null;
170 assert _enclosingClassName.equals(getQualifiedClassName(enclosingClass.getName()));
171
172 String relName = that.getName().getText();
173 String fullName = _enclosingClassName + '$' + enclosingClass.preincrementLocalClassNum() + relName;
174 // System.err.println("***ALARM*** Processing local class '" + relName + "' in class " + _enclosingClassName
175 // + " with flattened class name " + fullName);
176 handleInnerClassDef(that, _bodyData, relName, fullName);
177 // How do we know that generated number is correct?
178 return null;
179 }
180
181 /** Process a local inner interface definition */
182 public Void forInnerInterfaceDef(InnerInterfaceDef that) {
183 // System.err.println("***Signalling local interface error");
184 _addAndIgnoreError("Local interfaces are illegal in Java.", that);
185 // handleInnerInterfaceDef(that, _bodyData, getQualifiedClassName(_bodyData.getSymbolData().getName()) + '.' +
186 // _bodyData.getSymbolData().preincrementLocalClassNum() + that.getName().getText());
187 // // How do we know that generated number is correct?
188 return null;
189 }
190
191 /** Delegate to helper method. */
192 public Void forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation that) {
193 SymbolData enclosing = getQualifiedSymbolData(_enclosingClassName);
194 assert enclosing != null;
195 simpleAnonymousClassInstantiationHelper(that, enclosing);
196 return null;
197 }
198
199 /** Delegate to helper method. */
200 public Void forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation that) {
201 SymbolData enclosing = getQualifiedSymbolData(_enclosingClassName);
202 assert enclosing != null;
203 complexAnonymousClassInstantiationHelper(that, enclosing); // TODO: the wrong enclosing context?
204 return null;
205 }
206
207 /** If this is the body of a constructor, referencing 'this' is illegal. So, check to see if this is a constructor,
208 * and if so, throw an error. This should catch both the ComplexThisReference and the SimpleThisReference case.
209 */
210 //TODO: it might be nice to create a ConstructorBodyIntermediateVisitor, so this check is not necessary here.
211 public Void forThisReferenceDoFirst(ThisReference that) {
212 if (isConstructor(_bodyData)) {
213 _addAndIgnoreError("You cannot reference the field 'this' inside a constructor at the Intermediate Level", that);
214 }
215 return null;
216 }
217
218 /** Process a local variable declaration within a method. Calls the super method to convert these to a VariableData
219 * array, then makes sure that each VariableData is set to be final, as required at the Intermediate level.
220 * @param enclosingData The Data which contains the variables
221 */
222 protected VariableData[] _variableDeclaration2VariableData(VariableDeclaration vd, Data enclosingData) {
223 VariableData[] vds = super._variableDeclaration2VariableData(vd, enclosingData);
224 for (int i = 0; i < vds.length; i++) {
225 if (vds[i].getMav().getModifiers().length > 0) {
226 StringBuilder s = new StringBuilder("the keyword(s) ");
227 String[] modifiers = vds[i].getMav().getModifiers();
228 for (String m: modifiers) { if (! m.equals("final")) s.append("\"" + m + "\" "); }
229 _addAndIgnoreError("You cannot use " + s + "to declare a local variable", vd);
230 }
231 if (! vds[i].isFinal()) vds[i].setFinal();
232 vds[i].setIsLocalVariable(true); // Was commented out. Why ????
233 }
234 // System.err.println("Return VariableDatas " + vds);
235 return vds;
236 }
237
238 // /** Check for problems with modifiers that are specific to method definitions. */
239 // public Void forModifiersAndVisibilityDoFirst(ModifiersAndVisibility that) {
240 // String[] modifiers = that.getModifiers();
241 // if (Utilities.isAbstract(modifiers) && Utilities.isStatic(modifiers)) _badModifiers("static", "abstract", that);
242 // return super.forModifiersAndVisibilityDoFirst(that);
243 // }
244
245 /** Test most of the methods declared above right here: */
246 public static class BodyBodyIntermediateVisitorTest extends TestCase {
247
248 private BodyBodyIntermediateVisitor _bbv;
249
250 private SymbolData _sd1;
251 private MethodData _md1;
252 private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
253 private ModifiersAndVisibility _protectedMav =
254 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
255 private ModifiersAndVisibility _privateMav =
256 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
257 private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
258 private ModifiersAndVisibility _abstractMav =
259 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
260 private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
261
262
263 public BodyBodyIntermediateVisitorTest() { this(""); }
264
265 public BodyBodyIntermediateVisitorTest(String name) { super(name); }
266
267 public void setUp() {
268 _sd1 = new SymbolData("ILikeMonkey");
269 _sd1.setIsContinuation(false);
270
271 _md1 = new MethodData("methodName",
272 _publicMav,
273 new TypeParameter[0],
274 SymbolData.INT_TYPE,
275 new VariableData[0],
276 new String[0],
277 _sd1,
278 null);
279
280 errors = new LinkedList<Pair<String, JExpressionIF>>();
281 LanguageLevelConverter.symbolTable.clear();
282 LanguageLevelConverter._newSDs.clear();
283 LanguageLevelConverter.symbolTable.put("ILikeMonkey", _sd1);
284 visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, edu.rice.cs.javalanglevels.tree.SourceFile>>();
285 // _hierarchy = new Hashtable<String, TypeDefBase>();
286
287 _bbv =
288 new BodyBodyIntermediateVisitor(_md1,
289 new File(""),
290 "",
291 "ILikeMonkey",
292 new LinkedList<String>(),
293 new LinkedList<String>(),
294 new HashSet<String>(),
295 new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
296 new LinkedList<Command>(),
297 new HashSet<String>());
298
299 _bbv._classesInThisFile = new HashSet<String>();
300 _bbv.continuations = new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
301 // _bbv._resetNonStaticFields();
302 _bbv._importedPackages.addFirst("java.lang");
303 _sd1.setSuperClass(_bbv.getQualifiedSymbolData("java.lang.Object"));
304
305 _errorAdded = false;
306 }
307
308 public void testForMethodDefDoFirst() {
309 ConcreteMethodDef cmd = new ConcreteMethodDef(SourceInfo.NONE,
310 _packageMav,
311 new TypeParameter[0],
312 new PrimitiveType(SourceInfo.NONE, "int"),
313 new Word(SourceInfo.NONE, "methodName"),
314 new FormalParameter[0],
315 new ReferenceType[0],
316 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
317 cmd.visit(_bbv);
318 assertEquals("There should be one error.", 1, errors.size());
319 assertEquals("The error message should be correct.",
320 "Methods definitions cannot appear within the body of another method or block.",
321 errors.get(0).getFirst());
322 }
323
324 /* These last two tests are shared with ClassBodyIntermediateVisitor, perhaps we could factor them out. */
325
326 public void testForVariableDeclarationOnly() {
327 // Check one that works
328 VariableDeclaration vdecl = new VariableDeclaration(SourceInfo.NONE,
329 _packageMav,
330 new VariableDeclarator[] {
331 new UninitializedVariableDeclarator(SourceInfo.NONE,
332 new PrimitiveType(SourceInfo.NONE, "double"),
333 new Word (SourceInfo.NONE, "field1")),
334 new UninitializedVariableDeclarator(SourceInfo.NONE,
335 new PrimitiveType(SourceInfo.NONE, "boolean"),
336 new Word (SourceInfo.NONE, "field2"))});
337 VariableData vd1 = new VariableData("field1", _finalMav, SymbolData.DOUBLE_TYPE, false, _bbv._bodyData);
338 VariableData vd2 = new VariableData("field2", _finalMav, SymbolData.BOOLEAN_TYPE, false, _bbv._bodyData);
339 vdecl.visit(_bbv);
340 // if (errors.size() > 0) System.err.println("Error was:" + errors.get(0).getFirst());
341 assertEquals("There should not be any errors.", 0, errors.size());
342 assertTrue("field1 was added.", _md1.getVars().contains(vd1));
343 assertTrue("field2 was added.", _md1.getVars().contains(vd2));
344
345 // Check one that doesn't work
346 VariableDeclaration vdecl2 = new VariableDeclaration(SourceInfo.NONE,
347 _packageMav,
348 new VariableDeclarator[] {
349 new UninitializedVariableDeclarator(SourceInfo.NONE,
350 new PrimitiveType(SourceInfo.NONE, "double"),
351 new Word (SourceInfo.NONE, "field3")),
352 new UninitializedVariableDeclarator(SourceInfo.NONE,
353 new PrimitiveType(SourceInfo.NONE, "int"),
354 new Word (SourceInfo.NONE, "field3"))});
355 VariableData vd3 = new VariableData("field3", _finalMav, SymbolData.DOUBLE_TYPE, false, _bbv._bodyData);
356 vdecl2.visit(_bbv);
357 assertEquals("There should be one error.", 1, errors.size());
358 assertEquals("The error message should be correct", "You cannot have two variables with the same name.",
359 errors.get(0).getFirst());
360 assertTrue("field3 was added.", _md1.getVars().contains(vd3));
361 }
362
363 // public void testForOtherExpressionOnly() {
364 // // Test that if the OtherExpressino contains a Word, that the Word is resolved.
365 // assertFalse("java.lang.System should not be in the symbolTable.",
366 // LanguageLevelConverter.symbolTable.containsKey("java.lang.System"));
367 // Expression ex =
368 // new Expression( SourceInfo.NONE,
369 // new ExpressionPiece[] { new OtherExpression(SourceInfo.NONE,
370 // new Word(SourceInfo.NONE, "System"))});
371 // ex.visit(_bbv);
372 ////// System.out.println(errors.get(0).getFirst());
373 //// for (int i = 0; i < errors.size(); i++)
374 //// System.out.println(errors.get(i).getFirst());
375 // assertEquals("There should not be any errors.", 0, errors.size());
376 // assertTrue("java.lang.System should be in the symbolTable.",
377 // LanguageLevelConverter.symbolTable.containsKey("java.lang.System"));
378 // }
379
380 /** Generate a block containing a bitwise or operation and the specified SourceInfo si. Note: we need
381 * to generate error blocks with distinct literal data to avoid generating duplicate error messages
382 * which are suppressed in the cumulative errors table. */
383 private Block _generateErrorBlock(int litValue) {
384 final SourceInfo si = SourceInfo.NONE;
385 BracedBody errorBody = new BracedBody(si, new BodyItemI[] {
386 new ExpressionStatement(si,
387 new BitwiseOrExpression(si,
388 new SimpleNameReference(si,
389 new Word(si, "i")),
390 new IntegerLiteral(si, litValue)))});
391 return new Block(si, errorBody);
392 }
393
394
395 public void testForTryCatchStatement() {
396 //Make sure that no error is thrown
397 BracedBody emptyBody = new BracedBody(SourceInfo.NONE, new BodyItemI[0]);
398 Block b = new Block(SourceInfo.NONE, emptyBody);
399
400 NormalTryCatchStatement ntcs = new NormalTryCatchStatement(SourceInfo.NONE, b, new CatchBlock[0]);
401 TryCatchFinallyStatement tcfs = new TryCatchFinallyStatement(SourceInfo.NONE, b, new CatchBlock[0], b);
402 ntcs.visit(_bbv);
403 tcfs.visit(_bbv);
404 assertEquals("After visiting both NormalTryCatchStatement and TryCatchFinallyStatement, there should be no "
405 + "errors", 0, errors.size());
406
407 // //make sure that if there is an error in one of the bodies, it is caught:
408 // BracedBody errorBody = new BracedBody(SourceInfo.NONE, new BodyItemI[] {
409 // new ExpressionStatement(SourceInfo.NONE,
410 // new BitwiseOrExpression(SourceInfo.NONE,
411 // new SimpleNameReference(SourceInfo.NONE,
412 // new Word(SourceInfo.NONE, "i")),
413 // new IntegerLiteral(SourceInfo.NONE, 10)))});
414 // Block errorBlock = new Block(SourceInfo.NONE, errorBody);
415
416 // assert ! SourceInfo.TEST_0.equals(SourceInfo.TEST_1);
417 ntcs = new NormalTryCatchStatement(SourceInfo.TEST_0, _generateErrorBlock(0), new CatchBlock[0]);
418 ntcs.visit(_bbv);
419 assertEquals("Should be one error", 1, errors.size());
420 assertEquals("Error message should be correct",
421 "Bitwise or expressions cannot be used in the functional language level. "
422 + "Perhaps you meant to compare two values using regular or (||)",
423 errors.getLast().getFirst());
424
425 //make sure that if there is an error in one of the catch statements, it is caught:
426 UninitializedVariableDeclarator uvd =
427 new UninitializedVariableDeclarator(SourceInfo.TEST_1,
428 new PrimitiveType(SourceInfo.TEST_1, "int"),
429 new Word(SourceInfo.TEST_1, "i"));
430 FormalParameter fp = new FormalParameter(SourceInfo.TEST_1, uvd, false);
431
432 tcfs = new TryCatchFinallyStatement(SourceInfo.TEST_1, b, new CatchBlock[] {
433 new CatchBlock(SourceInfo.TEST_1, fp, _generateErrorBlock(1))
434 }, b);
435
436 assertEquals("Should be one error", 1, errors.size());
437 tcfs.visit(_bbv);
438 assertEquals("Should be two errors", 2, errors.size());
439 assertEquals("Error message should be correct",
440 "Bitwise or expressions cannot be used in the functional language level."
441 + " Perhaps you meant to compare two values using regular or (||)",
442 errors.getLast().getFirst());
443 }
444
445 public void testForThisReferenceDoFirst() {
446 SimpleThisReference str = new SimpleThisReference(SourceInfo.NONE);
447 ComplexThisReference ctr =
448 new ComplexThisReference(SourceInfo.NONE,
449 new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "field")));
450
451 //if a this reference occurs outside of a constructor, no error
452 _bbv._bodyData = _md1;
453 str.visit(_bbv);
454 ctr.visit(_bbv);
455 assertEquals("Should be no errors", 0, errors.size());
456
457
458 //if a this reference occurs in a constructor, give an error
459 MethodData constr = new MethodData("ILikeMonkey", _publicMav, new TypeParameter[0], _sd1,
460 new VariableData[0],
461 new String[0],
462 _sd1,
463 null);
464 _bbv._bodyData = constr;
465 str.visit(_bbv);
466 assertEquals("Should be 1 error", 1, errors.size());
467 assertEquals("Error message should be correct",
468 "You cannot reference the field 'this' inside a constructor at the Intermediate Level",
469 errors.getLast().getFirst());
470
471 ctr.visit(_bbv);
472 assertEquals("Should be 2 errors", 2, errors.size());
473 assertEquals("Error message should be correct",
474 "You cannot reference the field 'this' inside a constructor at the Intermediate Level",
475 errors.getLast().getFirst());
476
477
478 }
479
480 public void testForInnerClassDef() {
481
482 // Test a local inner class definition and reference
483 SymbolData obj = new SymbolData("ILikeMonkey");
484 LanguageLevelConverter.symbolTable.put("ILikeMonkey", obj);
485 InnerClassDef cd0 =
486 new InnerClassDef(SourceInfo.NONE,
487 _packageMav,
488 new Word(SourceInfo.NONE, "Rod"),
489 new TypeParameter[0],
490 new ClassOrInterfaceType(SourceInfo.NONE, "ILikeMonkey", new Type[0]),
491 new ReferenceType[0],
492 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
493 cd0.visit(_bbv);
494 assertEquals("There should be no errors", 0, errors.size());
495 SymbolData innerClass1 = _bbv._bodyData.getInnerClassOrInterface("Rod");
496 assertNotNull("Should have a inner class named Rod", innerClass1);
497
498 // Test one with explicit modifiers
499 InnerClassDef cd1 =
500 new InnerClassDef(SourceInfo.NONE,
501 _publicMav,
502 new Word(SourceInfo.NONE, "Todd"),
503 new TypeParameter[0],
504 new ClassOrInterfaceType(SourceInfo.NONE, "ILikeMonkey", new Type[0]),
505 new ReferenceType[0],
506 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
507 cd1.visit(_bbv);
508 assertEquals("There should be no errors", 0, errors.size()); // modifiers are allowed
509 SymbolData innerClass2 = _bbv._bodyData.getInnerClassOrInterface("Todd");
510 assertNotNull("Should have a inner class named Todd", innerClass2);
511 }
512
513 public void testForInnerInterfaceDef() {
514 //Test a trivial inner interface definition
515 InnerInterfaceDef iid =
516 new InnerInterfaceDef(SourceInfo.NONE,
517 _packageMav,
518 new Word(SourceInfo.NONE, "Broken"),
519 new TypeParameter[0],
520 new ReferenceType[0],
521 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
522 iid.visit(_bbv);
523 assertEquals("There should be one error", 1, errors.size());
524 assertEquals("The error message should be correct",
525 "Local interfaces are illegal in Java.", errors.get(0).getFirst());
526 SymbolData innerInterface = _bbv._bodyData.getInnerClassOrInterface("Broken");
527 assertNull("Should NOT have a inner interface named Broken", innerInterface);
528
529 // Test a inner interface definition and reference
530 InnerInterfaceDef id0 =
531 new InnerInterfaceDef(SourceInfo.NONE,
532 _packageMav,
533 new Word(SourceInfo.NONE, "RodInterface"),
534 new TypeParameter[0],
535 new ReferenceType[0],
536 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
537 id0.visit(_bbv);
538 assertEquals("There should be 2 errors", 2, errors.size());
539 assertEquals("The error message should be correct",
540 "Local interfaces are illegal in Java.", errors.get(1).getFirst());
541 innerInterface = _bbv._bodyData.getInnerClassOrInterface("RodInterface");
542 assertNull("Should NOT have a inner interface named RodInterface", innerInterface);
543
544 // Test one with explicit modifiers
545 InnerInterfaceDef id1 =
546 new InnerInterfaceDef(SourceInfo.NONE,
547 _publicMav,
548 new Word(SourceInfo.NONE, "Todd"),
549 new TypeParameter[0],
550 new ReferenceType[0],
551 new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
552 id1.visit(_bbv);
553 assertEquals("There should be three errors", 3, errors.size()); // class modifiers are allowed
554 assertEquals("The error message should be correct",
555 "Local interfaces are illegal in Java.", errors.get(2).getFirst());
556 innerInterface = _bbv._bodyData.getInnerClassOrInterface("Todd");
557 assertNull("Should NOT have a inner interface named Todd", innerInterface);
558 }
559
560 public void testDummy() { }
561 }
562 }