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 package edu.rice.cs.javalanglevels;
037
038 import edu.rice.cs.javalanglevels.tree.*;
039 import edu.rice.cs.javalanglevels.parser.JExprParser;
040 import java.util.*;
041
042 import junit.framework.TestCase;
043
044 import edu.rice.cs.plt.reflect.JavaVersion;
045
046 /** Represents the data for a given class. There are two states of SymbolData. One is a continuation which
047 * is created when a type is referenced, but the corresponding class has not been read for its members. The
048 * other is a complete SymbolData containing all of the member data.
049 */
050 public class SymbolData extends TypeData {
051
052 /***************Singleton primitive SymbolDatas********************/
053
054 /** This anonymous class represents the boolean primitive type */
055 public static final SymbolData BOOLEAN_TYPE = new PrimitiveData("boolean") {
056
057 /** You can only cast a boolean primitive to a boolean primitive or a Boolean object (in 1.5). */
058 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
059 return isAssignableTo(castTo, version);
060 }
061
062 /** Returns true if the specified SymbolData is a boolean type. */
063 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
064 if (toCheck == null) return false;
065 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !toCheck.isPrimitiveType()) {
066 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Boolean");
067 return (autoBoxMe != null && autoBoxMe.isAssignableTo(toCheck, version));
068 }
069 return toCheck == BOOLEAN_TYPE;
070 }
071 };
072
073 /** This anonymous class represents the char primitive type. */
074 public static final SymbolData CHAR_TYPE = new PrimitiveData("char") {
075
076 /** You can cast a char to a char, int, long, float, double or short or byte or Character object (in 1.5) */
077 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
078 return isAssignableTo(castTo, version) || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
079 }
080
081 /** You can assign a char primitive to a char, int, long, float, double or Character object (in 1.5) */
082 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
083 if (assignTo == null) return false;
084 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
085 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Character");
086 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
087 }
088
089 return assignTo == SymbolData.INT_TYPE ||
090 assignTo == SymbolData.LONG_TYPE ||
091 assignTo == SymbolData.FLOAT_TYPE ||
092 assignTo == SymbolData.DOUBLE_TYPE ||
093 assignTo == SymbolData.CHAR_TYPE;
094 }
095 };
096
097 /** This anonymous class represents the byte primitive type */
098 public static final SymbolData BYTE_TYPE = new PrimitiveData("byte") {
099
100 /** You can cast a byte primitive to a char, int, long, float, double or short or byte or Byte object (in 1.5) */
101 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
102 return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE;
103 }
104
105 /** You can assign a byte primitive to a byte, short, int, long, float, double, or Byte object(in 1.5). */
106 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
107 if (assignTo == null) return false;
108
109 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
110 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Byte");
111 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
112 }
113
114 return assignTo == SymbolData.BYTE_TYPE ||
115 assignTo == SymbolData.SHORT_TYPE ||
116 assignTo == SymbolData.INT_TYPE ||
117 assignTo == SymbolData.LONG_TYPE ||
118 assignTo == SymbolData.FLOAT_TYPE ||
119 assignTo == SymbolData.DOUBLE_TYPE;
120 }
121 };
122
123 /** This anonymous class represents the short primitive type. */
124 public static final SymbolData SHORT_TYPE = new PrimitiveData("short") {
125
126 /** You can cast a short primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
127 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
128 return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.BYTE_TYPE;
129 }
130
131 /** You can assign a short primitive to a short, int, long, float, double, or Short object(in 1.5) */
132 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
133 if (assignTo == null) return false;
134
135 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
136 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Short");
137 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
138 }
139
140 return assignTo==SymbolData.SHORT_TYPE ||
141 assignTo == SymbolData.INT_TYPE ||
142 assignTo == SymbolData.LONG_TYPE ||
143 assignTo == SymbolData.FLOAT_TYPE ||
144 assignTo == SymbolData.DOUBLE_TYPE;
145 }
146 };
147
148 /** This anonymous class represents the int primitive type. */
149 public static final SymbolData INT_TYPE = new PrimitiveData("int") {
150
151 /** You can cast a int primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
152 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
153 return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.SHORT_TYPE
154 || castTo == SymbolData.BYTE_TYPE;
155 }
156
157 /** You can assign a int primitive to a int, long, float, double, or Integer/Long/Float/Double or
158 * Number/Object type (in 1.5) */
159 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
160 if (assignTo == null) return false;
161
162 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
163 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Integer");
164 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
165 }
166
167 return assignTo == SymbolData.INT_TYPE || assignTo == SymbolData.LONG_TYPE ||
168 assignTo == SymbolData.FLOAT_TYPE || assignTo == SymbolData.DOUBLE_TYPE;
169 }
170 };
171
172 /** This represents the long primitive */
173 public static final SymbolData LONG_TYPE = new PrimitiveData("long"){
174
175 /** You can cast a long primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
176 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
177 return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE ||
178 castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
179 }
180
181 /** You can assign a long primitive to a long, float, double, or Long object(in 1.5) */
182 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
183 if (assignTo == null) {return false;}
184
185 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
186 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Long");
187 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
188 }
189
190 return assignTo == SymbolData.LONG_TYPE ||
191 assignTo == SymbolData.FLOAT_TYPE ||
192 assignTo == SymbolData.DOUBLE_TYPE;
193
194 }
195 };
196
197 /** This represents the float primitive */
198 public static final SymbolData FLOAT_TYPE = new PrimitiveData("float"){
199
200 /** You can cast a float primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
201 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
202 return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE
203 || castTo == SymbolData.LONG_TYPE || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
204 }
205
206 /** You can assign a float primitive to a float, double, or Float object(in 1.5) */
207 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
208 if (assignTo == null) return false;
209
210 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
211 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Float");
212 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
213 }
214
215 return assignTo == SymbolData.FLOAT_TYPE || assignTo == SymbolData.DOUBLE_TYPE;
216 }
217 };
218
219 /**This represents the double primitive*/
220 public static final SymbolData DOUBLE_TYPE = new PrimitiveData("double"){
221
222 /** A double primitive can be cast to a char, int, long, float, double, short or byte primitive or a Float
223 * or Double object, */
224 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
225 return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE
226 || castTo == SymbolData.LONG_TYPE || castTo == SymbolData.DOUBLE_TYPE || castTo == SymbolData.SHORT_TYPE
227 || castTo == SymbolData.BYTE_TYPE;
228 }
229
230 /** You can assign a double primitive to a float, double, or Float object(in 1.5) */
231 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
232 if (assignTo == null) { return false; }
233
234 if (LanguageLevelConverter.versionSupportsAutoboxing(version) && ! assignTo.isPrimitiveType()) {
235 SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Double");
236 return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
237 }
238 return assignTo == SymbolData.DOUBLE_TYPE;
239 }
240 };
241
242 /** Used for the void type. */
243 public static final SymbolData VOID_TYPE = new PrimitiveData("void") {
244
245 /** A void value cannot be cast to anything */
246 public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
247
248 /** A void value can be assigned to itself */
249 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return this == toCheck; }
250 };
251
252 /** Used for an exception */
253 public static final SymbolData EXCEPTION = new SymbolData("exception") {
254 /** You cannot cast an exception to anything. */
255 public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
256
257 /** Returns true, because an exception takes the place of a return.
258 * This SymbolData is only used when the user has thrown an Exception.
259 */
260 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return true; }
261
262 };
263
264 /** Used to signal a symbol table search that failed. */
265 public static final SymbolData NOT_FOUND = new SymbolData("not found") {
266
267 /** A not-found value cannot be cast to anything */
268 public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
269
270 /** A not-found value cannot be assigned to anything */
271 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
272 };
273
274 /** Singleton class representing null*/
275 public static final SymbolData NULL_TYPE = new SymbolData("null") {
276
277 /** You can cast null to any reference type (i.e. something that is not a primitive). */
278 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
279 return isAssignableTo(castTo, version);
280 }
281
282 /** You can assign a null to any reference (non-primitive) type */
283 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
284 return (assignTo != null) && ! assignTo.isPrimitiveType();
285 }
286
287 };
288
289 /** Used when 2 or more SymbolDatas could match*/
290 public static final SymbolData AMBIGUOUS_REFERENCE = new SymbolData("ambiguous reference") {
291 /** An ambiguous reference cannot be cast to anything */
292 public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
293
294 /** An ambiguous reference cannot be assigned to anything */
295 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
296 };
297
298 /** Used when a this constructor invocation is seen. */
299 public static final SymbolData THIS_CONSTRUCTOR = new SymbolData("this constructor") {
300 /** Cannot be cast to anything */
301 public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
302
303 /** Cannot be assigned to anything */
304 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
305 };
306
307 /** Used when a super constructor invocation is seen. */
308 public static final SymbolData SUPER_CONSTRUCTOR = new SymbolData("super constructor") {
309 /** Cannot be cast to anything */
310 public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
311
312 /** Cannot be assigned to anything */
313 public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
314 };
315
316 /** Do some initialization*/
317 static {
318 ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
319 VOID_TYPE.setIsContinuation(false);
320 VOID_TYPE.setMav(_publicMav);
321 NOT_FOUND.setIsContinuation(false);
322 NOT_FOUND.setMav(_publicMav);
323 EXCEPTION.setMav(_publicMav);
324 EXCEPTION.setIsContinuation(false);
325 }
326
327 /********Instance fields***********/
328
329 /* The inherited _name field is fully qualified. */
330
331 /**True iff this symbol data is a continuation (i.e. hasn't been resolved)*/
332 private boolean _isContinuation;
333
334 /* True iff this symbol corresponds to a file with an autogenerated "import junit.framework.*;" */
335 private boolean _hasAutoGeneratedJunitImport;
336
337 /**The generic type information for this class. Not used. */
338 private TypeParameter[] _typeParameters;
339
340 /**List of methods defined in this class*/
341 private LinkedList<MethodData> _methods;
342
343 /**The SymbolData corresponding to this class's super class. */
344 private SymbolData _superClass;
345
346 /**List of SymbolDatas corresponding to super interfaces. */
347 private ArrayList<SymbolData> _interfaces;
348
349 /**List of SymbolDatas corresponding to inner interfaces. */
350 private LinkedList<SymbolData> _innerInterfaces;
351
352 /** Flag that is true if this SymbolData is an interface. */
353 private boolean _isInterface;
354
355 /** Stores the package information for this symbol data. May not be set. */
356 private String _package;
357
358 /** Represents an instance of this class--i.e. an instantiation of it.*/
359 private InstanceData _instanceData;
360
361 /**The current constructor count. Incremented during first pass, decremented during second pass. */
362 private int _constructorNumber;
363
364 /** The number of local classes, used in naming them. */
365 private int _localClassNum;
366
367 /* The number of anonymous inner classes, used in naming them. */
368 private int _anonymousInnerClassNum;
369
370 /** Constructors */
371
372 /** Constructor for SymbolData
373 * @param name The name of this class or interface
374 * @param modifiersAndVisibility The modifiersAndVisibility of this class or interface
375 * @param typeParameters Generic type info, not used
376 * @param superClass The super class of this class
377 * @param interfaces The super interfaces
378 * @param outerData The enclosing data of this class, or null
379 */
380 public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
381 SymbolData superClass, ArrayList<SymbolData> interfaces, Data outerData) {
382 super(outerData);
383 _name = name;
384 _modifiersAndVisibility = modifiersAndVisibility;
385 _typeParameters = typeParameters;
386 _methods = new LinkedList<MethodData>();
387 _superClass = superClass;
388 _interfaces = interfaces;
389
390 assert interfaces != null;
391
392 for (SymbolData sd: interfaces) { addEnclosingData(sd); }
393
394 /* Add first because we want to look at the super class first */
395 _enclosingData.addFirst(_superClass);
396 _innerClasses = new LinkedList<SymbolData>();
397 _innerInterfaces = new LinkedList<SymbolData>();
398 _isContinuation = false;
399 _hasAutoGeneratedJunitImport = false;
400 _isInterface = false;
401 _localClassNum = 0;
402 _anonymousInnerClassNum = 0;
403 _package = "";
404 _constructorNumber = 0;
405 _instanceData = new InstanceData(this);
406 }
407
408 /** Constructor for SymbolData
409 * @param name The name of this class or interface
410 * @param modifiersAndVisibility The modifiersAndVisibility of this class or interface
411 * @param typeParameters Generic type info, not used
412 * @param superClass The super class of this class
413 * @param interfaces The super interfaces
414 * @param outerData The enclosing data of this class, or null
415 */
416 public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
417 SymbolData superClass, ArrayList<SymbolData> interfaces, Data outerData, String pkg) {
418 this(name, modifiersAndVisibility, typeParameters, superClass, interfaces, outerData);
419 _package = pkg;
420 }
421
422 /** This constructor is only called by Interfaces. Thus, there is never a super class, and _isInterface
423 * is set to true.
424 * @param name The name of this class or interface
425 * @param modifiersAndVisibility The modifiersAndVisibility of this class or interface
426 * @param typeParameters Generic type info, not used
427 * @param interfaces The super interfaces
428 * @param outerData The enclosing data of this class, or null
429 */
430 public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
431 ArrayList<SymbolData> interfaces, Data outerData) {
432 this(name, modifiersAndVisibility, typeParameters, null, interfaces, outerData);
433 _isInterface = true;
434 }
435
436 /** Creates a continuation symbol for the specified name; does not enter this name in any table. */
437 public SymbolData(String name) { this(name, SourceInfo.NONE); }
438
439 /** Creates a continuation symbol for the specified name and source info; does not enter this name in any table. */
440 public SymbolData(String name, SourceInfo si) {
441 super(null);
442 _name = name;
443 _modifiersAndVisibility = new ModifiersAndVisibility(si, new String[0]);
444 _typeParameters = new TypeParameter[0];
445 _methods = new LinkedList<MethodData>();
446 _superClass = null;
447 _interfaces = new ArrayList<SymbolData>();
448 _innerClasses = new LinkedList<SymbolData>();
449 _innerInterfaces = new LinkedList<SymbolData>();
450 _isContinuation = true;
451 _isInterface = false;
452 _package = "";
453 _instanceData = new InstanceData(this);
454 }
455
456 /** No reference type is a Primitive type. */
457 public boolean isPrimitiveType() { return false; }
458
459 public String toString() {
460 if (_isContinuation) return "? " + _name;
461 return "!" + _name;
462 }
463
464 /**
465 * See if this can be assigned to assignTo.
466 * An assignment is legal:
467 * 1. if this is a class type
468 * - if assignTo is a class type, then the types must be the same, or this must be a subclass of assignTo
469 * - if assignTo is an interface, then we must implement it.
470 * - if assignTo is an array, then it is not assignable.
471 * 2. if this is an interface
472 * - if assignTo is a class, assignTo must be java.lang.Object.
473 * - if assignTo is an interface, then the types must be the same, or this must be a subinterface of assignTo.
474 * - if assignTo is an array, then it is not assignable
475 * All of these rules are followed in isSubclassOf(), which traverses the hierarchy.
476 */
477 public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
478 if (assignTo != null) {
479 if (assignTo.isPrimitiveType() && LanguageLevelConverter.versionSupportsAutoboxing(version)) {
480 // You never box the left, so see if this can be unboxed to be a primitive.
481 SymbolData unboxedType = this.unbox();
482 if (unboxedType == null) return false;
483 else return unboxedType.isAssignableTo(assignTo, version);
484 }
485 else return this.isSubClassOf(assignTo);
486 }
487 return false;
488 }
489
490 /** Resolves this symbol using the visitor llv.
491 * @return the new symbol definition. */
492 public SymbolData resolve(SourceInfo si, LanguageLevelVisitor llv) { return llv.resolveSymbol(si, this); }
493
494 /** If this SymbolData is a wrapper class for a primitive, return the primitive type. Else return null.
495 * @return the Primitive this SymbolData wraps, if there is one. Otherwise return null.
496 */
497 private SymbolData unbox() {
498 String name = getName();
499 if (name.equals("java.lang.Integer")) {return SymbolData.INT_TYPE;}
500 if (name.equals("java.lang.Character")) {return SymbolData.CHAR_TYPE;}
501 if (name.equals("java.lang.Short")) {return SymbolData.SHORT_TYPE;}
502 if (name.equals("java.lang.Byte")) {return SymbolData.BYTE_TYPE;}
503 if (name.equals("java.lang.Float")) {return SymbolData.FLOAT_TYPE;}
504 if (name.equals("java.lang.Double")) {return SymbolData.DOUBLE_TYPE;}
505 if (name.equals("java.lang.Long")) {return SymbolData.LONG_TYPE;}
506 if (name.equals("java.lang.Boolean")) {return SymbolData.BOOLEAN_TYPE;}
507 return null;
508 }
509
510 /**
511 * See if this can be cast as a castTo.
512 * A cast is legal if:
513 * 1. if both sides are the same type
514 * 2. Both are primitives and
515 * - a widening primitive coversion is possible OR
516 * - a narrowing primitive conversion is possible
517 * 3. this is a class type and
518 * - castTo is a class type and one is the super class of the other
519 * - castTo is an interface type and this is not final OR this implements castTo
520 * - castTo is an array type, and this is Object
521 * 4. this is an interface type and
522 * - castTo is a class type and is not final OR this implements this
523 * - castTo is an interface type and this and castTo do not contain one or more methods with the same signature
524 * but different return types
525 * - castTo is an array type and this is either Serializable or Cloneable.
526 * @param castTo The TypeData we are trying to cast to. (castTo) this
527 * @return true If the cast is legal, false otherwise.
528 */
529 public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
530 if (castTo != null) {
531 if (castTo.isPrimitiveType()) {
532 if (LanguageLevelConverter.versionSupportsAutoboxing(version)) {
533 //You never box the left, so see if this can be unboxed to be a primitive.
534 SymbolData unboxedType = this.unbox();
535 if (unboxedType == null) {return false;}
536 else {return unboxedType.isCastableTo(castTo, version);}
537 }
538 else {return false;} //without autoboxing, cannot cast an object to a primitive
539 }
540
541 else if (!this.isInterface()) { //we're a class
542 if (!castTo.isInterface()) {//castTo is a class or array
543 return this.isSubClassOf(castTo) || castTo.isSubClassOf(this);
544 }
545
546 else { //castTo is an interface
547 return (!castTo.hasModifier("final") || castTo.isSubClassOf(this));
548 }
549
550 }
551
552 else { // this is an interface
553
554 if (!castTo.isInterface()) {//castTo is a class or array
555 return !castTo.hasModifier("final") || castTo.isSubClassOf(this);
556 }
557
558 else { // castTo is an interface
559 // return false if this and castTo contain methods with the same signature but different return types.
560 if (LanguageLevelConverter.versionSupportsAutoboxing(version)) return true;
561 for (MethodData md: this.getMethods()) {
562 if (checkDifferentReturnTypes(md, castTo, false, version)) {
563 /* TypeChecker._addError("Types " + this.getName() + " and " + castTo.getName() + " are incompatible.
564 Both implement " + md.getName() + " but have different return types", md.getSourceInfo()); */
565 return false;
566 }
567 }
568 return true;
569 }
570 }
571 }
572 return false;
573 }
574
575 /** Depth-first traversal of the tree of enclosing data checking to see if sd is above this SymbolData
576 * in the class hierarchy.
577 */
578 public boolean isSubClassOf(SymbolData sd) {
579 if (sd == null) return false;
580 if (this.equals(sd)) return true;
581 if (sd.isInterface()) {
582 for (SymbolData i: _interfaces) {
583 if (i == null) continue;
584 if (i.equals(sd)) return true;
585 if (i.isSubClassOf(sd)) return true;
586 }
587 }
588
589 if (_superClass != null) return _superClass.isSubClassOf(sd);
590 return false;
591 }
592
593 /** Checks to see if this SymbolData is an inner class of outerClass (that is, that outerClass appears
594 * somewhere in its enclosing data chain. If stopAtStatic flag is true, stop as soon as we see a static class
595 * in the chain. This is because we are trying to resolve something, such as a "this" call, that cannot be seen outside
596 * of a static inner class.
597 * @param outerClass The SymbolData we believe might be our outer class.
598 * @param stopAtStatic boolean flag, true if we want to stop at a static outer class.
599 * @return true if we are its inner class, false otherwise.
600 */
601 public boolean isInnerClassOf(SymbolData outerClass, boolean stopAtStatic) {
602 if (this == outerClass) return true;
603 Data outerData = this.getOuterData();
604 if (outerData == null) return false;
605 if (stopAtStatic && this.hasModifier("static")) {return false;}
606 return outerData.getSymbolData().isInnerClassOf(outerClass, stopAtStatic);
607 }
608
609 /**@return false, since this is a SymbolData and not an InstanceData*/
610 public boolean isInstanceType() { return false; }
611
612 /**@return this SymbolData.*/
613 public SymbolData getSymbolData() { return this; }
614
615 /** @return the InstanceData corresponding to this class. */
616 public InstanceData getInstanceData() { return _instanceData; }
617
618 /** Sets the InstanceData for this class to the specified value. */
619 public void setInstanceData(InstanceData id) { _instanceData = id; }
620
621 /** @return the package */
622 public String getPackage() { return _package; }
623
624 /** Sets the package to the specified value */
625 public void setPackage(String pkg) { _package = pkg; }
626
627 /** @return the generic type parameters */
628 public TypeParameter[] getTypeParameters() {
629 return _typeParameters;
630 }
631
632 /**Set the generic type parameters to the specified value*/
633 public void setTypeParameters(TypeParameter[] typeParameters) {
634 _typeParameters = typeParameters;
635 }
636
637 /**@return true if this is an interface*/
638 public boolean isInterface() {
639 return _isInterface;
640 }
641
642 public void setInterface(boolean ii) {
643 _isInterface = ii;
644 }
645
646 /**@return the list of inner interfaces*/
647 public LinkedList<SymbolData> getInnerInterfaces() {
648 return _innerInterfaces;
649 }
650
651 /** Takes in a name and tries to match it with one of this Data's inner classes or inner interfaces. The input string
652 * is a name relative to this SymbolData (such as B.C to request the class A.B.C from class A) and may be delimited
653 * by '.' or '$'.
654 * TODO; NO!!! This is broken. '$' appears in anonymous class names and local class names, where it is NOT
655 * used as a name segment separator
656 * Checks the super class and interfaces of this SymbolData to see if the inner class or interface
657 * can be found there. If no matching visibile inner classes or interfaces are found, but one or more that are not
658 * visible are found, one of the non-visibile ones will be returned.
659 * @return The SymbolData for the matching inner class or interface or null if there isn't one or SymbolData.
660 * AMBIGUOUS_REFERENCE if the reference is ambiguous.
661 */
662 protected SymbolData getInnerClassOrInterfaceHelper(String nameToMatch, int firstIndexOfDot) {
663 Iterator<SymbolData> iter = innerClassesAndInterfacesIterator();
664 while (iter.hasNext()) {
665 SymbolData sd = iter.next();
666 String sdName = sd.getName();
667
668 sdName = LanguageLevelVisitor.getUnqualifiedClassName(sdName);
669 if (firstIndexOfDot == -1) {
670 if (sdName.equals(nameToMatch))
671 return sd;
672 }
673 else {
674 if (sdName.equals(nameToMatch.substring(0, firstIndexOfDot))) {
675 return sd.getInnerClassOrInterface(nameToMatch.substring(firstIndexOfDot + 1));
676 }
677 }
678 }
679
680 SymbolData result = null;
681 SymbolData newResult = null;
682 SymbolData privateResult = null;
683
684 // Next, look through the inner classes/interfaces of this class's super class
685 // Check accessibility, because if you cannot see the super class's inner class, you can't use it.
686 if (_superClass != null) {
687 newResult = _superClass.getInnerClassOrInterfaceHelper(nameToMatch, firstIndexOfDot);
688 if (newResult != null) {
689 SymbolData outerPiece;
690
691 if (firstIndexOfDot > 0)
692 outerPiece = _superClass.getInnerClassOrInterfaceHelper(nameToMatch.substring(0, firstIndexOfDot), -1);
693 else outerPiece = newResult;
694
695 if (TypeChecker.checkAccess(outerPiece.getMav(), outerPiece, this)) {result = newResult;}
696 else privateResult = newResult;
697 }
698 }
699
700 // Next, look through the inner classes/interfaces of each of this class's interfaces
701 // Check accessibility, because if you cannot see the super class's inner class, you can't use it.
702 for (SymbolData id: _interfaces) { // TODO: find out how null is being inserted in _interfaces
703 if (id == null) {
704 // System.err.println("In SymbolData " + getName() + ", _interfaces contains a null entry");
705 // assert false;
706 continue;
707 }
708 newResult = id.getInnerClassOrInterfaceHelper(nameToMatch, firstIndexOfDot);
709 if (newResult != null) {
710 SymbolData outerPiece;
711 if (firstIndexOfDot > 0) {
712 outerPiece = _superClass.getInnerClassOrInterfaceHelper(nameToMatch.substring(0, firstIndexOfDot), -1);
713 }
714 else { outerPiece = newResult; }
715 if (TypeChecker.checkAccess(outerPiece.getMav(), outerPiece, this)) {
716 if (result == null) {result = newResult;}
717 else {return SymbolData.AMBIGUOUS_REFERENCE;}
718 }
719 else {privateResult = newResult;}
720 }
721 }
722 if (result != null) {return result;}
723 return privateResult; //this will be null if no matching inner classes/interfaces were found.
724 }
725
726
727 /**Iterate over first the inner classes and then the inner interfaces.*/
728 public Iterator<SymbolData> innerClassesAndInterfacesIterator() {
729 return new Iterator<SymbolData>() {
730 private Iterator<SymbolData> _first = _innerClasses.iterator();
731 private Iterator<SymbolData> _second = _innerInterfaces.iterator();
732
733 public boolean hasNext() { return _first.hasNext() || _second.hasNext(); }
734
735 public SymbolData next() {
736 if (_first.hasNext()) return _first.next();
737 else return _second.next();
738 }
739
740 public void remove() { throw new UnsupportedOperationException(); }
741 };
742 }
743
744
745 /**Add the specified innerInterface to the list of innerInterfaces*/
746 public void addInnerInterface(SymbolData innerInterface) { _innerInterfaces.addLast(innerInterface); }
747
748 /**Increment the local class num and return it*/
749 public int preincrementLocalClassNum() { return ++_localClassNum; }
750
751 /**Set the anonymous inner class num to the specified value*/
752 public void setAnonymousInnerClassNum(int i) { _anonymousInnerClassNum=i; }
753
754 /**Increment the anonymous inner class num, and return it*/
755 public int preincrementAnonymousInnerClassNum() { return ++_anonymousInnerClassNum; }
756
757 /**@return the anonymous inner class num*/
758 public int getAnonymousInnerClassNum() { return _anonymousInnerClassNum; }
759
760 /**Return the local class num, and then decrement it*/
761 public int postdecrementLocalClassNum() { return _localClassNum--; }
762
763 /**Return the anonymous inner class num, and then decrement it*/
764 public int postdecrementAnonymousInnerClassNum() { return _anonymousInnerClassNum--; }
765
766 /** Adds a (perhaps mutable) variable or field to a SymbolData. */
767 public boolean addVar(VariableData var) {
768 // Next line commented out because local variables do not have a initial value
769 // if (! var.isFinal()) var.setHasValue();
770 return super.addVar(var);
771 }
772
773 /** Adds fields or variables to a SymboLData.*/
774 public boolean addVars(VariableData[] vars) {
775 boolean success = true;
776 for (int i = 0; i<vars.length; i++) {
777 LinkedList<SymbolData> seen = new LinkedList<SymbolData>();
778 if (! _repeatedName(vars[i], seen)) {
779 // Next line commented out because local variables do not have a initial value
780 // if (! vars[i].isFinal()) vars[i].setHasValue();
781 _vars.addLast(vars[i]);
782 }
783 else success = false;
784 }
785 return success;
786 }
787
788 /** Add the array of variable datas to the list of variables defined in this scope, unless a name has already been
789 * used. Return true if all variables were added successfully, false otherwise. Set each of the variable datas in
790 * the array to be final before adding them.
791 * Since this method is used to add fields at the Functional level,
792 * and at this level, we do not want the user to be able to shadow fields defined
793 * in the superclass hierarchy, instead of using the normal repeated Name method,
794 * check the repeated name throughout the hierarchy.
795 *
796 * @param vars The VariableData[] that we want to add.
797 * @return true if all VariableDatas were added successfully, false otherwise.
798 */
799 public boolean addFinalVars(VariableData[] vars) {
800 boolean success = true;
801 for (int i = 0; i<vars.length; i++) {
802 LinkedList<SymbolData> seen = new LinkedList<SymbolData>();
803 if (!_repeatedNameInHierarchy(vars[i], seen)) {
804 if (! vars[i].isFinal()) vars[i].setFinal();
805 _vars.addLast(vars[i]);
806 }
807 else {
808 success = false;
809 }
810 }
811 return success;
812 }
813
814 /** Checks to see if a variable with the same name as vr has already been defined in the scope of this data. If so,
815 * return true. Otherwise, return false.
816 * @param vr The VariableData whose name we are searching for.
817 * @return true if that name has already been used in this scope, false otherwise.
818 */
819 private boolean _repeatedName(VariableData vr, LinkedList<SymbolData> seen) {
820 seen.addLast(this);
821 Iterator<VariableData> iter = _vars.iterator();
822 while (iter.hasNext()) {
823 if (vr.getName().equals(iter.next().getName())) return true;
824 }
825 return false;
826 }
827
828 /** Checks to see if a variable with the same name as vr has already been defined in the scope of this data or its
829 * super class/interfaces. If so, return true. Otherwise, return false.
830 * @param vr The VariableData whose name we are searching for.
831 * @return true if that name has already been used in this scope, false otherwise.
832 */
833 private boolean _repeatedNameInHierarchy (VariableData vr, LinkedList<SymbolData> seen) {
834 seen.addLast(this);
835 Iterator<VariableData> iter = _vars.iterator();
836 while (iter.hasNext()) {
837 if (vr.getName().equals(iter.next().getName())) return true;
838 }
839
840 // Does this shadow something in the super class?
841 if (_superClass != null && _superClass._repeatedNameInHierarchy(vr, seen)) return true;
842
843 //Does this shadow something in the super interfaces? TODO: postpone this test until all interfaces have been identified.
844 for (SymbolData sd: _interfaces) {
845 if (sd != null && sd._repeatedNameInHierarchy(vr, seen)) return true;
846 }
847 return false;
848 }
849
850 /** @return the list of methods defined in this symbol data*/
851 public LinkedList<MethodData> getMethods() { return _methods; }
852
853 /** Returns true if there is a method with the given name in this SymbolData.
854 * @param name The name of the method to return
855 * @return true if a MethodData is found or false otherwise.
856 */
857 public boolean hasMethod(String name) {
858 for (int i = 0; i < _methods.size(); i++) {
859 MethodData currMd = _methods.get(i);
860 if (currMd.getName().equals(name)) return true;
861 }
862 return false;
863 }
864
865 /** Returns the method with the given name and param types.
866 * @param name The name of the method to return
867 * @param paramTypes Array of the TypeDatas correpsonding to the parameters to the method.
868 * @return The matched MethodData or null if it is not found
869 */
870 public MethodData getMethod(String name, TypeData[] paramTypes) {
871 for (MethodData currMd: _methods) {
872 if (currMd.getName().equals(name)) {
873 if (paramTypes.length == currMd.getParams().length) {
874 boolean match = true;
875 for (int j = 0; j < paramTypes.length; j++) { // TODO; clean up this coding!
876 if (paramTypes[j] == null || paramTypes[j].getSymbolData() == null || currMd.getParams()[j].getType() == null)
877 continue; // prevents a null pointer exception
878 if (! paramTypes[j].getSymbolData().equals(currMd.getParams()[j].getType().getSymbolData())) {
879 match = false;
880 break;
881 }
882 }
883 if (match) return currMd;
884 }
885 }
886 }
887 return null;
888 }
889
890 /**Sets the list of methods to the specified one*/
891 public void setMethods(LinkedList<MethodData> methods) {
892 _methods = methods;
893 }
894
895 /**Calls repeatedSignature with fromClassFile set to false by default.*/
896 public static MethodData repeatedSignature(LinkedList<MethodData> listOfMethods, MethodData method) {
897 return repeatedSignature(listOfMethods, method, false);
898 }
899
900 /** Checks if two methods in this SymbolData have the same name and parameters.
901 * @param listOfMethods The methods in this SymbolData
902 * @param method The MethodData for the method to be added
903 * @param fromClassFile Whether or not a class file is adding this method.
904 * Important because bridge methods, which differ only in return type,
905 * can be added from a class file and are legal but cannot exist in source code.
906 * @return the MethodData that was already in listOfMethods that method duplicates if there is one or null otherwise.
907 */
908 public static MethodData repeatedSignature(LinkedList<MethodData> listOfMethods, MethodData method,
909 boolean fromClassFile) {
910 Iterator<MethodData> iter = listOfMethods.iterator();
911 VariableData[] methodParams = method.getParams();
912 while (iter.hasNext()) {
913 boolean match = true;
914 MethodData currMd = iter.next();
915 // Check if names are the same and if this is called from a class file check if return types are the same.
916 if (currMd.getName().equals(method.getName()) &&
917 (! fromClassFile || currMd.getReturnType() == method.getReturnType())) {
918 VariableData[] currMdParams = currMd.getParams();
919 if (currMdParams.length == methodParams.length) {
920 for (int i = 0; i < currMdParams.length; i++) {
921 if (currMdParams[i].getType() != methodParams[i].getType()) {
922 match = false;
923 break;
924 }
925 }
926 if (match) return currMd;
927 }
928 }
929 }
930 return null;
931 }
932
933
934
935 /** @return true if this is a primitive boolean or a Boolean with autoboxing enabled*/
936 boolean isBooleanType(JavaVersion version) {
937 return this == BOOLEAN_TYPE ||
938 (getName().equals("java.lang.Boolean") && LanguageLevelConverter.versionSupportsAutoboxing(version));
939 }
940
941
942 /** @return true if this is a primitive char or a Character with autoboxing enabled*/
943 boolean isCharType(JavaVersion version) {
944 return this == CHAR_TYPE || (getName().equals("java.lang.Character") &&
945 LanguageLevelConverter.versionSupportsAutoboxing(version));
946 }
947
948 /** @return true if this is a primitive byte or a Byte with autoboxing enabled*/
949 boolean isByteType(JavaVersion version) {
950 return this == BYTE_TYPE || (getName().equals("java.lang.Byte") &&
951 LanguageLevelConverter.versionSupportsAutoboxing(version));
952 }
953
954 /** @return true if this is a primitive short or a Short with autoboxing enabled*/
955 boolean isShortType(JavaVersion version) {
956 return this == SHORT_TYPE || (getName().equals("java.lang.Short") &&
957 LanguageLevelConverter.versionSupportsAutoboxing(version));
958 }
959
960 /**@return true if this is a primitive int or an Integer with autoboxing enabled*/
961 boolean isIntType(JavaVersion version) {
962 return this==INT_TYPE || (getName().equals("java.lang.Integer") &&
963 LanguageLevelConverter.versionSupportsAutoboxing(version));
964 }
965
966 /**@return true if this is a primitive long or a Long with autoboxing enabled*/
967 boolean isLongType(JavaVersion version) {
968 return this == LONG_TYPE || (this.getName().equals("java.lang.Long") &&
969 LanguageLevelConverter.versionSupportsAutoboxing(version));
970 }
971
972 /**@return true if this is a primitive char or a Character with autoboxing enabled*/
973 boolean isFloatType(JavaVersion version) {
974 return this == FLOAT_TYPE || (getName().equals("java.lang.Float") &&
975 LanguageLevelConverter.versionSupportsAutoboxing(version));
976 }
977
978 /**@return true if this is a primitive double or a Double with autoboxing enabled*/
979 boolean isDoubleType(JavaVersion version) {
980 return this == DOUBLE_TYPE ||
981 (getName().equals("java.lang.Double") && LanguageLevelConverter.versionSupportsAutoboxing(version));
982 }
983
984 /** Compares the ModifiersAndVisibility of the 2 method data to determine if overwriting can override the access
985 * priviledges of overwritten.
986 */
987 private static boolean _isCompatible(MethodData overwritten, MethodData overwriting) {
988 if (overwritten.hasModifier("public")) { // A public method can only be overwritten by a public method.
989 return overwriting.hasModifier("public");
990 }
991 if (overwritten.hasModifier("protected")) { // A protected method can only be overwritten by protected/public method
992 return overwriting.hasModifier("protected") || overwriting.hasModifier("public");
993 }
994 if (! overwritten.hasModifier("private")) { // default methods can be overridden by a non-private method
995 return ! overwriting.hasModifier("private");
996 }
997 return true;
998 }
999
1000 /**Call checkDifferentReturnTypes with addError set to true by default*/
1001 protected static boolean checkDifferentReturnTypes(MethodData md, SymbolData sd, JavaVersion version) {
1002 return checkDifferentReturnTypes(md, sd, true, version);
1003 }
1004
1005 /** Called to make sure that no method has the same name and parameters as a method it inherits while having
1006 * different return types.
1007 * @param md The MethodData we're currently trying to add
1008 * @param sd The SymbolData of the class whose enclosingDatas we're examining for
1009 * different return types.
1010 * @param addError true if errors should be added to the type checker
1011 * @return Whether there exists a conflict
1012 */
1013 protected static boolean checkDifferentReturnTypes(MethodData md, SymbolData sd, boolean addError,
1014 JavaVersion version) {
1015 // We only want to check the super class and interfaces, not outer classes.
1016 ArrayList<SymbolData> interfaces = sd.getInterfaces();
1017 LinkedList<SymbolData> enclosingData = new LinkedList<SymbolData>();
1018 enclosingData.addAll(interfaces);
1019 SymbolData superClass = sd.getSuperClass();
1020 if (superClass != null) {
1021 enclosingData.add(superClass);
1022 }
1023 Iterator<SymbolData> iter = enclosingData.iterator();
1024 while (iter.hasNext()) {
1025 SymbolData currSd = iter.next();
1026 MethodData matchingMd = repeatedSignature(currSd.getMethods(), md);
1027 if (matchingMd != null) {
1028 if (matchingMd.hasModifier("private")) return false;
1029 boolean subclass = md.getReturnType().isSubClassOf(matchingMd.getReturnType());
1030 if (matchingMd.getReturnType() != md.getReturnType() && ! subclass &&
1031 LanguageLevelConverter.versionIs15(version)) {
1032 StringBuffer methodSignature = new StringBuffer(md.getName() + "(");
1033 VariableData[] params = md.getParams();
1034 for (int i = 0; i < params.length; i++) {
1035 if (i > 0) methodSignature.append(", ");
1036 methodSignature.append(params[i].getType().getName());
1037 }
1038 methodSignature.append(")");
1039 String methodSigString = methodSignature.toString();
1040 // This entire method is only called from the type checker, so add an error to its error list.
1041 if (addError) {
1042 TypeChecker.errors.addLast(new Pair<String, JExpressionIF>(methodSigString + " in " + sd.getName() +
1043 " cannot override " + methodSigString + " in " +
1044 currSd.getName() +
1045 "; attempting to use different return types",
1046 md.getJExpression())); }
1047 return true;
1048 }
1049
1050 if (! _isCompatible(matchingMd, md)) { // check compatibility of visiblity modifiers
1051 String access = "package";
1052 if (matchingMd.hasModifier("private")) access = "private";
1053 if (matchingMd.hasModifier("public")) access = "public";
1054 if (matchingMd.hasModifier("protected")) access = "protected";
1055 if (addError) {
1056 TypeChecker.errors.
1057 addLast(new Pair<String, JExpressionIF>(md.getName() + " in " + md.getSymbolData().getName()
1058 + " cannot override " + matchingMd.getName() + " in "
1059 + matchingMd.getSymbolData().getName() +
1060 ". You are attempting to assign weaker access priviledges. In "
1061 + matchingMd.getSymbolData().getName() + ", "
1062 + matchingMd.getName() + " was "
1063 + access, md.getJExpression())); }
1064 return true;
1065 }
1066 }
1067 else if (checkDifferentReturnTypes(md, currSd, version)) return true;
1068 }
1069 return false;
1070 }
1071
1072 /** Checks to see if methodName is used in this SymbolData's scope. If so, finds a new name for the method by
1073 * appending a counter to its name until an unused method name results. Returns the new name.
1074 * @param methodName The initial String name of the variable we are creating.
1075 * @return The new variable name which does not shadow anything in vars.
1076 */
1077 public String createUniqueMethodName(String methodName) {
1078 LinkedList<SymbolData> toCheck = new LinkedList<SymbolData>();
1079 toCheck.add(this);
1080 Set<String> names = new HashSet<String>();
1081 while(toCheck.size() > 0) {
1082 SymbolData sd = toCheck.removeFirst();
1083 LinkedList<MethodData> methods = sd.getMethods();
1084 for(MethodData md : methods) { names.add(md.getName()); }
1085 if (sd.getSuperClass() != null) { toCheck.add(sd.getSuperClass()); }
1086 toCheck.addAll(sd.getInterfaces());
1087 if (sd.getOuterData() != null) { toCheck.add(sd.getOuterData().getSymbolData()); }
1088 }
1089
1090 String newName = methodName;
1091 int counter = 0; // Note: loop tests for counter overflow, but memory would be exhausted much earlier
1092 while (names.contains(newName) && counter != -1) {
1093 newName = methodName + counter;
1094 counter++;
1095 }
1096
1097 if (counter == -1) throw
1098 new RuntimeException("Internal Program Error: Unable to rename method " + methodName
1099 + ". All possible names were taken. Please report this bug.");
1100
1101 return newName;
1102 }
1103
1104
1105 /** Called to generate an error message when two methods are created with the same signature. */
1106 private String _createErrorMessage(MethodData md) {
1107 StringBuffer message =
1108 new StringBuffer("In the class \"" + md.getSymbolData().getName() +
1109 "\", you cannot have two methods with the same name: \"" + md.getName() + "\"");
1110 VariableData[] params = md.getParams();
1111 if (params.length > 0) {
1112 message.append(" and parameter type");
1113 if (params.length > 1) {
1114 message.append("s");
1115 }
1116 message.append(":");
1117 }
1118 for (int i = 0; i < params.length; i++) {
1119 VariableData p = params[i];
1120 if (p != null && p.getType() != null) {
1121 if (i > 0) {
1122 message.append(",");
1123 }
1124 message.append(" " + p.getType().getName());
1125 }
1126 }
1127 return message.toString();
1128 }
1129
1130 /** When adding a method, we must check that the method's signature (name and parameters)
1131 * does not match that of any other method in the same class. We also must check that
1132 * a method does not have the same signature but a different return type from a method
1133 * in its superclass or one of its interfaces.
1134 ` */
1135 public void addMethod(MethodData method) {
1136 // Detect repeated methods
1137 if (repeatedSignature(_methods, method) != null) {
1138 LanguageLevelVisitor.errors.addLast(new Pair<String, JExpressionIF>(_createErrorMessage(method),
1139 method.getJExpression()));
1140 }
1141 else {
1142 _methods.addLast(method);
1143 // System.err.println("*** Adding method " + method.getName() + " to " + this);
1144 }
1145 }
1146
1147 /** This version of addMethod is called whenever the method corresponds to one that is auto-generated
1148 * (toString, equals, hashCode, etc.) and is necessary because we need to check if the user defined
1149 * a method with the same signature and, if so, highlight the user method instead of trying to highlight
1150 * the auto-generated method (which doesn't appear in the raw version of the source anyway).
1151 */
1152 public void addMethod(MethodData method, boolean isAugmentedCode) {
1153 // Detect if a method was user-defined that matches the signature of an auto-generated method.
1154 MethodData md = repeatedSignature(_methods, method);
1155 if (md != null) {
1156 LanguageLevelVisitor.errors.
1157 addLast(new Pair<String, JExpressionIF>("This method's signature conflicts with an automatically generated "
1158 + "method's signature",
1159 md.getJExpression()));
1160 }
1161 else {
1162 _methods.addLast(method);
1163 }
1164 }
1165
1166 /**
1167 * Important to know if this is called from a class file since JSR14 allows methods to have the same
1168 * name and parameters with different return types for bridge methods.
1169 */
1170 public void addMethod(MethodData method, boolean isAugmentedCode, boolean fromClassFile) {
1171 // This checking cannot be performed until symbolTable is complete
1172 // // Detect if a method was user-defined that matches the signature of an auto-generated method.
1173 // MethodData md = repeatedSignature(_methods, method, fromClassFile);
1174 // if (md != null) {
1175 // LanguageLevelVisitor.errors.
1176 // addLast(new Pair<String, JExpressionIF>(_createErrorMessage(method), md.getJExpression()));
1177 // }
1178 // else {
1179 _methods.addLast(method);
1180 // }
1181 }
1182
1183 /**@return the superClass of this symbol data*/
1184 public SymbolData getSuperClass() {
1185 return _superClass;
1186 }
1187
1188 public void clearSuperClass() { _superClass = null; }
1189
1190 /** Set the super class to the specified value. */
1191 public void setSuperClass(SymbolData superClass) {
1192 assert superClass != null;
1193 _superClass = superClass;
1194 addEnclosingData(superClass);
1195 }
1196
1197 /**@return the interfaces of this symbol data*/
1198 public ArrayList<SymbolData> getInterfaces() { return _interfaces; }
1199
1200 /** Add an interface to the list of interfaces. TODO: find out where null is being added as an interface! */
1201 public void addInterface(SymbolData interphace) {
1202 if (interphace != null) {
1203 _interfaces.add(interphace);
1204 addEnclosingData(interphace);
1205 }
1206 }
1207
1208 /**Set the interfaces to be the specified list*/
1209 public void setInterfaces(ArrayList<SymbolData> interfaces) {
1210 assert interfaces != null;
1211 _interfaces = interfaces;
1212 for (SymbolData sd: interfaces) { if (sd != null) addEnclosingData(sd); }
1213 }
1214
1215 /**Add one to the number of constructors for this symbol data*/
1216 public void incrementConstructorCount() {
1217 _constructorNumber ++;
1218 }
1219
1220 /**Subtract one from the number of constructors for this symbol data*/
1221 public void decrementConstructorCount() {
1222 _constructorNumber --;
1223 }
1224
1225 /**@return the number of constructors*/
1226 public int getConstructorCount() {
1227 return _constructorNumber;
1228 }
1229
1230 /**@return true if this is a continuation*/
1231 public boolean isContinuation() {
1232 return _isContinuation;
1233 }
1234
1235 /**Set the isContinuation flag to the specified value*/
1236 public void setIsContinuation(boolean isContinuation) {
1237 _isContinuation = isContinuation;
1238 }
1239
1240 /**@return true if this is a continuation*/
1241 public boolean hasAutoGeneratedJunitImport() {
1242 return _hasAutoGeneratedJunitImport;
1243 }
1244
1245 /**Set the isContinuation flag to the specified value*/
1246 public void setHasAutoGeneratedJunitImport(boolean hasAutoGeneratedJunitImport) {
1247 _hasAutoGeneratedJunitImport = hasAutoGeneratedJunitImport;
1248 }
1249
1250 /**@return true if this Symbol Data is a primitive type that is a number type*/
1251 public boolean isNumberTypeWithoutAutoboxing() {
1252 return (this == SymbolData.INT_TYPE ||
1253 this == SymbolData.DOUBLE_TYPE ||
1254 this == SymbolData.LONG_TYPE ||
1255 this == SymbolData.CHAR_TYPE ||
1256 this == SymbolData.FLOAT_TYPE ||
1257 this == SymbolData.SHORT_TYPE ||
1258 this == SymbolData.BYTE_TYPE);
1259 }
1260
1261 /**@return true if this Symbol Data is a primitive type that is a number type or is
1262 * a Object number type with autoboxing enabled.*/
1263 public boolean isNumberType(JavaVersion version) {
1264 if (!LanguageLevelConverter.versionSupportsAutoboxing(version)) {
1265 return isNumberTypeWithoutAutoboxing();
1266 }
1267 if (this.isDoubleType(version) ||
1268 this.isFloatType(version) ||
1269 this.isLongType(version) ||
1270 this.isIntType(version) ||
1271 this.isCharType(version) ||
1272 this.isShortType(version) ||
1273 this.isByteType(version)) {
1274 return true;
1275 }
1276 return false;
1277 }
1278
1279
1280 /**@return true if this is a non float or boolean type, with autoboxing if it is allowed, or without autoboxing*/
1281 public boolean isNonFloatOrBooleanType(JavaVersion version) {
1282 if (!LanguageLevelConverter.versionSupportsAutoboxing(version)) {
1283 return isNonFloatOrBooleanTypeWithoutAutoboxing();
1284 }
1285
1286 return (this.isIntType(version) ||
1287 this.isLongType(version) ||
1288 this.isCharType(version) ||
1289 this.isShortType(version) ||
1290 this.isByteType(version) ||
1291 this.isBooleanType(version));
1292 }
1293
1294 /** @return true if this is a non float or boolean type, without autoboxing*/
1295 public boolean isNonFloatOrBooleanTypeWithoutAutoboxing() {
1296 return (this==SymbolData.INT_TYPE ||
1297 this==SymbolData.LONG_TYPE ||
1298 this==SymbolData.CHAR_TYPE ||
1299 this==SymbolData.SHORT_TYPE ||
1300 this==SymbolData.BYTE_TYPE ||
1301 this==SymbolData.BOOLEAN_TYPE);
1302
1303 }
1304
1305
1306 /**
1307 * Returns true if the provided Object is equal to this symbol data.
1308 * SymbolDatas are equal if their fields are the same.
1309 * */
1310 public boolean equals(Object obj) {
1311 if (obj == null) return false;
1312 if ((obj.getClass() != this.getClass())) { //|| (obj.hashCode() != this.hashCode())) {
1313 return false;
1314 }
1315 SymbolData sd = (SymbolData) obj;
1316
1317 /*Return true if the fields are all .equals.*/
1318
1319 return this.isContinuation() == sd.isContinuation() &&
1320 this.getMav().equals(sd.getMav()) &&
1321 LanguageLevelVisitor.arrayEquals(this.getTypeParameters(), sd.getTypeParameters()) &&
1322 this.getMethods().equals(sd.getMethods()) &&
1323 this.getSuperClass() == sd.getSuperClass() && //could be null
1324 this.getInterfaces().equals(sd.getInterfaces()) &&
1325 this.getOuterData() == sd.getOuterData() && //could be null
1326 this.getInnerClasses().equals(sd.getInnerClasses()) &&
1327 this.getName().equals(sd.getName()) &&
1328 this.getInnerInterfaces().equals(sd.getInnerInterfaces()) &&
1329 this.getPackage().equals(sd.getPackage()) &&
1330 this.isInterface() == sd.isInterface();
1331
1332
1333 }
1334
1335 /**
1336 * Since SymbolDatas have unique names, in any given symboltable, hash on the name
1337 */
1338 public int hashCode() {
1339 return getName().hashCode();
1340 }
1341
1342 /** Check to see if this class is one of the 5 known classes that implement Runnable. Checking each class recursively
1343 * to see if it extends Runnable is too time consuming, so we are hoping this short cut will work.
1344 * Clearly, this has some disadvantages.
1345 */
1346 public boolean implementsRunnable() {
1347 return this.getName().equals("java.lang.Thread") || this.getName().equals("java.util.TimerTask")
1348 || this.getName().equals("javax.swing.text.AsyncBoxView$ChildState")
1349 || this.getName().equals("java.awt.image.renderable.RenderableImageProducer")
1350 || this.getName().equals("java.util.concurrent.FutureTask");// || this.getName().equals("java.lang.Runnable");
1351 }
1352
1353 /**Check to see if the interface i appears anywhere in the hierarchy for this class/interface*/
1354 public boolean hasInterface(SymbolData i) {
1355 if (i == null) return false;
1356
1357 if (getInterfaces().contains(i)) { return true; }
1358
1359 if ((this.getSuperClass() != null) && this.getSuperClass().hasInterface(i)) { return true; }
1360
1361 for (int j = 0; j < getInterfaces().size(); j++) {
1362 if (getInterfaces().get(j).hasInterface(i)) return true;
1363 }
1364 return false;
1365 }
1366
1367 /**
1368 * Get all of your vars and all vars that you inherit.
1369 */
1370 public LinkedList<VariableData> getAllSuperVars() {
1371 LinkedList<VariableData> myVars = new LinkedList<VariableData>();
1372 if (this.getSuperClass() != null) {
1373 myVars.addAll(this.getSuperClass().getVars());
1374 myVars.addAll(this.getSuperClass().getAllSuperVars());
1375 }
1376 for (int i = 0; i<getInterfaces().size(); i++) {
1377 myVars.addAll(this.getInterfaces().get(i).getVars());
1378 myVars.addAll(this.getInterfaces().get(i).getAllSuperVars());
1379 }
1380 return myVars;
1381 }
1382
1383 /** Test the methods defined in the above class */
1384 public static class SymbolDataTest extends TestCase {
1385
1386 private SymbolData _sd;
1387
1388 private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
1389 private ModifiersAndVisibility _protectedMav =
1390 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
1391 private ModifiersAndVisibility _privateMav =
1392 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
1393 private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
1394 private ModifiersAndVisibility _abstractMav =
1395 new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
1396 private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
1397 private ModifiersAndVisibility _publicFinalMav =
1398 new ModifiersAndVisibility(SourceInfo.NONE, new String[]{"public", "final"});
1399
1400 public SymbolDataTest() {
1401 this("");
1402 }
1403 public SymbolDataTest(String name) {
1404 super(name);
1405 }
1406
1407 public void setUp() {
1408 _sd = new SymbolData("i.like.monkey");
1409 LanguageLevelVisitor.errors = new LinkedList<Pair<String, JExpressionIF>>();
1410 }
1411
1412 public void testRepeatedSignatures() {
1413 MethodData md = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1414 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1415 new VariableData(SymbolData.BOOLEAN_TYPE)},
1416 new String[0],
1417 _sd,
1418 null);
1419 md.getParams()[0].setEnclosingData(md);
1420 md.getParams()[1].setEnclosingData(md);
1421 LinkedList<MethodData> mds = new LinkedList<MethodData>();
1422 mds.addFirst(md);
1423 // Test same name, return type, and params from a source file.
1424 MethodData md2 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1425 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1426 new VariableData(SymbolData.BOOLEAN_TYPE) },
1427 new String[0],
1428 _sd,
1429 null);
1430 md2.getParams()[0].setEnclosingData(md2);
1431 md2.getParams()[1].setEnclosingData(md2);
1432
1433 assertTrue("repeatedSignatures should return md exactly.", md == _sd.repeatedSignature(mds, md2));
1434 // Test same name, return type, and params from a class file.
1435 MethodData md3 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1436 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1437 new VariableData(SymbolData.BOOLEAN_TYPE) },
1438 new String[0],
1439 _sd,
1440 null);
1441 md3.getParams()[0].setEnclosingData(md3);
1442 md3.getParams()[1].setEnclosingData(md3);
1443
1444 assertTrue("repeatedSignatures should return md exactly.", md == _sd.repeatedSignature(mds, md3, true));
1445 // Test same name, different return type, and params from a class file.
1446 MethodData md4 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE,
1447 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1448 new VariableData(SymbolData.BOOLEAN_TYPE) },
1449 new String[0],
1450 _sd,
1451 null);
1452 md4.getParams()[0].setEnclosingData(md4);
1453 md4.getParams()[1].setEnclosingData(md4);
1454
1455
1456 assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md4, true));
1457 // Test same name, return type, and different params from a source file.
1458 MethodData md5 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE,
1459 new VariableData[] { new VariableData(SymbolData.BOOLEAN_TYPE) },
1460 new String[0],
1461 _sd,
1462 null);
1463 md5.getParams()[0].setEnclosingData(md5);
1464
1465 assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md5));
1466 // Test same name, return type, and different order params from a source file.
1467 MethodData md6= new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE,
1468 new VariableData[] { new VariableData(SymbolData.BOOLEAN_TYPE),
1469 new VariableData(SymbolData.CHAR_TYPE) },
1470 new String[0],
1471 _sd,
1472 null);
1473 md6.getParams()[0].setEnclosingData(md6);
1474 md6.getParams()[1].setEnclosingData(md6);
1475
1476 assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md6));
1477 }
1478
1479 public void testCheckDifferentReturnTypes() {
1480
1481 TypeChecker.errors = new LinkedList<Pair<String, JExpressionIF>>();
1482
1483 // Create a super class and give it a method.
1484 SymbolData superSd = new SymbolData("superClass");
1485 MethodData md = new MethodData("methodName",
1486 _publicMav,
1487 new TypeParameter[0],
1488 SymbolData.INT_TYPE,
1489 new VariableData[0],
1490 new String[0],
1491 superSd,
1492 null);
1493 superSd.addMethod(md);
1494 _sd.setSuperClass(superSd);
1495 // Test with an exact copy of the method.
1496 MethodData md2 = new MethodData("methodName",
1497 _publicMav,
1498 new TypeParameter[0],
1499 SymbolData.INT_TYPE,
1500 new VariableData[0],
1501 new String[0],
1502 _sd,
1503 null);
1504 assertFalse("There should not be a conflict.", checkDifferentReturnTypes(md2, _sd, JavaVersion.JAVA_5));
1505 assertEquals("There should not be an error.", 0, TypeChecker.errors.size());
1506 // Test with an exact copy of the method except for differing return types.
1507 MethodData md3 = new MethodData("methodName",
1508 _publicMav,
1509 new TypeParameter[0],
1510 SymbolData.CHAR_TYPE,
1511 new VariableData[0],
1512 new String[0],
1513 _sd,
1514 null);
1515 assertTrue("There should be a conflict.", checkDifferentReturnTypes(md3, _sd, JavaVersion.JAVA_5));
1516 assertEquals("There should be one error.", 1, TypeChecker.errors.size());
1517 assertEquals("The error message should be correct.",
1518 "methodName() in i.like.monkey cannot override methodName() in superClass;" +
1519 " attempting to use different return types",
1520 TypeChecker.errors.get(0).getFirst());
1521 // Create a super super class and give it a method.
1522 SymbolData superSuperSd = new SymbolData("superSuperClass");
1523 MethodData md4 = new MethodData("superSuperMethodName",
1524 _publicMav,
1525 new TypeParameter[0],
1526 SymbolData.INT_TYPE,
1527 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1528 new String[0],
1529 superSuperSd,
1530 null);
1531 md4.getParams()[0].setEnclosingData(md4);
1532 superSuperSd.addMethod(md4);
1533 superSd.setSuperClass(superSuperSd);
1534 // Test with an exact copy except for differing parameters.
1535 MethodData md5 = new MethodData("superSuperMethodName",
1536 _publicMav,
1537 new TypeParameter[0],
1538 SymbolData.INT_TYPE,
1539 new VariableData[0],
1540 new String[0],
1541 null,
1542 null);
1543 assertFalse("There should not be a conflict.", checkDifferentReturnTypes(md5, _sd, JavaVersion.JAVA_5));
1544 assertEquals("There should still be one error.", 1, TypeChecker.errors.size());
1545 // Test with an exact copy except for diffeing return types.
1546 MethodData md6 = new MethodData("superSuperMethodName",
1547 _publicMav,
1548 new TypeParameter[0],
1549 SymbolData.BYTE_TYPE,
1550 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1551 new String[0],
1552 null,
1553 null);
1554 md6.getParams()[0].setEnclosingData(md6);
1555 assertTrue("There should be a conflict.", checkDifferentReturnTypes(md6, _sd, JavaVersion.JAVA_5));
1556 assertEquals("There should be two errors.", 2, TypeChecker.errors.size());
1557
1558 //Test a method that restricts the mav of the super class's method
1559 MethodData md7 = new MethodData("superSuperMethodName",
1560 _privateMav,
1561 new TypeParameter[0],
1562 SymbolData.INT_TYPE,
1563 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1564 new String[0],
1565 new SymbolData("myData"),
1566 null);
1567
1568 md7.getParams()[0].setEnclosingData(md7);
1569 assertTrue("There should be a conflict", checkDifferentReturnTypes(md7, _sd, JavaVersion.JAVA_5));
1570 assertEquals("There should be three errors", 3, TypeChecker.errors.size());
1571 assertEquals("The error message should be correct",
1572 "superSuperMethodName in myData cannot override superSuperMethodName in " + superSuperSd.getName() +
1573 ". You are attempting to assign weaker access priviledges. In " + superSuperSd.getName() +
1574 ", superSuperMethodName was public", TypeChecker.errors.get(2).getFirst());
1575
1576
1577 //Test a method that narrows the return type of the super class's method
1578 SymbolData stringSd = new SymbolData("java.lang.String");
1579 stringSd.setIsContinuation(false);
1580 stringSd.setSuperClass(SymbolData.INT_TYPE);
1581
1582 MethodData md8 = new MethodData("superSuperMethodName",
1583 _publicMav,
1584 new TypeParameter[0],
1585 stringSd,
1586 new VariableData[] {new VariableData(SymbolData.CHAR_TYPE)},
1587 new String[0],
1588 new SymbolData("myData"),
1589 null);
1590
1591 assertFalse("There should be no conflict", checkDifferentReturnTypes(md8, _sd, JavaVersion.JAVA_5));
1592 assertEquals("There should still be 3 errors", 3, TypeChecker.errors.size());
1593 /* Java 1.4 is not supported. */
1594 // assertTrue("There should be a conflict in 1.4", checkDifferentReturnTypes(md8, _sd, JavaVersion.JAVA_1_4));
1595 // assertEquals("There should now be 4 errors", 4, TypeChecker.errors.size());
1596 // assertEquals("The error message should be correct", TypeChecker.errors.getLast().getFirst(),
1597 // "superSuperMethodName(char) in superClass cannot override superSuperMethodName(char) in " +
1598 // superSuperSd.getName() + "; attempting to use different return types");
1599 }
1600
1601 public void test_createErrorMessage() {
1602 // Test with a method with no parameters.
1603 MethodData md = new MethodData("methodName",
1604 _publicMav,
1605 new TypeParameter[0],
1606 SymbolData.INT_TYPE,
1607 new VariableData[0],
1608 new String[0],
1609 _sd,
1610 null);
1611 assertEquals("The error message should be correct.",
1612 "In the class \"i.like.monkey\", you cannot have two methods with the same name: \"methodName\"",
1613 _sd._createErrorMessage(md));
1614 // Test with a method with one parameter.
1615 MethodData md2 = new MethodData("superSuperMethodName",
1616 _publicMav,
1617 new TypeParameter[0],
1618 SymbolData.INT_TYPE,
1619 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1620 new String[0],
1621 _sd,
1622 null);
1623 assertEquals("The error message should be correct.",
1624 "In the class \"i.like.monkey\", you cannot have two methods with the same name: "
1625 + "\"superSuperMethodName\" and parameter type: char",
1626 _sd._createErrorMessage(md2));
1627 md2.getParams()[0].setEnclosingData(md2);
1628 // Test with a method with two parameters.
1629 MethodData md3 = new MethodData("superSuperMethodName",
1630 _publicMav,
1631 new TypeParameter[0],
1632 SymbolData.INT_TYPE,
1633 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1634 new VariableData(SymbolData.CHAR_TYPE) },
1635 new String[0],
1636 _sd,
1637 null);
1638 md3.getParams()[0].setEnclosingData(md3);
1639 md3.getParams()[1].setEnclosingData(md3);
1640
1641 assertEquals("The error message should be correct.",
1642 "In the class \"i.like.monkey\", you cannot have two methods with the same name: "
1643 + "\"superSuperMethodName\" and parameter types: char, char",
1644 _sd._createErrorMessage(md3));
1645
1646 }
1647
1648 public void testAddMethod() {
1649 MethodData md = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1650 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1651 new VariableData(SymbolData.BOOLEAN_TYPE)},
1652 new String[0],
1653 _sd,
1654 null);
1655
1656 md.getParams()[0].setEnclosingData(md);
1657 md.getParams()[1].setEnclosingData(md);
1658
1659 _sd.addMethod(md);
1660 assertEquals("There should be no errors.", 0, LanguageLevelVisitor.errors.size());
1661 // Test same name, return type, and params from a source file.
1662 MethodData md2 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
1663 new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1664 new VariableData(SymbolData.BOOLEAN_TYPE) },
1665 new String[0],
1666 _sd,
1667 null);
1668 md2.getParams()[0].setEnclosingData(md2);
1669 md2.getParams()[1].setEnclosingData(md2);
1670
1671 _sd.addMethod(md2);
1672 assertEquals("There should be one error.", 1, LanguageLevelVisitor.errors.size());
1673 assertEquals("The error message should be correct.", "In the class \"" + _sd.getName() +
1674 "\", you cannot have two methods with the same name: \"" + md.getName()
1675 + "\" and parameter types: char, boolean",
1676 LanguageLevelVisitor.errors.get(0).getFirst());
1677 MethodData md4 = new MethodData("methodName",
1678 _publicMav,
1679 new TypeParameter[0],
1680 SymbolData.INT_TYPE,
1681 new VariableData[0],
1682 new String[0],
1683 _sd,
1684 null);
1685 _sd.addMethod(md4);
1686 assertEquals("There should still be one error.", 1, LanguageLevelVisitor.errors.size());
1687 MethodData md5 = new MethodData("methodNamePlusStuff",
1688 _publicMav,
1689 new TypeParameter[0],
1690 SymbolData.INT_TYPE,
1691 new VariableData[0],
1692 new String[0],
1693 _sd,
1694 null);
1695 _sd.addMethod(md5);
1696 assertEquals("There should still be one error.", 1, LanguageLevelVisitor.errors.size());
1697 // Check that _sd only has two methods, the original md and md5.
1698 assertEquals("There are three methods in _sd.", 3, _sd.getMethods().size());
1699 assertEquals("The original method was added.", md, _sd.getMethods().get(0));
1700 assertEquals("md5 was added.", md5, _sd.getMethods().get(2));
1701
1702 // Check that adding a method from augmented code produces the correct error message.
1703 _sd.addMethod(md2, true);
1704 assertEquals("There should be two errors.", 2, LanguageLevelVisitor.errors.size());
1705 assertEquals("The error message should be correct.",
1706 "This method's signature conflicts with an automatically generated method's signature",
1707 LanguageLevelVisitor.errors.get(1).getFirst());
1708 }
1709
1710 public void testIsNumberType() {
1711 assertTrue(SymbolData.INT_TYPE.isNumberType(JavaVersion.JAVA_5));
1712 assertTrue(new SymbolData("java.lang.Integer").isNumberType(JavaVersion.JAVA_5));
1713 assertTrue(SymbolData.DOUBLE_TYPE.isNumberType(JavaVersion.JAVA_5));
1714 assertTrue(new SymbolData("java.lang.Double").isNumberType(JavaVersion.JAVA_5));
1715 assertTrue(SymbolData.LONG_TYPE.isNumberType(JavaVersion.JAVA_5));
1716 assertTrue(new SymbolData("java.lang.Long").isNumberType(JavaVersion.JAVA_5));
1717 assertTrue(SymbolData.CHAR_TYPE.isNumberType(JavaVersion.JAVA_5));
1718 assertTrue(new SymbolData("java.lang.Character").isNumberType(JavaVersion.JAVA_5));
1719 assertTrue(SymbolData.FLOAT_TYPE.isNumberType(JavaVersion.JAVA_5));
1720 assertTrue(new SymbolData("java.lang.Float").isNumberType(JavaVersion.JAVA_5));
1721 assertTrue(SymbolData.SHORT_TYPE.isNumberType(JavaVersion.JAVA_5));
1722 assertTrue(new SymbolData("java.lang.Short").isNumberType(JavaVersion.JAVA_5));
1723 assertTrue(SymbolData.BYTE_TYPE.isNumberType(JavaVersion.JAVA_5));
1724 assertTrue(new SymbolData("java.lang.Byte").isNumberType(JavaVersion.JAVA_5));
1725 assertFalse(SymbolData.BOOLEAN_TYPE.isNumberType(JavaVersion.JAVA_5));
1726 assertFalse(new SymbolData("java.lang.Boolean").isNumberType(JavaVersion.JAVA_5));
1727 }
1728
1729 public void testIsNumberTypeWithoutAutoboxing() {
1730 assertTrue(SymbolData.INT_TYPE.isNumberTypeWithoutAutoboxing());
1731 assertFalse((new SymbolData("java.lang.Integer")).isNumberTypeWithoutAutoboxing());
1732 assertTrue(SymbolData.DOUBLE_TYPE.isNumberTypeWithoutAutoboxing());
1733 assertFalse((new SymbolData("java.lang.Double")).isNumberTypeWithoutAutoboxing());
1734 assertTrue(SymbolData.LONG_TYPE.isNumberTypeWithoutAutoboxing());
1735 assertFalse((new SymbolData("java.lang.Long")).isNumberTypeWithoutAutoboxing());
1736 assertTrue(SymbolData.CHAR_TYPE.isNumberTypeWithoutAutoboxing());
1737 assertFalse((new SymbolData("java.lang.Character")).isNumberTypeWithoutAutoboxing());
1738 assertTrue(SymbolData.FLOAT_TYPE.isNumberTypeWithoutAutoboxing());
1739 assertFalse((new SymbolData("java.lang.Float")).isNumberTypeWithoutAutoboxing());
1740 assertTrue(SymbolData.SHORT_TYPE.isNumberTypeWithoutAutoboxing());
1741 assertFalse((new SymbolData("java.lang.Short")).isNumberTypeWithoutAutoboxing());
1742 assertTrue(SymbolData.BYTE_TYPE.isNumberTypeWithoutAutoboxing());
1743 assertFalse((new SymbolData("java.lang.Byte")).isNumberTypeWithoutAutoboxing());
1744 assertFalse(SymbolData.BOOLEAN_TYPE.isNumberTypeWithoutAutoboxing());
1745 assertFalse((new SymbolData("java.lang.Boolean")).isNumberTypeWithoutAutoboxing());
1746 }
1747
1748
1749 public void testIsIntType() {
1750 assertTrue(SymbolData.INT_TYPE.isIntType(JavaVersion.JAVA_5));
1751 assertTrue((new SymbolData("java.lang.Integer")).isIntType(JavaVersion.JAVA_5));
1752 assertFalse(SymbolData.DOUBLE_TYPE.isIntType(JavaVersion.JAVA_5));
1753 assertFalse((new SymbolData("java.lang.Double")).isIntType(JavaVersion.JAVA_5));
1754 assertFalse(SymbolData.LONG_TYPE.isIntType(JavaVersion.JAVA_5));
1755 assertFalse((new SymbolData("java.lang.Long")).isIntType(JavaVersion.JAVA_5));
1756 assertFalse(SymbolData.CHAR_TYPE.isIntType(JavaVersion.JAVA_5));
1757 assertFalse((new SymbolData("java.lang.Character")).isIntType(JavaVersion.JAVA_5));
1758 assertFalse(SymbolData.FLOAT_TYPE.isIntType(JavaVersion.JAVA_5));
1759 assertFalse((new SymbolData("java.lang.Float")).isIntType(JavaVersion.JAVA_5));
1760 assertFalse(SymbolData.SHORT_TYPE.isIntType(JavaVersion.JAVA_5));
1761 assertFalse((new SymbolData("java.lang.Short")).isIntType(JavaVersion.JAVA_5));
1762 assertFalse(SymbolData.BYTE_TYPE.isIntType(JavaVersion.JAVA_5));
1763 assertFalse((new SymbolData("java.lang.Byte")).isIntType(JavaVersion.JAVA_5));
1764 assertFalse(SymbolData.BOOLEAN_TYPE.isIntType(JavaVersion.JAVA_5));
1765 assertFalse((new SymbolData("java.lang.Boolean")).isIntType(JavaVersion.JAVA_5));
1766 }
1767
1768
1769 public void testIsDoubleType() {
1770 assertFalse(SymbolData.INT_TYPE.isDoubleType(JavaVersion.JAVA_5));
1771 assertFalse((new SymbolData("java.lang.Integer")).isDoubleType(JavaVersion.JAVA_5));
1772 assertTrue(SymbolData.DOUBLE_TYPE.isDoubleType(JavaVersion.JAVA_5));
1773 assertTrue((new SymbolData("java.lang.Double")).isDoubleType(JavaVersion.JAVA_5));
1774 assertFalse(SymbolData.CHAR_TYPE.isDoubleType(JavaVersion.JAVA_5));
1775 assertFalse((new SymbolData("java.lang.Character")).isDoubleType(JavaVersion.JAVA_5));
1776 assertFalse(SymbolData.FLOAT_TYPE.isDoubleType(JavaVersion.JAVA_5));
1777 assertFalse((new SymbolData("java.lang.Float")).isDoubleType(JavaVersion.JAVA_5));
1778 assertFalse(SymbolData.SHORT_TYPE.isDoubleType(JavaVersion.JAVA_5));
1779 assertFalse((new SymbolData("java.lang.Short")).isDoubleType(JavaVersion.JAVA_5));
1780 assertFalse(SymbolData.BYTE_TYPE.isDoubleType(JavaVersion.JAVA_5));
1781 assertFalse((new SymbolData("java.lang.Byte")).isDoubleType(JavaVersion.JAVA_5));
1782 assertFalse(SymbolData.BOOLEAN_TYPE.isDoubleType(JavaVersion.JAVA_5));
1783 assertFalse((new SymbolData("java.lang.Boolean")).isDoubleType(JavaVersion.JAVA_5));
1784 }
1785
1786 public void testIsCharType() {
1787 assertFalse(SymbolData.INT_TYPE.isCharType(JavaVersion.JAVA_5));
1788 assertFalse((new SymbolData("java.lang.Integer")).isCharType(JavaVersion.JAVA_5));
1789 assertFalse(SymbolData.DOUBLE_TYPE.isCharType(JavaVersion.JAVA_5));
1790 assertFalse((new SymbolData("java.lang.Double")).isCharType(JavaVersion.JAVA_5));
1791 assertTrue(SymbolData.CHAR_TYPE.isCharType(JavaVersion.JAVA_5));
1792 assertTrue((new SymbolData("java.lang.Character")).isCharType(JavaVersion.JAVA_5));
1793 assertFalse(SymbolData.FLOAT_TYPE.isCharType(JavaVersion.JAVA_5));
1794 assertFalse((new SymbolData("java.lang.Float")).isCharType(JavaVersion.JAVA_5));
1795 assertFalse(SymbolData.SHORT_TYPE.isCharType(JavaVersion.JAVA_5));
1796 assertFalse((new SymbolData("java.lang.Short")).isCharType(JavaVersion.JAVA_5));
1797 assertFalse(SymbolData.BYTE_TYPE.isCharType(JavaVersion.JAVA_5));
1798 assertFalse((new SymbolData("java.lang.Byte")).isCharType(JavaVersion.JAVA_5));
1799 assertFalse(SymbolData.BOOLEAN_TYPE.isCharType(JavaVersion.JAVA_5));
1800 assertFalse((new SymbolData("java.lang.Boolean")).isCharType(JavaVersion.JAVA_5));
1801 }
1802
1803 public void testIsFloatType() {
1804 assertFalse(SymbolData.INT_TYPE.isFloatType(JavaVersion.JAVA_5));
1805 assertFalse((new SymbolData("java.lang.Integer")).isFloatType(JavaVersion.JAVA_5));
1806 assertFalse(SymbolData.DOUBLE_TYPE.isFloatType(JavaVersion.JAVA_5));
1807 assertFalse((new SymbolData("java.lang.Double")).isFloatType(JavaVersion.JAVA_5));
1808 assertFalse(SymbolData.CHAR_TYPE.isFloatType(JavaVersion.JAVA_5));
1809 assertFalse((new SymbolData("java.lang.Character")).isFloatType(JavaVersion.JAVA_5));
1810 assertTrue(SymbolData.FLOAT_TYPE.isFloatType(JavaVersion.JAVA_5));
1811 assertTrue((new SymbolData("java.lang.Float")).isFloatType(JavaVersion.JAVA_5));
1812 assertFalse(SymbolData.SHORT_TYPE.isFloatType(JavaVersion.JAVA_5));
1813 assertFalse((new SymbolData("java.lang.Short")).isFloatType(JavaVersion.JAVA_5));
1814 assertFalse(SymbolData.BYTE_TYPE.isFloatType(JavaVersion.JAVA_5));
1815 assertFalse((new SymbolData("java.lang.Byte")).isFloatType(JavaVersion.JAVA_5));
1816 assertFalse(SymbolData.BOOLEAN_TYPE.isFloatType(JavaVersion.JAVA_5));
1817 assertFalse((new SymbolData("java.lang.Boolean")).isFloatType(JavaVersion.JAVA_5));
1818 }
1819
1820
1821 public void testIsByteType() {
1822 assertFalse(SymbolData.INT_TYPE.isByteType(JavaVersion.JAVA_5));
1823 assertFalse((new SymbolData("java.lang.Integer")).isByteType(JavaVersion.JAVA_5));
1824 assertFalse(SymbolData.DOUBLE_TYPE.isByteType(JavaVersion.JAVA_5));
1825 assertFalse((new SymbolData("java.lang.Double")).isByteType(JavaVersion.JAVA_5));
1826 assertFalse(SymbolData.CHAR_TYPE.isByteType(JavaVersion.JAVA_5));
1827 assertFalse((new SymbolData("java.lang.Character")).isByteType(JavaVersion.JAVA_5));
1828 assertFalse(SymbolData.FLOAT_TYPE.isByteType(JavaVersion.JAVA_5));
1829 assertFalse((new SymbolData("java.lang.Float")).isByteType(JavaVersion.JAVA_5));
1830 assertFalse(SymbolData.SHORT_TYPE.isByteType(JavaVersion.JAVA_5));
1831 assertFalse((new SymbolData("java.lang.Short")).isByteType(JavaVersion.JAVA_5));
1832 assertTrue(SymbolData.BYTE_TYPE.isByteType(JavaVersion.JAVA_5));
1833 assertTrue((new SymbolData("java.lang.Byte")).isByteType(JavaVersion.JAVA_5));
1834 assertFalse(SymbolData.BOOLEAN_TYPE.isByteType(JavaVersion.JAVA_5));
1835 assertFalse((new SymbolData("java.lang.Boolean")).isByteType(JavaVersion.JAVA_5));
1836 }
1837
1838 public void testIsBooleanType() {
1839 assertFalse(SymbolData.INT_TYPE.isBooleanType(JavaVersion.JAVA_5));
1840 assertFalse((new SymbolData("java.lang.Integer")).isBooleanType(JavaVersion.JAVA_5));
1841 assertFalse(SymbolData.DOUBLE_TYPE.isBooleanType(JavaVersion.JAVA_5));
1842 assertFalse((new SymbolData("java.lang.Double")).isBooleanType(JavaVersion.JAVA_5));
1843 assertFalse(SymbolData.CHAR_TYPE.isBooleanType(JavaVersion.JAVA_5));
1844 assertFalse((new SymbolData("java.lang.Character")).isBooleanType(JavaVersion.JAVA_5));
1845 assertFalse(SymbolData.FLOAT_TYPE.isBooleanType(JavaVersion.JAVA_5));
1846 assertFalse((new SymbolData("java.lang.Float")).isBooleanType(JavaVersion.JAVA_5));
1847 assertFalse(SymbolData.SHORT_TYPE.isBooleanType(JavaVersion.JAVA_5));
1848 assertFalse((new SymbolData("java.lang.Short")).isBooleanType(JavaVersion.JAVA_5));
1849 assertFalse(SymbolData.BYTE_TYPE.isBooleanType(JavaVersion.JAVA_5));
1850 assertFalse((new SymbolData("java.lang.Byte")).isBooleanType(JavaVersion.JAVA_5));
1851 assertTrue(SymbolData.BOOLEAN_TYPE.isBooleanType(JavaVersion.JAVA_5));
1852 assertTrue((new SymbolData("java.lang.Boolean")).isBooleanType(JavaVersion.JAVA_5));
1853 }
1854
1855 public void testIsNonFloatOrBooleanType() {
1856 assertTrue(SymbolData.INT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1857 assertTrue(new SymbolData("java.lang.Integer").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1858 assertFalse(SymbolData.DOUBLE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1859 assertFalse(new SymbolData("java.lang.Double").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1860 assertTrue(SymbolData.CHAR_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1861 assertTrue(new SymbolData("java.lang.Character").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1862 assertFalse(SymbolData.FLOAT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1863 assertFalse(new SymbolData("java.lang.Float").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1864 assertTrue(SymbolData.SHORT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1865 assertTrue(new SymbolData("java.lang.Short").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1866 assertTrue(SymbolData.BYTE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1867 assertTrue(new SymbolData("java.lang.Byte").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1868 assertTrue(SymbolData.LONG_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1869 assertTrue(new SymbolData("java.lang.Long").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1870 assertTrue(SymbolData.BOOLEAN_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1871 assertTrue(new SymbolData("java.lang.Boolean").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1872
1873 }
1874
1875 public void testIsNonFloatOrBooleanTypeWithoutAutoboxing() {
1876 assertTrue(SymbolData.INT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1877 assertFalse(SymbolData.DOUBLE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1878 assertTrue(SymbolData.CHAR_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1879 assertFalse(SymbolData.FLOAT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1880 assertTrue(SymbolData.SHORT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1881 assertTrue(SymbolData.BYTE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1882 assertTrue(SymbolData.LONG_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1883 assertTrue(SymbolData.BOOLEAN_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1884 }
1885
1886
1887 public void testEquals() {
1888 SymbolData superSd = new SymbolData("superClass");
1889 _sd =
1890 new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1891
1892 //check variables that are equal;
1893 SymbolData _sd2 =
1894 new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1895 assertTrue("Equals should return true if two SymbolDatas are equal", _sd.equals(_sd2));
1896 assertTrue("Equals should return true in opposite direction as well", _sd2.equals(_sd));
1897
1898 //comparison to null
1899 assertFalse("Equals should return false if SymbolData is compared to null",_sd.equals(null));
1900
1901 //different names
1902 _sd2 = new SymbolData("q", _publicMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1903 assertFalse("Equals should return false if class names are different", _sd.equals(_sd2));
1904
1905 //different MAV
1906 _sd2 =
1907 new SymbolData("i.like.monkey", _protectedMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1908 assertFalse("Equals should return false if class modifiers are different", _sd.equals(_sd2));
1909
1910 //different type parameters
1911 _sd2 =
1912 new SymbolData("i.like.monkey",
1913 _publicMav,
1914 new TypeParameter[] { new TypeParameter(SourceInfo.NONE,
1915 new TypeVariable(SourceInfo.NONE,"tv"),
1916 new TypeVariable(SourceInfo.NONE,"i")) },
1917 superSd,
1918 new ArrayList<SymbolData>(), null);
1919 assertFalse("Equals should return false if class type parameters are different", _sd.equals(_sd2));
1920
1921 //different super classes
1922 _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], null, new ArrayList<SymbolData>(), null);
1923 assertFalse("Equals should return false if super classes are different", _sd.equals(_sd2));
1924
1925 //different interfaces
1926 ArrayList<SymbolData> interfaces = new ArrayList<SymbolData>();
1927 interfaces.add(SymbolData.INT_TYPE);
1928 _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, interfaces, null);
1929 assertFalse("Equals should return false if the interfaces are different", _sd.equals(_sd2));
1930 }
1931
1932 public void testImplementsRunnable() {
1933 SymbolData sd1 = new SymbolData("java.lang.Thread");
1934 SymbolData sd2 = new SymbolData("java.util.TimerTask");
1935 SymbolData sd3 = new SymbolData("javax.swing.text.AsyncBoxView$ChildState");
1936 SymbolData sd4 = new SymbolData("java.awt.image.renderable.RenderableImageProducer");
1937 SymbolData sd5 = new SymbolData("java.util.concurrent.FutureTask");
1938 SymbolData sd6 = new SymbolData("java.util.Vector");
1939 assertTrue("Should implement Runnable", sd1.implementsRunnable());
1940 assertTrue("Should implement Runnable", sd2.implementsRunnable());
1941 assertTrue("Should implement Runnable", sd3.implementsRunnable());
1942 assertTrue("Should implement Runnable", sd4.implementsRunnable());
1943 assertTrue("Should implement Runnable", sd5.implementsRunnable());
1944 assertFalse("Should not implement Runnable", sd6.implementsRunnable());
1945 }
1946
1947 public void testHasInterface() {
1948 /* Runnable has two subinterfacers, subRunnable and subRunnable2. subRunnable has a subclass someSd and
1949 subRunnable2 has a subclass someOtherSd. */
1950
1951 SymbolData runnable = new SymbolData("java.lang.Runnable");
1952 runnable.setInterface(true);
1953 SymbolData subRunnable = new SymbolData("edgar");
1954 subRunnable.setInterface(true);
1955 subRunnable.addInterface(runnable);
1956 assertTrue(subRunnable.hasInterface(runnable));
1957 SymbolData subRunnable2 = new SymbolData("jones");
1958 subRunnable2.setInterface(true);
1959 subRunnable2.addInterface(runnable);
1960 assertTrue(subRunnable2.hasInterface(runnable));
1961 SymbolData someSd = new SymbolData("someSd");
1962 someSd.addInterface(subRunnable);
1963 assertTrue(someSd.hasInterface(runnable));
1964 SymbolData someOtherSd = new SymbolData("someOtherSd");
1965 someOtherSd.addInterface(subRunnable2);
1966 assertTrue(someOtherSd.hasInterface(runnable));
1967 SymbolData notRunnable = new SymbolData("aksdf");
1968 assertFalse(notRunnable.hasInterface(runnable));
1969 someOtherSd.addInterface(notRunnable);
1970 assertTrue(someOtherSd.hasInterface(runnable));
1971
1972 // Try myClass without setting a super class, then try it once it's super class is someSd.
1973 SymbolData myClass = new SymbolData("myClass");
1974 assertFalse(myClass.hasInterface(runnable));
1975 myClass.setSuperClass(someSd);
1976 assertTrue(myClass.hasInterface(runnable));
1977 SymbolData myClass2 = new SymbolData("myClass2");
1978 assertFalse(myClass2.hasInterface(runnable));
1979 myClass2.addInterface(someOtherSd);
1980 assertTrue(myClass2.hasInterface(runnable));
1981 }
1982
1983 public void test_isAssignable() {
1984 MethodData md =
1985 new MethodData("Overwritten", _publicMav, new TypeParameter[0], _sd, new VariableData[0], new String[0], _sd,
1986 new NullLiteral(SourceInfo.NONE));
1987 MethodData md2 =
1988 new MethodData("Overwriting", _publicMav, new TypeParameter[0], _sd, new VariableData[0], new String[0], _sd,
1989 new NullLiteral(SourceInfo.NONE));
1990
1991 //tests a wide variety of possibilities, but not all possibilities.
1992 assertTrue("Should be assignable", _isCompatible(md, md2));
1993 md.setMav(_protectedMav);
1994 assertTrue("Should be assignable", _isCompatible(md, md2));
1995 md.setMav(_privateMav);
1996 assertTrue("Should be assignable", _isCompatible(md, md2));
1997 md.setMav(_packageMav);
1998 assertTrue("Should be assignable", _isCompatible(md, md2));
1999 md2.setMav(_protectedMav);
2000 assertTrue("Should be assignable", _isCompatible(md, md2));
2001 md2.setMav(_privateMav);
2002 assertFalse("Should not be assignable", _isCompatible(md, md2));
2003 md2.setMav(_packageMav);
2004 assertTrue("Should be assignable", _isCompatible(md, md2));
2005
2006 }
2007
2008
2009 public void testRepeatedNameInHierarchy() {
2010 SymbolData _d = new SymbolData("myname");
2011
2012 VariableData vd = new VariableData("v1", _publicMav, SymbolData.INT_TYPE, false, _d);
2013
2014 //compare a vd to an symbol data with no vars
2015 assertFalse("No variables to repeat name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2016
2017 //compare a vd to a symbol data with 1 var with a different name
2018 _d.addVar(new VariableData("v2", _protectedMav, SymbolData.BOOLEAN_TYPE, true, _d));
2019 assertFalse("No repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2020
2021 //compare a vd to a symbol data who has a var with the same name
2022 _d.addVar(vd);
2023 assertTrue("Should be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2024
2025 //what if super class has var
2026 _d.setVars(new LinkedList<VariableData>());
2027 SymbolData superC = new SymbolData("I am a super class");
2028 superC.addVar(new VariableData(vd.getName(), _protectedMav, SymbolData.DOUBLE_TYPE, false, superC));
2029 _d.setSuperClass(superC);
2030 assertTrue("Should be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2031
2032 //what if interface has var
2033 _d.clearSuperClass();
2034 _d.addInterface(superC);
2035 assertTrue("Should also be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2036 }
2037
2038 public void testAddFinalVars() {
2039 SymbolData _d = new SymbolData("genius");
2040 VariableData vd = new VariableData("v1", _publicMav, SymbolData.INT_TYPE, true, _d);
2041 VariableData vd2 = new VariableData("v2", _publicMav, SymbolData.CHAR_TYPE, true, _d);
2042 VariableData[] toAdd = new VariableData[] {vd, vd2};
2043 LinkedList<VariableData> myVds = new LinkedList<VariableData>();
2044
2045 //first adding array
2046 myVds.addLast(vd);
2047 myVds.addLast(vd2);
2048 assertTrue("Should be able to add new vars array", _d.addFinalVars(toAdd));
2049 assertEquals("Variable list should have 2 variables", myVds, _d.getVars());
2050
2051 //trying to read array whose variables are already there.
2052 assertFalse("Should not be able to add same variables again", _d.addFinalVars(toAdd));
2053 assertEquals("Variable list should not have changed", myVds, _d.getVars());
2054 assertTrue("vd should now be final", _d.getVars().get(0).hasModifier("final"));
2055 assertTrue("vd2 should now be final", _d.getVars().get(1).hasModifier("final"));
2056
2057
2058
2059 //trying to add a different array
2060 VariableData vd3 = new VariableData("v3", _publicFinalMav, SymbolData.INT_TYPE, true, _d);
2061 VariableData[] toAdd2 = new VariableData[] {vd3};
2062 myVds.addLast(vd3);
2063
2064 assertTrue("Should be able to add new variable array", _d.addFinalVars(toAdd2));
2065 assertEquals("Variable list should now have 3 variables", myVds, _d.getVars());
2066 assertTrue("vd3 should now be final", _d.getVars().get(2).hasModifier("final"));
2067
2068
2069 //try adding an empty array of variable datas
2070 assertTrue("Should be able to add an empty array", _d.addFinalVars(new VariableData[0]));
2071 assertEquals("Variable list should not have changed by adding empty array", myVds, _d.getVars());
2072 }
2073
2074 public void testGetAllVars() {
2075 SymbolData sd1 = new SymbolData("SubSub");
2076 SymbolData sd2 = new SymbolData("Sub");
2077 SymbolData sd3 = new SymbolData("Super");
2078 SymbolData sd4 = new SymbolData("SuperInterface");
2079 sd4.setInterface(true);
2080 SymbolData sd5 = new SymbolData("NotRelated");
2081
2082 sd1.setSuperClass(sd2);
2083 sd2.setSuperClass(sd3);
2084 sd2.addInterface(sd4);
2085
2086 VariableData vd1 = new VariableData("vd1", _finalMav, SymbolData.INT_TYPE, false, sd1);
2087 VariableData vd2 = new VariableData("vd2", _finalMav, SymbolData.INT_TYPE, false, sd2);
2088 VariableData vd3 = new VariableData("vd3", _finalMav, SymbolData.INT_TYPE, false, sd3);
2089 VariableData vd4 = new VariableData("vd4", _finalMav, SymbolData.INT_TYPE, false, sd4);
2090 VariableData vd5 = new VariableData("vd5", _finalMav, SymbolData.INT_TYPE, false, sd5);
2091
2092 sd1.addVar(vd1);
2093 sd2.addVar(vd2);
2094 sd3.addVar(vd3);
2095 sd4.addVar(vd4);
2096 sd5.addVar(vd5);
2097
2098 LinkedList<VariableData> shouldContain = new LinkedList<VariableData>();
2099 shouldContain.addLast(vd2);
2100 shouldContain.addLast(vd3);
2101 shouldContain.addLast(vd4);
2102
2103 LinkedList<VariableData> vds = sd1.getAllSuperVars();
2104 assertEquals("the list should have 3 elements", 3, vds.size());
2105 assertEquals("The list should be correct", shouldContain, vds);
2106 }
2107
2108 public void testIsSubclassOf() {
2109 _sd = new SymbolData("subClass");
2110 SymbolData superC = new SymbolData("superC");
2111 _sd._superClass = superC;
2112
2113 //not subclass
2114 assertFalse("subClass, int, and boolean are not related", _sd.isSubClassOf(SymbolData.BOOLEAN_TYPE));
2115
2116 //same class
2117 assertTrue("subClass is a subclass of itself", _sd.isSubClassOf(_sd));
2118
2119 //direct subclass
2120 assertTrue("subClass is a subclass of its super class", _sd.isSubClassOf(superC));
2121
2122 //subclass of subclass of provided data
2123 superC._superClass = SymbolData.CHAR_TYPE;
2124 assertTrue("subClass is a subclass of its super class's super class", _sd.isSubClassOf(SymbolData.CHAR_TYPE));
2125
2126 //Interface
2127 SymbolData myData = new SymbolData("yes");
2128 SymbolData yourData = new SymbolData("interface");
2129 yourData.setInterface(true);
2130 myData.setIsContinuation(false);
2131 myData.addInterface(yourData);
2132 yourData.setIsContinuation(false);
2133 assertTrue("Should be assignable", myData.isSubClassOf(yourData));
2134 }
2135
2136 public void testIsInnerClassOf() {
2137 _sd = new SymbolData("innerClass");
2138 SymbolData outer1 = new SymbolData("outer1");
2139 outer1.addInnerClass(_sd);
2140 _sd.setOuterData(outer1);
2141 SymbolData outer2 = new SymbolData("outer2");
2142 outer2.addInnerClass(outer1);
2143 outer1.setOuterData(outer2);
2144 outer2.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static"}));
2145 SymbolData outer3 = new SymbolData("outer3");
2146 outer3.addInnerClass(outer2);
2147 outer2.setOuterData(outer3);
2148
2149
2150 SymbolData notInChain = new SymbolData("no");
2151
2152 assertTrue("_sd is an inner class of itself", _sd.isInnerClassOf(_sd, true));
2153 assertTrue("outer1 is the outer class of _sd", _sd.isInnerClassOf(outer1, true));
2154 assertTrue("outer2 is an outer class of _sd", _sd.isInnerClassOf(outer2, true));
2155 assertTrue("outer2 is an outer class of itself", outer2.isInnerClassOf(outer2, true));
2156 assertFalse("_sd is not related to notInChain", _sd.isInnerClassOf(notInChain, true));
2157 assertFalse("_sd is not an outer class of outer1", outer1.isInnerClassOf(_sd, true));
2158 assertFalse("outer3 cannot be seen from _sd if the static flag is true, because outer2 is static",
2159 _sd.isInnerClassOf(outer3, true));
2160 assertTrue("But, outer3 is an outer class of _sd", _sd.isInnerClassOf(outer3, false));
2161 }
2162
2163 public void testCreateUniqueMethodName() {
2164 SymbolData george = new SymbolData("George");
2165 VariableData[] noVars = new VariableData[0];
2166 george.addMethod(new MethodData("getFriends", noVars));
2167 george.addMethod(new MethodData("sayHello", noVars));
2168
2169 SymbolData iAteGeorge = new SymbolData("IAteGeorge");
2170 iAteGeorge.addMethod(new MethodData("sayHello", noVars));
2171 iAteGeorge.addMethod(new MethodData("sayHello0", noVars));
2172 iAteGeorge.addInnerClass(george);
2173 george.setOuterData(iAteGeorge);
2174
2175 SymbolData mrsGeorge = new SymbolData("MrsGeorge");
2176 mrsGeorge.addMethod(new MethodData("sayHello1", noVars));
2177 george.setSuperClass(mrsGeorge);
2178
2179 SymbolData grandmaGeorge = new SymbolData("GrandmaGeorge");
2180 grandmaGeorge.addMethod(new MethodData("sayHello2", noVars));
2181 grandmaGeorge.addMethod(new MethodData("sayHello5", noVars));
2182 george.addInterface(grandmaGeorge);
2183
2184 SymbolData papaOfIAteGeorge = new SymbolData("PapaOfIAteGeorge");
2185 papaOfIAteGeorge.addMethod(new MethodData("sayHello3", noVars));
2186 iAteGeorge.setSuperClass(papaOfIAteGeorge);
2187
2188 assertEquals("The generated name is correct when SymbolData has that method name",
2189 "getFriends0", george.createUniqueMethodName("getFriends"));
2190 assertEquals("The generated name is correct when SymbolData doesn't have a method of that name",
2191 "eatDinner", george.createUniqueMethodName("eatDinner"));
2192 assertEquals("The generated name is correct when a super class uses the name",
2193 "sayHello10", george.createUniqueMethodName("sayHello1"));
2194 assertEquals("The generated name is correct when an outer class uses the name",
2195 "sayHello00", george.createUniqueMethodName("sayHello0"));
2196 assertEquals("The generated name is correct when an interface uses the name",
2197 "sayHello20", george.createUniqueMethodName("sayHello2"));
2198 assertEquals("The generated name is correct when a super class of an outer class uses the name",
2199 "sayHello30", george.createUniqueMethodName("sayHello3"));
2200 assertEquals("The generated name is correct when a super class of an outer class uses the name",
2201 "sayHello30", george.createUniqueMethodName("sayHello3"));
2202 assertEquals("The generated name is correct when a lot of things use the name",
2203 "sayHello4", george.createUniqueMethodName("sayHello"));
2204
2205 }
2206 }
2207 }