001 /*BEGIN_COPYRIGHT_BLOCK
002 *
003 * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 * * Redistributions of source code must retain the above copyright
009 * notice, this list of conditions and the following disclaimer.
010 * * Redistributions in binary form must reproduce the above copyright
011 * notice, this list of conditions and the following disclaimer in the
012 * documentation and/or other materials provided with the distribution.
013 * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014 * names of its contributors may be used to endorse or promote products
015 * derived from this software without specific prior written permission.
016 *
017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028 *
029 * This software is Open Source Initiative approved Open Source Software.
030 * Open Source Initative Approved is a trademark of the Open Source Initiative.
031 *
032 * This file is part of DrJava. Download the current version of this project
033 * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034 *
035 * END_COPYRIGHT_BLOCK*/
036
037 package edu.rice.cs.javalanglevels;
038
039 import edu.rice.cs.javalanglevels.parser.*;
040 import edu.rice.cs.javalanglevels.tree.*;
041 import edu.rice.cs.javalanglevels.util.Log;
042 import edu.rice.cs.javalanglevels.util.Utilities;
043 import java.io.*;
044 import java.util.*;
045 import junit.framework.TestCase;
046 import edu.rice.cs.plt.reflect.JavaVersion;
047 import edu.rice.cs.plt.iter.*;
048
049 import static edu.rice.cs.javalanglevels.SourceInfo.NONE;
050
051 public class Augmentor extends JExpressionIFDepthFirstVisitor<Void> {
052 // public static final Log _log = new Log("Augmentor.txt", true);
053
054 private static final String newLine = System.getProperty("line.separator");
055 private static final int indentWidth = 2; // TODO: get this from DrJava?
056
057
058 /** IDIOCY Pointer: Why are all these private fields static? They are set in the constructor. Was this design
059 * choice made to ensure only one Augmentor exists at a time by clobbering fields. Stupid, stupid, stupid. */
060
061 /** The original source file to be augmented. */
062 static private BufferedReader _fileIn;
063
064 /** The current line number in _fileIn. */
065 static private int _fileInLine;
066
067 /** The current column number in _fileIn. This is the 1 greater than the last column read. */
068 static private int _fileInColumn;
069
070 /** The destination file. */
071 static private BufferedWriter _fileOut;
072
073 /** The current line number in _fileOut. */
074 static private int _fileOutLine;
075
076 /** The dj* line number to which the current line number in _fileOut corresponds. */
077 static private int _fileOutCorrespondingLine;
078
079 /** A map from original dj* line number to generated java line number. */
080 static private TreeMap<Integer,Integer> _lineNumberMap;
081
082 /** The symbol information from this source tree. */
083 static private LanguageLevelVisitor _llv;
084
085 /** If true, generated toString, hashCode, & equals methods should correctly handle arrays & infinitely recursive
086 * structures */
087 static private boolean _safeSupportCode;
088
089 /** A String of variable definitions to be written at the end of the top-level class definitions */
090 static private List<String> _endOfClassVarDefs;
091
092 /** The SymbolData enclosing whatever we are currently augmenting.*/
093 private SymbolData _enclosingData;
094
095 /** Main constructor for Augmentor: Used by the LanguageLevelConverter when converting language level files.
096 * @param safeSupportCode true if the user wants safe support code to be generated (this comes with a high overhead)
097 * @param fileIn A BufferedReader corresponding to the LanguageLevel file we should read from
098 * @param fileOut A BufferedWriter corresponding to the .java file we should write to.
099 * @param llv The LanguageLevelVisitor that was used to traverse the language level file.
100 */
101 public Augmentor(boolean safeSupportCode, BufferedReader fileIn, BufferedWriter fileOut, LanguageLevelVisitor llv) {
102 _fileIn = fileIn;
103 _fileInLine = 1;
104 _fileInColumn = 1;
105 _fileOut = fileOut;
106 _fileOutLine = 1;
107 _fileOutCorrespondingLine = 1;
108 _lineNumberMap = new TreeMap<Integer,Integer>();
109 _llv = llv;
110 _safeSupportCode = safeSupportCode;
111 _endOfClassVarDefs = new LinkedList<String>();
112
113 _enclosingData = null;
114 }
115
116 /** Create another Augmentor sharing the same static fields as the current Augmentor, but with a new _enclosingData d.
117 * This constructor should only be called from within another Augmentor.
118 * @param d The EnclosingData from which this Augmentor works.
119 */
120 protected Augmentor(SymbolData d) { _enclosingData = d; }
121
122 /** This method is called by default from cases that do not override forCASEOnly. */
123 protected Void defaultCase(JExpressionIF that) { return null; }
124
125 /** Return a Void array of the specified size. */
126 protected Void[] makeArrayOfRetType(int len) { return new Void[len]; }
127
128 /** Writes out implicit variableDeclarationModfiers that must be added to augmented file. If no visibility modifier
129 * is present, this method makes static fields "public final" and instance fields "private final". If a visibility
130 * modifier is present, it overrides this default. But all fields are forced to be "final".
131 * @param that is the field declaration being augmented
132 */
133 protected void augmentVariableDeclarationModifiers(VariableDeclaration that) {
134
135 // make static fields public final, make instance fields private final
136 StringBuilder modifierString = new StringBuilder();
137 String[] modifiers = that.getMav().getModifiers();
138 if (! Utilities.hasVisibilityModifier(modifiers)) {
139 if (Utilities.isStatic(modifiers)) modifierString.append("public ");
140 else modifierString.append("private ");
141 }
142 if (! Utilities.isFinal(modifiers)) modifierString.append("final ");
143 _writeToFileOut(modifierString.toString());
144 }
145
146 /** Do the augmenting appropriate for a Variable Declaration: all Variable Declarations should
147 * be augmented with "final" if such a modifier is not already present.
148 * @param that The VariableDeclaration we are augmenting.
149 */
150 public Void forVariableDeclaration(VariableDeclaration that) {
151 _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
152 augmentVariableDeclarationModifiers(that);
153 super.forVariableDeclaration(that);
154 return null;
155 }
156
157 /** All formal parameters (parameters to a method or in a catch clause) are augmented to be "final".
158 * Always read up to the start of the FormalParameter before beginning augmentation.
159 * @param that The FormalParameter we are augmenting.
160 */
161 public Void forFormalParameter(FormalParameter that) {
162 _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
163 if (! that.isIsFinal()) _writeToFileOut("final ");
164
165 // We don't bother to visit the declarator, since it does not need to be augmented.
166 return null;
167 }
168
169 /** Do the augmentation necessary for a ConstructorDef. If no visibility modifier is present, augment with "public"
170 * by default. The Formal Parameters to the MethodDef need to be visited so that they can be augmented with "final".
171 * Always read up to the start of the ConstructorDef before beginning augmentation.
172 * @param that The ConstructorDef we are augmenting.
173 */
174 public Void forConstructorDef(ConstructorDef that) {
175 _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
176
177 // Check and see if the constructor has modifiers. If not, make it public by default
178 String[] modifiers = that.getMav().getModifiers();
179 if (! Utilities.hasVisibilityModifier(modifiers)) _writeToFileOut("public ");
180
181 for (FormalParameter fp : that.getParameters()) { fp.visit(this); }
182 // We don't bother visiting the rest of the method declaration
183 return null;
184 }
185
186 /** Do the augmentation necessary for a MethodDef. If the user did not specify a visibility level,
187 * the method is automatically augmented to be "public". Otherwise, the user's modifier is left unchanged.
188 * At all levels, the Formal Parameters to the MethodDef need to be visited so that
189 * they can be augmented with "final" if "final" is not already present.
190 * Always read up to the start of the MethodDef before beginning augmentation.
191 * @param that The MethodDef being visited.
192 */
193 public Void forMethodDef(MethodDef that) {
194 SourceInfo mdSourceInfo = that.getSourceInfo();
195 _readAndWriteThroughIndex(mdSourceInfo.getStartLine(), mdSourceInfo.getStartColumn() - 1);
196
197 if (! Utilities.hasVisibilityModifier(that.getMav().getModifiers())) _writeToFileOut("public ");
198
199 for (FormalParameter fp : that.getParams()) { fp.visit(this); }
200 // We don't bother visiting the rest of the method declaration
201 return null;
202 }
203
204
205 /** Delegate the augmentation of this AbstractMethodDef to forMethodDef.
206 * @param that The AbstractMethodDef being augmented.
207 */
208 public Void forAbstractMethodDef(AbstractMethodDef md) { forMethodDef(md); return null; }
209
210 /** Delegate the augmentation of this method def's declaration to forMethodDef. Then, visit the body with a
211 * MethodBodyAugmentor so that each piece of the body can be correctly augmented.
212 * @param that The ConcreteMethodDef being augmented.
213 */
214 public Void forConcreteMethodDef(ConcreteMethodDef that) {
215 assert _enclosingData != null;
216
217 forMethodDef(that);
218 SymbolData enclosing = _enclosingData.getSymbolData();
219 MethodData md =
220 enclosing.getMethod(that.getName().getText(),
221 formalParameters2TypeDatas(that.getParams(), enclosing));
222 // _log.log("Augmenting ConcreteMethodDef " + that + " with MethodData " + md);
223 if (md == null) {
224 throw new RuntimeException("Internal Program Error: Can't find method data for " + that.getName() +
225 " Please report this bug.");
226 }
227 that.getBody().visit(new MethodBodyAugmentor(enclosing));
228 return null;
229 }
230
231 /** Class Defs can only appear at the top level of a source file. If the class type is public but "public" does
232 * not appear as a visibility modifier, add it. Visit the body of the class definition with a new Augmentor.
233 * Then, (so that this appears after the rest of the class body) add any necessary augmented methods.
234 * @param cd The ClassDef we're augmenting.
235 */
236 public Void forClassDef(ClassDef cd) {
237 String className = cd.getName().getText();
238 SymbolData sd = _llv.symbolTable.get(_llv.getQualifiedClassName(className));
239 if (sd == null) { throw new RuntimeException("Internal Program Error: Can't find SymbolData for " +
240 cd.getName().getText() + " Please report this bug."); }
241
242 ModifiersAndVisibility m = cd.getMav();
243 String[] modifiers = m.getModifiers();
244
245 /* Support legacy Elementary level (dj0) files by generating a Junit import statement if this import has
246 * been auto-generated. */
247
248 if (sd.hasAutoGeneratedJunitImport()) {
249 // import statement should be OK here because language level test files can only contain one class. */
250 _writeToFileOut("import junit.framework.TestCase;" + newLine);
251 }
252
253 /* Support legacy Elementary level (dj0) files by add "public " prefix to classes that must be public (TestCase
254 * files). */
255 if (sd.hasModifier("public") && (! Utilities.isPublic(m.getModifiers()))) {
256 assert ! Utilities.hasVisibilityModifier(modifiers);
257 _readAndWriteThroughIndex(m.getSourceInfo().getStartLine(), m.getSourceInfo().getStartColumn() - 1);
258 _writeToFileOut("public ");
259 }
260
261 BracedBody bb = cd.getBody();
262 sd.setAnonymousInnerClassNum(0);
263 bb.visit(new Augmentor(sd));
264
265 int baseIndent = cd.getSourceInfo().getStartColumn() - 1;
266 className = LanguageLevelVisitor.getUnqualifiedClassName(sd.getName());
267 _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);
268
269 // Augment this class declaration
270 writeConstructor(className, sd, baseIndent);
271 writeAccessors(sd, baseIndent);
272 String valueToStringName = writeValueToString(sd, baseIndent);
273 String valueEqualsName = writeValueEquals(sd, baseIndent);
274 String valueHashCodeName = writeValueHashCode(sd, baseIndent, valueEqualsName);
275 writeToString(sd, baseIndent, valueToStringName);
276 writeEquals(className, sd, baseIndent, valueEqualsName);
277 writeHashCode(className, sd, baseIndent, false, valueHashCodeName);
278 for (String s : _endOfClassVarDefs) {
279 _writeToFileOut(newLine + indentString(baseIndent, 1) + s);
280 }
281 if (_endOfClassVarDefs.size() > 0) {
282 _writeToFileOut(newLine);
283 _endOfClassVarDefs.clear();
284 }
285 _writeToFileOut(indentString(baseIndent, 0));
286
287 // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
288 return null;
289 }
290
291 /** Look up this inner class in the enclosing data, and then visits its body. InnerClassDefs can appear inside method
292 * or class or interface bodies. No augmentation is done, because an InnerClass can only appear at the
293 * AdvancedLevel,
294 * and we do not do augmentation at the Advanced Level. If this were to change, we would need to
295 * add the Augmentation back in.
296 * @param cd The InnerClassDef we are augmenting.
297 */
298 public Void forInnerClassDef(InnerClassDef cd) {
299 String className = cd.getName().getText();
300 if (_enclosingData == null) {
301 throw new RuntimeException("Internal Program Error: Enclosing Data is null. Please report this bug.");
302 }
303 SymbolData sd = _enclosingData.getInnerClassOrInterface(className);
304 if (sd == null) {
305 throw new RuntimeException("Internal Program Error: Can't find SymbolData for " + cd.getName().getText() +
306 ". Please report this bug.");
307 }
308
309 /** WARNING: the code suffix copied from ClassDef; it it works it should be refactored. */
310 BracedBody bb = cd.getBody();
311 sd.setAnonymousInnerClassNum(0);
312 bb.visit(new Augmentor(sd));
313
314 int baseIndent = cd.getSourceInfo().getStartColumn() - 1;
315 className = LanguageLevelVisitor.getUnqualifiedClassName(sd.getName());
316 _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);
317
318 // Augment this class declaration
319 writeConstructor(className, sd, baseIndent);
320 writeAccessors(sd, baseIndent);
321 String valueToStringName = writeValueToString(sd, baseIndent);
322 String valueEqualsName = writeValueEquals(sd, baseIndent);
323 String valueHashCodeName = writeValueHashCode(sd, baseIndent, valueEqualsName);
324 writeToString(sd, baseIndent, valueToStringName);
325 writeEquals(className, sd, baseIndent, valueEqualsName);
326 writeHashCode(className, sd, baseIndent, false, valueHashCodeName);
327 for (String s : _endOfClassVarDefs) {
328 _writeToFileOut(newLine + indentString(baseIndent, 1) + s);
329 }
330 if (_endOfClassVarDefs.size() > 0) {
331 _writeToFileOut(newLine);
332 _endOfClassVarDefs.clear();
333 }
334 _writeToFileOut(indentString(baseIndent, 0));
335
336
337 // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
338 return null;
339 }
340
341 /* Old suffix */
342
343 // BracedBody bb = cd.getBody();
344 // sd.setAnonymousInnerClassNum(0);
345 // bb.visit(new Augmentor(sd));
346 //
347 // _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);;
348 //
349 // // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
350 // return null;
351 // }
352
353 /** Look up this top level interface in the symbolTable, and then visit its body. Write any necessary extra variable
354 * definitions at the end of the file. InterfaceDefs can only appear at the top level of a source file.
355 * @param cd The InterfaceDef being augmented.
356 */
357 public Void forInterfaceDef(InterfaceDef cd) {
358 String interfaceName = cd.getName().getText();
359 SymbolData sd = _llv.symbolTable.get(_llv.getQualifiedClassName(interfaceName));
360 if (sd == null) { throw new RuntimeException("Internal Program Error: Can't find SymbolData for " +
361 cd.getName().getText() + ". Please report this bug."); }
362 ModifiersAndVisibility m = cd.getMav();
363
364 /* Make interfaces public by default? */
365 // if (! Utilities.hasVisibilityModifier(m.getModifiers()) {
366 // _readAndWriteThroughIndex(m.getSourceInfo().getStartLine(), m.getSourceInfo().getStartColumn() - 1);
367 // _writeToFileOut("public ");
368 // }
369
370 BracedBody bb = cd.getBody();
371 sd.setAnonymousInnerClassNum(0);
372 bb.visit(new Augmentor(sd));
373
374 int baseIndent = cd.getSourceInfo().getStartColumn() - 1;
375 _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);
376 for (String s : _endOfClassVarDefs) {
377 _writeToFileOut(newLine + indentString(baseIndent, 1) + s);
378 }
379 if (_endOfClassVarDefs.size() > 0) {
380 _writeToFileOut(newLine);
381 _endOfClassVarDefs.clear();
382 }
383 _writeToFileOut(indentString(baseIndent, 0));
384 // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
385 return null;
386 }
387
388 /** Look up this inner interface in the enclosing data, and then visit its body with a new Augmentor.
389 * No code augmentation is done since InnerInterfaces can only appear at the Advanced Level, and
390 * we are not doing code augmentation at the Advanced Level. If we were to start doing code augmentation
391 * at the Advanced level, this might need to change.
392 * InnerInterfaceDefs can appear inside method or class or interface bodies.
393 */
394 public Void forInnerInterfaceDef(InnerInterfaceDef cd) {
395 String interfaceName = cd.getName().getText();
396 if (_enclosingData == null) {
397 throw new RuntimeException("Internal Program Error: Enclosing Data is null. Please report this bug.");
398 }
399 SymbolData sd = _enclosingData.getInnerClassOrInterface(interfaceName);
400 if (sd == null) {
401 throw new RuntimeException("Internal Program Error: Can't find SymbolData for " + cd.getName().getText() +
402 ". Please report this bug.");
403 }
404
405 BracedBody bb = cd.getBody();
406 sd.setAnonymousInnerClassNum(0);
407 bb.visit(new Augmentor(sd));
408
409 // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
410 return null;
411 }
412
413
414 /* Look up this Anonymous Inner Class inside its enclosing data, and then visit its body. Then, if it
415 * is from an Elementary or Intermediate Level file, augment with the necessary automatically generated methods.
416 * @param e The AnonymousClassInstantiation we are augmenting.
417 */
418 public Void forAnonymousClassInstantiation(AnonymousClassInstantiation e) {
419 SymbolData sd = _enclosingData.getNextAnonymousInnerClass();
420 // _log.log("Augmenting anonymous class " + e + " with SymbolData " + sd);
421 if (sd == null) {
422 throw new RuntimeException("Internal Program Error: Couldn't find the SymbolData for the anonymous inner class." +
423 " Please report this bug.");
424 }
425 BracedBody bb = e.getBody();
426 sd.setAnonymousInnerClassNum(0);
427 bb.visit(new Augmentor(sd));
428
429 int baseIndent = e.getSourceInfo().getStartColumn() - 1;
430 _readAndWriteThroughIndex(e.getSourceInfo().getEndLine(), e.getSourceInfo().getEndColumn() - 1);
431 // if (_isElementaryFile() || _isIntermediateFile()) {
432 String className = Data.dollarSignsToDots(e.getType().getName());
433 writeAccessors(sd, baseIndent);
434 String valueToStringName = writeValueToString(sd, baseIndent);
435 String valueEqualsName = writeValueEquals(sd, baseIndent);
436 String valueHashCodeName = writeValueHashCode(sd, baseIndent, valueEqualsName);
437 writeToString(sd, baseIndent, valueToStringName);
438 if (!_safeSupportCode) { writeAnonEquals(baseIndent);}
439 else { writeEquals(className, sd, baseIndent, valueEqualsName); }
440 writeHashCode(className, sd, baseIndent, true, valueHashCodeName);
441 _writeToFileOut(indentString(baseIndent, 0));
442
443 // }
444 return null;
445 }
446
447 /**Delegate to for AnonymousClassInstantiation(e).*/
448 public Void forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation e) {
449 forAnonymousClassInstantiation(e);
450 return null;
451 }
452
453 /** Visit the encosing part of this ComplexAnonymousClass name, and then delegate to
454 * forAnonymousClassInstantiation(e). */
455 public Void forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation e) {
456 e.getEnclosing().visit(this);
457 forAnonymousClassInstantiation(e);
458 return null;
459 }
460
461 /** Sort the Class and Interface defs based on the order they appear in the file. Then visit each in turn.
462 * Finally, write whatever remains in the file. (If this is an ElementaryLevel file that needs to import
463 * junit.framework.TestCase, make this the very first line of the augmented file. This is okay, because at the
464 * ElementaryLevel, there are no package statements we might get in trouble with.
465 */
466 public Void forSourceFile(SourceFile sf) {
467 TypeDefBase[] cds = sf.getTypes();
468
469 // We intentionally neglect to visit the package and import statements
470
471 //Visit each class and interface def in turn.
472 for (TypeDefBase cd : cds) { cd.visit(this); }
473
474 //Write out whatever is left in the file.
475 // _log.log("Processed source file through line " + _fileInLine + " and column " + _fileInColumn);
476 // _log.log("Now dumping remainder of file through line " + sf.getSourceInfo().getEndLine());
477 //_readAndWriteThroughIndex(sf.getSourceInfo().getEndLine(), sf.getSourceInfo().getEndColumn());
478 String remainder = _readThroughIndex(sf.getSourceInfo().getEndLine(), sf.getSourceInfo().getEndColumn());
479 if (!remainder.endsWith(newLine)) remainder = remainder + newLine; // make sure file ends in a newLine
480 _writeToFileOut(remainder, true);
481 return null;
482 }
483
484 /** Convert the provided FormalParameter array into an array of TypeData corresponding
485 * to the types of the FormalParameters.
486 */
487 protected static TypeData[] formalParameters2TypeDatas(FormalParameter[] fps, SymbolData enclosing) {
488 TypeData[] tds = new TypeData[fps.length];
489 int j = 0;
490 for (FormalParameter fp: fps) {
491 SymbolData type = _llv.getSymbolData(fp.getDeclarator().getType().getName(), fp.getSourceInfo());
492
493 if (type == null) {
494 //see if this is a partially qualified field reference
495 type = enclosing.getInnerClassOrInterface(fp.getDeclarator().getType().getName());
496 }
497
498 tds[j]= type; j++; // store type in next empty slot of tds
499 }
500 assert j == fps.length;
501
502 return tds;
503 }
504
505
506 /**
507 * Write a constructor for a previously generated (determined by MethodData.isGenerated())
508 * constructor, if one exists.
509 *
510 * @param sd The method's enclosing class.
511 * @param baseIndent The base indent level (number of spaces).
512 */
513 protected static void writeConstructor(String className, SymbolData sd, int baseIndent) {
514 // Find the constructor. There should be at most one that we generated, so select that one.
515 MethodData constructor = null;
516 for (MethodData currMd : sd.getMethods()) {
517 if (currMd.getName().equals(LanguageLevelVisitor.getUnqualifiedClassName(sd.getName())) && currMd.isGenerated()) {
518 constructor = currMd;
519 break;
520 }
521 }
522 if (constructor == null) return;
523
524
525 // Write the method signature.
526 VariableData[] constructorParams = constructor.getParams();
527
528 _writeToFileOut(newLine + indentString(baseIndent, 1) +
529 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
530 _writeToFileOut(indentString(baseIndent, 1) + "public " + className + "(");
531 for (int q = 0; q < constructorParams.length; q++) {
532 if (q>0) {
533 _writeToFileOut(", ");
534 }
535 VariableData vd = constructorParams[q];
536 _writeToFileOut(Data.dollarSignsToDots(vd.getType().getName()) + " " + vd.getName());
537 }
538
539 _writeToFileOut(") {" + newLine);
540
541
542 // Generate lists of super params & local params
543 LinkedList<VariableData> superParams = new LinkedList<VariableData>();
544 LinkedList<VariableData> localParams = new LinkedList<VariableData>();
545 LinkedList<VariableData> localFields = sd.getVars();
546
547 for (VariableData param : constructorParams) {
548 boolean hasLocalField = false;
549 for (VariableData field : localFields) {
550 hasLocalField = hasLocalField || field.getName().equals(param.getName());
551 if (hasLocalField) { break; }
552 }
553
554 if (hasLocalField) { localParams.add(param); }
555 else if (param.getName().startsWith("super_")) { superParams.add(param); }
556 else {
557 throw new RuntimeException("Internal Program Error: Unexpected parameter name in generated constructor: " +
558 param.getName() +". Please report this bug");
559 }
560 }
561
562 // Add the call to the super constructor here.
563 _writeToFileOut(indentString(baseIndent, 2) + "super(");
564
565 for (int z = 0; z < superParams.size(); z++) {
566 if (z > 0) {
567 _writeToFileOut(", ");
568 }
569 _writeToFileOut(superParams.get(z).getName());
570 }
571 _writeToFileOut(");" + newLine);
572
573 // Instantiate local fields.
574 for (int i = 0; i < localParams.size(); i++) {
575 String varName = localParams.get(i).getName();
576 _writeToFileOut(indentString(baseIndent, 2) + "this." + varName + " = " + varName + ";" + newLine);
577 }
578 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
579 }
580
581 /**
582 * Write an accessor method for each previously generated (determined by MethodData.isGenerated())
583 * accessor.
584 *
585 * @param sd The method's enclosing class.
586 * @param baseIndent The base indent level (number of spaces).
587 */
588 protected static void writeAccessors(SymbolData sd, int baseIndent) {
589 // Find the accessor methods and generate them if we had to create them ourselves.
590 LinkedList<MethodData> methods = sd.getMethods();
591 MethodData accessor = null;
592 Iterator<MethodData> iter = methods.iterator();
593 VariableData[] vars = sd.getVars().toArray(new VariableData[sd.getVars().size()]);
594 for (int i = 0; i < vars.length; i++) {
595 accessor = null;
596 iter = methods.iterator();
597 while (iter.hasNext()) {
598 MethodData currMd = iter.next();
599 if (currMd.getName().equals(vars[i].getName()) && currMd.isGenerated()) {
600 accessor = currMd;
601 break;
602 }
603 }
604 if (accessor != null) {
605 _writeToFileOut(newLine + indentString(baseIndent, 1) +
606 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
607 _writeToFileOut(indentString(baseIndent, 1) + "public " +
608 Data.dollarSignsToDots(vars[i].getType().getName()) + " " +
609 LanguageLevelVisitor.getFieldAccessorName(vars[i].getName()) + "() {" + newLine);
610 _writeToFileOut(indentString(baseIndent, 2) + "return " + vars[i].getName() + ";" + newLine +
611 indentString(baseIndent, 1) + "}" + newLine);
612 }
613 }
614 }
615
616 /**
617 * Write a toString method that prints out each field with a visible accessor.
618 *
619 * @param sd The method's enclosing class.
620 * @param baseIndent The base indent level (number of spaces).
621 * @param valueToStringName The name of the generated valueToString method
622 */
623 protected static void writeToString(SymbolData sd, int baseIndent, String valueToStringName) {
624 LinkedList<MethodData> methods = sd.getMethods();
625 MethodData toString = null;
626 Iterator<MethodData> iter = methods.iterator();
627 // Find the toString method and generate it if we had to create it ourselves.
628 while (iter.hasNext()) {
629 MethodData currMd = iter.next();
630 if (currMd.getName().equals("toString") && currMd.isGenerated()) {
631 toString = currMd;
632 break;
633 }
634 }
635 if (toString == null) return;
636 // Builds a list of MethodData accessors for VariableDatas of this class.
637 LinkedList<MethodData> allMds = _getVariableAccessorListHelper(sd);
638 MethodData[] mds = allMds.toArray(new MethodData[allMds.size()]);
639
640 if (_safeSupportCode) { writeSafeToString(sd, baseIndent, valueToStringName, mds); }
641 else { writeSimpleToString(sd, baseIndent, valueToStringName, mds); }
642 }
643
644 /** Helper to writeToString; writes a toString that handles infinitely-recursive data structures. */
645 protected static void writeSafeToString(SymbolData sd, int baseIndent, String valueToStringName,
646 MethodData[] accessors) {
647
648 String flagName = sd.createUniqueName("__toStringFlag");
649 VariableData toStringFlag = new VariableData(flagName,
650 new ModifiersAndVisibility(NONE,
651 new String[]{ "private", "static" }),
652 _llv.getQualifiedSymbolData("java.util.LinkedList", SourceInfo.NONE, false),
653 true, sd);
654 toStringFlag.setGenerated(true);
655 sd.addVar(toStringFlag);
656
657 _writeToFileOut(newLine + indentString(baseIndent, 1) +
658 "/** This field is automatically generated by the Language Level Converter. */" + newLine);
659 _writeToFileOut(indentString(baseIndent, 1) + "private boolean " + flagName + " = false;" + newLine);
660 _writeToFileOut(newLine + indentString(baseIndent, 1) +
661 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
662 _writeToFileOut(indentString(baseIndent, 1) + "public java.lang.String toString() {" + newLine);
663 _writeToFileOut(indentString(baseIndent, 2) + "if (" + flagName + ") {" + newLine);
664 _writeToFileOut(indentString(baseIndent, 3) + "return getClass().getName() + \"(...)\";" + newLine);
665 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
666 _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
667 _writeToFileOut(indentString(baseIndent, 3) + flagName + " = true;" + newLine);
668 _writeToFileOut(indentString(baseIndent, 3) + "String result;" + newLine);
669 _writeToFileOut(indentString(baseIndent, 3) + "try {" + newLine);
670 _writeToFileOut(indentString(baseIndent, 4) + "result = getClass().getName() + \"(\" + " + newLine);
671 for (int i = 0; i < accessors.length; i++) {
672 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5) ||
673 ! accessors[i].getReturnType().getSymbolData().isPrimitiveType()) {
674
675 _writeToFileOut(indentString(baseIndent, 6) + valueToStringName + "(" + accessors[i].getName() + "()) + ");
676 }
677 else {
678 _writeToFileOut(indentString(baseIndent, 6) + accessors[i].getName() + "() + ");
679 }
680
681 if (i < accessors.length - 1) {
682 _writeToFileOut("\", \" + ");
683 }
684 _writeToFileOut(newLine);
685 }
686 _writeToFileOut(indentString(baseIndent, 6) + "\")\";" + newLine);
687 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
688 _writeToFileOut(indentString(baseIndent, 3) + "catch (RuntimeException e) {" + newLine);
689 _writeToFileOut(indentString(baseIndent, 4) + flagName + " = false;" + newLine);
690 _writeToFileOut(indentString(baseIndent, 4) + "throw e;" + newLine);
691 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
692 _writeToFileOut(indentString(baseIndent, 3) + flagName + " = false;" + newLine);
693 _writeToFileOut(indentString(baseIndent, 3) + "return result;" + newLine);
694 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
695 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
696 }
697
698 /** Helper to writeToString; writes a short toString that does not handle infinitely-recursive data structures. */
699 protected static void writeSimpleToString(SymbolData sd, int baseIndent, String valueToStringName,
700 MethodData[] accessors) {
701
702 _writeToFileOut(newLine + indentString(baseIndent, 1) +
703 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
704 _writeToFileOut(indentString(baseIndent, 1) + "public java.lang.String toString() {" + newLine);
705 _writeToFileOut(indentString(baseIndent, 2) + "return getClass().getName() + \"(\" + " + newLine);
706 for (int i = 0; i < accessors.length; i++) {
707 _writeToFileOut(indentString(baseIndent, 4) + accessors[i].getName() + "() + ");
708
709 if (i < accessors.length - 1) {
710 _writeToFileOut("\", \" + ");
711 }
712 _writeToFileOut(newLine);
713 }
714 _writeToFileOut(indentString(baseIndent, 4) + "\")\";" + newLine);
715 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
716 }
717
718 /**
719 * Write an equals method that requires the Object parameter to be an instanceof this type
720 * and have matching fields for each of the fields with visible accessors.
721 *
722 * @param className The unqualified name of this method's class or, in the case of anonymous inner classes, the
723 * name of its superclass (or implemented interface).
724 * @param sd The method's enclosing class.
725 * @param baseIndent The base indent level (number of spaces).
726 * @param valueEqualsName The name of the generated valueEquals method
727 */
728 protected static void writeEquals(String className, SymbolData sd, int baseIndent, String valueEqualsName) {
729 LinkedList<MethodData> methods = sd.getMethods();
730 MethodData equals = null;
731 Iterator<MethodData> iter = methods.iterator();
732
733 // Find the equals method and generate it if we had to create it ourselves.
734 while (iter.hasNext()) {
735 MethodData currMd = iter.next();
736 if (currMd.getName().equals("equals") && currMd.isGenerated()) {
737 equals = currMd;
738 break;
739 }
740 }
741 if (equals == null) return;
742
743 LinkedList<MethodData> allMds = _getVariableAccessorListHelper(sd);
744 MethodData[] mds = allMds.toArray(new MethodData[allMds.size()]);
745
746 if (_safeSupportCode) { writeSafeEquals(className, sd, baseIndent, valueEqualsName, mds); }
747 else { writeSimpleEquals(className, sd, baseIndent, valueEqualsName, mds); }
748 }
749
750 /** Helper to writeEquals; writes an equals that handles infinitely-recursive data structures. */
751 protected static void writeSafeEquals(String className, SymbolData sd, int baseIndent, String valueEqualsName,
752 MethodData[] accessors) {
753
754 String listName = sd.createUniqueName("__equalsList");
755
756 VariableData equalsList =
757 new VariableData(listName, new ModifiersAndVisibility(SourceInfo.NONE, new String[]{ "private", "static" }),
758 _llv.getQualifiedSymbolData("java.util.LinkedList", SourceInfo.NONE, false),
759 true, sd);
760 equalsList.setGenerated(true);
761 sd.addVar(equalsList);
762
763 _writeToFileOut(newLine + indentString(baseIndent, 1) +
764 "/** This field is automatically generated by the Language Level Converter. */");
765 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5))
766 _writeToFileOut(newLine + indentString(baseIndent, 1) + "private java.util.LinkedList<" + className + "> " +
767 listName + " = new java.util.LinkedList<" + className + ">();" + newLine);
768 else
769 _writeToFileOut(newLine + indentString(baseIndent, 1) + "private java.util.LinkedList " + listName +
770 " = new java.util.LinkedList();" + newLine + newLine);
771
772 _writeToFileOut(newLine + indentString(baseIndent, 1) +
773 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
774 _writeToFileOut(indentString(baseIndent, 1) + "public boolean equals(java.lang.Object o) {" + newLine);
775 _writeToFileOut(indentString(baseIndent, 2) + "if (this == o) {" + newLine);
776 _writeToFileOut(indentString(baseIndent, 3) + "return true;" + newLine);
777 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
778 _writeToFileOut(indentString(baseIndent, 2) + "else if ((o == null) || (! o.getClass().equals(getClass()))) {" +
779 newLine);
780 _writeToFileOut(indentString(baseIndent, 3) + "return false;" + newLine);
781 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
782 _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
783 _writeToFileOut(indentString(baseIndent, 3) + "boolean alreadyTested = false;" + newLine);
784 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5)) {
785 _writeToFileOut(indentString(baseIndent, 3) + "for (" + className + " element : " + listName + ")" + newLine);
786 _writeToFileOut(indentString(baseIndent, 4) + "alreadyTested = alreadyTested || (o == element);" + newLine +
787 newLine);
788 }
789 else {
790 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5)) {
791 _writeToFileOut(indentString(baseIndent, 3) + "java.util.Iterator<" + className + "> i = " + listName +
792 ".iterator();" + newLine);
793 }
794 else {
795 _writeToFileOut(indentString(baseIndent, 3) + "java.util.Iterator i = " + listName + ".iterator();" + newLine);
796 }
797 _writeToFileOut(indentString(baseIndent, 3) + "while (!alreadyTested && i.hasNext())" + newLine);
798 _writeToFileOut(indentString(baseIndent, 4) + "alreadyTested = alreadyTested || (o == i.next());" + newLine +
799 newLine);
800 }
801 _writeToFileOut(indentString(baseIndent, 3) + "if (alreadyTested) { " + newLine);
802 _writeToFileOut(indentString(baseIndent, 4) + "return true;" + newLine);
803 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
804 _writeToFileOut(indentString(baseIndent, 3) + "else {" + newLine);
805 _writeToFileOut(indentString(baseIndent, 4) + className + " cast = ((" + className + ") o);" + newLine);
806 _writeToFileOut(indentString(baseIndent, 4) + listName + ".addLast(cast);" + newLine);
807 _writeToFileOut(indentString(baseIndent, 4) + "boolean result;" + newLine);
808 _writeToFileOut(indentString(baseIndent, 4) + "try {" + newLine);
809 _writeToFileOut(indentString(baseIndent, 5) + "result = ");
810 int variablesCompared = 0;
811 for (int i = 0; i < accessors.length; i++) {
812 if (variablesCompared > 0) {
813 _writeToFileOut(" && " + newLine + indentString(baseIndent, 7));
814 }
815 variablesCompared++;
816
817 String varName = accessors[i].getName() + "()";
818
819 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5) ||
820 ! accessors[i].getReturnType().getSymbolData().isPrimitiveType()) {
821
822 _writeToFileOut(valueEqualsName + "(" + varName + ", cast." + varName + ")");
823 }
824 else {
825 _writeToFileOut("(" + varName + " == cast." + varName + ")");
826 }
827 }
828
829 if (variablesCompared == 0)
830 _writeToFileOut("true");
831
832 _writeToFileOut(";" + newLine);
833 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
834 _writeToFileOut(indentString(baseIndent, 4) + "catch (RuntimeException e) {" + newLine);
835 _writeToFileOut(indentString(baseIndent, 5) + listName + ".removeLast();" + newLine);
836 _writeToFileOut(indentString(baseIndent, 5) + "throw e;" + newLine);
837 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
838 _writeToFileOut(indentString(baseIndent, 4) + listName + ".removeLast();" + newLine);
839 _writeToFileOut(indentString(baseIndent, 4) + "return result;" + newLine);
840 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
841 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
842 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
843 }
844
845 /** Helper to writeEquals; writes a simple equals that does not handle infinitely-recursive data structures. */
846 protected static void writeSimpleEquals(String className, SymbolData sd, int baseIndent, String valueEqualsName,
847 MethodData[] accessors) {
848
849 _writeToFileOut(newLine + indentString(baseIndent, 1) +
850 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
851 _writeToFileOut(indentString(baseIndent, 1) + "public boolean equals(java.lang.Object o) {" + newLine);
852 _writeToFileOut(indentString(baseIndent, 2) + "if (this == o) {" + newLine);
853 _writeToFileOut(indentString(baseIndent, 3) + "return true;" + newLine);
854 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
855 _writeToFileOut(indentString(baseIndent, 2) + "else if ((o == null) || (! o.getClass().equals(getClass()))) {" +
856 newLine);
857 _writeToFileOut(indentString(baseIndent, 3) + "return false;" + newLine);
858 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
859 _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
860 _writeToFileOut(indentString(baseIndent, 3) + className + " cast = ((" + className + ") o);" + newLine);
861 _writeToFileOut(indentString(baseIndent, 3) + "return ");
862 int variablesCompared = 0;
863 for (int i = 0; i < accessors.length; i++) {
864 if (variablesCompared > 0) {
865 _writeToFileOut(" && " + newLine + indentString(baseIndent, 5));
866 }
867 variablesCompared++;
868
869 String varName = accessors[i].getName() + "()";
870
871 if (! accessors[i].getReturnType().getSymbolData().isPrimitiveType()) {
872
873 _writeToFileOut("(" + varName + " != null && " + varName + ".equals(cast." + varName + "))");
874 }
875 else {
876 _writeToFileOut("(" + varName + " == cast." + varName + ")");
877 }
878 }
879
880 if (variablesCompared == 0)
881 _writeToFileOut("true");
882
883 _writeToFileOut(";" + newLine);
884 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
885 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
886 }
887
888
889 /**
890 * AnonymousClasses are only equal if they are identical.
891 */
892 protected static void writeAnonEquals(int baseIndent) {
893
894 _writeToFileOut(newLine + indentString(baseIndent, 1) +
895 "/** This method is automatically generated by the Language Level Converter. */" + newLine);
896 _writeToFileOut(indentString(baseIndent, 1) + "public boolean equals(java.lang.Object o) {" + newLine);
897 _writeToFileOut(indentString(baseIndent, 2) + "return (this == o);" + newLine);
898 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
899 }
900
901
902 /**
903 * Write a hashCode method that is consistent with the generated equals(Object) method.
904 *
905 * @param className The unqualified name of this method's class or, in the case of anonymous inner classes, the
906 * name of its superclass (or implemented interface).
907 * @param sd The method's enclosing class.
908 * @param baseIndent The base indent level (number of spaces).
909 * @param waitForVarDef True iff static variables cannot be defined in the current context and should be deferred
910 * by adding them to _endOfClassVarDefs.
911 * @param valueHashCodeName The name of the generated valueHashCode method
912 */
913 protected static void writeHashCode(String className, SymbolData sd, int baseIndent, boolean waitForVarDef,
914 String valueHashCodeName) {
915 LinkedList<MethodData> methods = sd.getMethods();
916 MethodData hashCode = null;
917 Iterator<MethodData> iter = methods.iterator();
918
919 // Find the hashCode method and generate it if we had to create it ourselves.
920 while (iter.hasNext()) {
921 MethodData currMd = iter.next();
922 if (currMd.getName().equals("hashCode") && currMd.isGenerated()) {
923 hashCode = currMd;
924 break;
925 }
926 }
927 if (hashCode == null) return;
928
929 LinkedList<MethodData> allMds = _getVariableAccessorListHelper(sd);
930 MethodData[] mds = allMds.toArray(new MethodData[allMds.size()]);
931
932 if (_safeSupportCode) { writeSafeHashCode(className, sd, baseIndent, waitForVarDef, valueHashCodeName, mds); }
933 else { writeSimpleHashCode(className, sd, baseIndent, waitForVarDef, valueHashCodeName, mds); }
934 }
935
936 /** Helper to writeHashCode; writes a hashCode that handles infinitely-recursive data structures.
937 * @param className The unqualified name of this method's class or, in the case of anonymous inner classes, the
938 * name of its superclass (or implemented interface).
939 * @param sd The method's enclosing class.
940 * @param baseIndent The base indent level (number of spaces).
941 * @param waitForVarDef True iff static variables cannot be defined in the current context and should be deferred
942 * by adding them to _endOfClassVarDefs.
943 * @param valueHashCodeName The name of the generated valueHashCode method
944 * @param accessors An Array of the MethodDatas corresponding to the accessors for this class.
945 */
946 protected static void writeSafeHashCode(String className, SymbolData sd, int baseIndent, boolean waitForVarDef,
947 String valueHashCodeName, MethodData[] accessors) {
948
949 String listName = "__hashCodeList";
950 listName = sd.createUniqueName(listName);
951 VariableData hashCodeList =
952 new VariableData(listName, new ModifiersAndVisibility(SourceInfo.NONE, new String[]{ "private", "static" }),
953 _llv.getQualifiedSymbolData("java.util.LinkedList", SourceInfo.NONE, false),
954 true, sd);
955 hashCodeList.setGenerated(true);
956
957 if (waitForVarDef) {
958 SymbolData outermostData = sd;
959 while (outermostData.getOuterData() != null) {
960 outermostData = outermostData.getOuterData().getSymbolData();
961 }
962 outermostData.addVar(hashCodeList);
963 _endOfClassVarDefs.add("/** This field is automatically generated by the Language Level Converter. */");
964 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5)) {
965 _endOfClassVarDefs.add("private static java.util.LinkedList<Object> " + listName +
966 " = new java.util.LinkedList<Object>();");
967 }
968 else {
969 _endOfClassVarDefs.add("private static java.util.LinkedList " + listName + " = new java.util.LinkedList();");
970 }
971 _endOfClassVarDefs.add("");
972 }
973 else {
974 sd.addVar(hashCodeList);
975 _writeToFileOut(newLine + indentString(baseIndent, 1) +
976 "/** This field is automatically generated by the Language Level Converter. */");
977 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5)) {
978 _writeToFileOut(newLine + indentString(baseIndent, 1) +
979 "private static java.util.LinkedList<" + className + "> " + listName +
980 " = new java.util.LinkedList<" + className + ">();" + newLine);
981 }
982 else {
983 _writeToFileOut(newLine + indentString(baseIndent, 1) +
984 "private static java.util.LinkedList " + listName + " = new java.util.LinkedList();" + newLine);
985 }
986 }
987
988 _writeToFileOut(newLine + indentString(baseIndent, 1) +
989 "/** This method is automatically generated by the Language Level Converter. */");
990 _writeToFileOut(newLine + indentString(baseIndent, 1) + "public int hashCode() {" + newLine);
991 _writeToFileOut(indentString(baseIndent, 2) + "if (" + listName + ".contains(this)) {" + newLine);
992 _writeToFileOut(indentString(baseIndent, 3) + "return -1;" + newLine);
993 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
994 _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
995 _writeToFileOut(indentString(baseIndent, 3) + listName + ".addLast(this);" + newLine);
996 _writeToFileOut(indentString(baseIndent, 3) + "int result;" + newLine);
997 _writeToFileOut(indentString(baseIndent, 3) + "try {" + newLine);
998 _writeToFileOut(indentString(baseIndent, 4) + "result = getClass().hashCode()");
999 for (int i = 0; i < accessors.length; i++) {
1000 _writeToFileOut(" ^ " + newLine + indentString(baseIndent, 6));
1001 SymbolData type = accessors[i].getReturnType().getSymbolData();
1002
1003 if (LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5) ||
1004 ! type.isPrimitiveType()) {
1005
1006 _writeToFileOut(valueHashCodeName + "(" + accessors[i].getName() + "())");
1007 }
1008 else if (type == SymbolData.BOOLEAN_TYPE) {
1009 _writeToFileOut("(" + accessors[i].getName() + "() ? 1 : 0)");
1010 }
1011 else if (type.isAssignableTo(SymbolData.INT_TYPE, LanguageLevelConverter.OPT.javaVersion())) {
1012 _writeToFileOut(accessors[i].getName() + "()");
1013 }
1014 else {
1015 _writeToFileOut("(int) " + accessors[i].getName() + "()");
1016 }
1017 }
1018
1019 _writeToFileOut(";" + newLine);
1020 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
1021 _writeToFileOut(indentString(baseIndent, 3) + "catch (RuntimeException e) {" + newLine);
1022 _writeToFileOut(indentString(baseIndent, 4) + listName + ".removeLast();" + newLine);
1023 _writeToFileOut(indentString(baseIndent, 4) + "throw e;" + newLine);
1024 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
1025 _writeToFileOut(indentString(baseIndent, 3) + listName + ".removeLast();" + newLine);
1026 _writeToFileOut(indentString(baseIndent, 3) + "return result;" + newLine);
1027 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
1028 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1029 }
1030
1031 /** Helper to writeHashCode; writes a simple hashCode that does not handle infinitely-recursive data structures.
1032 * @param className The unqualified name of this method's class or, in the case of anonymous inner classes, the
1033 * name of its superclass (or implemented interface).
1034 * @param sd The method's enclosing class.
1035 * @param baseIndent The base indent level (number of spaces).
1036 * @param waitForVarDef True iff static variables cannot be defined in the current context and should be deferred
1037 * by adding them to _endOfClassVarDefs.
1038 * @param valueHashCodeName The name of the generated valueHashCode method
1039 * @param accessors An Array of the MethodDatas corresponding to the accessors for this class.
1040 */
1041 protected static void writeSimpleHashCode(String className, SymbolData sd, int baseIndent, boolean waitForVarDef,
1042 String valueHashCodeName, MethodData[] accessors) {
1043
1044 _writeToFileOut(newLine + indentString(baseIndent, 1) +
1045 "/** This method is automatically generated by the Language Level Converter. */");
1046 _writeToFileOut(newLine + indentString(baseIndent, 1) + "public int hashCode() {" + newLine);
1047 _writeToFileOut(indentString(baseIndent, 2) + "return getClass().hashCode()");
1048 for (int i = 0; i < accessors.length; i++) {
1049 _writeToFileOut(" ^ " + newLine + indentString(baseIndent, 4));
1050 SymbolData type = accessors[i].getReturnType().getSymbolData();
1051
1052 if (! type.isPrimitiveType()) {
1053 _writeToFileOut("(" + accessors[i].getName() + "() == null ? 0 : " + accessors[i].getName() + "().hashCode())");
1054 }
1055 else if (type == SymbolData.BOOLEAN_TYPE) {
1056 _writeToFileOut("(" + accessors[i].getName() + "() ? 1 : 0)");
1057 }
1058 else if (type.isAssignableTo(SymbolData.INT_TYPE, LanguageLevelConverter.OPT.javaVersion())) {
1059 _writeToFileOut(accessors[i].getName() + "()");
1060 }
1061 else {
1062 _writeToFileOut("(int) " + accessors[i].getName() + "()");
1063 }
1064 }
1065
1066 _writeToFileOut(";" + newLine);
1067 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1068 }
1069
1070 /**
1071 * Write a method to generate a String for any Object, including arrays, nulls, and other reference types.
1072 *
1073 * @param sd The method's enclosing class.
1074 * @param baseIndent The base indent level (number of spaces).
1075 *
1076 * @return The name of the generated valueToString method (__valueToString by default).
1077 */
1078 private static String writeValueToString(SymbolData sd, int baseIndent) {
1079 String methodName = sd.createUniqueMethodName("__valueToString");
1080 if (_safeSupportCode) { writeSafeValueToString(sd, baseIndent, methodName); }
1081 return methodName;
1082 }
1083
1084 /** Helper to writeValueToString; writes a valueToString that correctly handles arbitrary arrays.
1085 * @param sd The method's enclosing class.
1086 * @param baseIndent The base indent level (number of spaces to put at the beginning of every line).
1087 * @param methodName The name of the generated valueToString method (__valueToString by default).
1088 */
1089
1090 private static void writeSafeValueToString(SymbolData sd, int baseIndent, String methodName) {
1091 String[] primitiveTypes = new String[]{"byte[]", "short[]", "char[]", "int[]", "long[]", "float[]", "double[]",
1092 "boolean[]"};
1093 boolean useGenerics = LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5);
1094
1095 _writeToFileOut(newLine);
1096 _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
1097 _writeToFileOut(indentString(baseIndent, 1) +
1098 " * This method is automatically generated by the LanguageLevelConverter." + newLine);
1099 _writeToFileOut(indentString(baseIndent, 1) +
1100 " * As a helper to toString(), it recursively generates a string for any object," + newLine);
1101 _writeToFileOut(indentString(baseIndent, 1) + " * including nulls, arrays, and standard reference types." + newLine);
1102 _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
1103 _writeToFileOut(indentString(baseIndent, 1) + "private java.lang.String " + methodName + "(java.lang.Object o) {" +
1104 newLine + newLine);
1105 _writeToFileOut(indentString(baseIndent, 2) + "class ArrayToString {" + newLine + newLine);
1106 _writeToFileOut(indentString(baseIndent, 3) + "public String valueFor(java.lang.Object o) {" + newLine);
1107 _writeToFileOut(indentString(baseIndent, 4) + "if (o instanceof java.lang.Object[]) {" + newLine);
1108
1109 if (useGenerics) {
1110 _writeToFileOut(indentString(baseIndent, 5) +
1111 "return arrayToString((java.lang.Object[]) o, new java.util.HashSet<java.lang.Object[]>());" +
1112 newLine);
1113 }
1114 else {
1115 _writeToFileOut(indentString(baseIndent, 5) +
1116 "return arrayToString((java.lang.Object[]) o, new java.util.HashSet());" + newLine);
1117 }
1118 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1119
1120 for (String type : primitiveTypes) {
1121 _writeToFileOut(indentString(baseIndent, 4) + "else if (o instanceof " + type + ") {" + newLine);
1122 _writeToFileOut(indentString(baseIndent, 5) + "return arrayToString((" + type + ") o);" + newLine);
1123 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1124 }
1125
1126 _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
1127 _writeToFileOut(indentString(baseIndent, 5) + "// o should be an array, but if not, toString() is called" + newLine);
1128 _writeToFileOut(indentString(baseIndent, 5) + "return o.toString();" + newLine);
1129 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1130
1131 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1132
1133 for (String type : primitiveTypes) {
1134 _writeToFileOut(indentString(baseIndent, 3) + "public java.lang.String arrayToString(" + type + " array) {" +
1135 newLine);
1136 _writeToFileOut(indentString(baseIndent, 4) + "java.lang.StringBuffer result = new java.lang.StringBuffer();" +
1137 newLine);
1138 _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"[\");" + newLine);
1139 _writeToFileOut(indentString(baseIndent, 4) + "if (array.length > 0) { result.append(array[0]); }" + newLine);
1140 _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 1; i < array.length; i++) {" + newLine);
1141 _writeToFileOut(indentString(baseIndent, 5) + "result.append(\", \");" + newLine);
1142 _writeToFileOut(indentString(baseIndent, 5) + "result.append(array[i]);" + newLine);
1143 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1144 _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"]\");" + newLine);
1145 _writeToFileOut(indentString(baseIndent, 4) + "return result.toString();" + newLine);
1146 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1147 }
1148
1149 if (useGenerics) {
1150 _writeToFileOut(indentString(baseIndent, 3) +
1151 "public java.lang.String arrayToString(java.lang.Object[] array, " +
1152 "java.util.HashSet<java.lang.Object[]> alreadyPrinted) {" + newLine);
1153 }
1154 else {
1155 _writeToFileOut(indentString(baseIndent, 3) +
1156 "public java.lang.String arrayToString(java.lang.Object[] array, " +
1157 "java.util.HashSet alreadyPrinted) {" + newLine);
1158 }
1159 _writeToFileOut(indentString(baseIndent, 4) +
1160 "if (alreadyPrinted.contains(array)) { return (\"[...]\"); }" + newLine);
1161 _writeToFileOut(indentString(baseIndent, 4) + "else { alreadyPrinted.add(array); }" + newLine + newLine);
1162 _writeToFileOut(indentString(baseIndent, 4) +
1163 "java.lang.StringBuffer result = new java.lang.StringBuffer();" + newLine);
1164 _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"[\");" + newLine);
1165 _writeToFileOut(indentString(baseIndent, 4) + "boolean nonEmpty = false;" + newLine);
1166 _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 0; i < array.length; i++) {" + newLine);
1167 _writeToFileOut(indentString(baseIndent, 5) + "if (nonEmpty) { result.append(\", \"); }" + newLine);
1168 _writeToFileOut(indentString(baseIndent, 5) + "nonEmpty = true;" + newLine + newLine);
1169 _writeToFileOut(indentString(baseIndent, 5) + "if (array[i] instanceof java.lang.Object[]) {" + newLine);
1170 _writeToFileOut(indentString(baseIndent, 6) +
1171 "result.append(arrayToString((java.lang.Object[]) array[i], alreadyPrinted));" + newLine);
1172 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1173 _writeToFileOut(indentString(baseIndent, 5) + "else {" + newLine);
1174 _writeToFileOut(indentString(baseIndent, 6) + "result.append(" + methodName + "(array[i]));" + newLine);
1175 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1176 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1177 _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"]\");" + newLine + newLine);
1178 _writeToFileOut(indentString(baseIndent, 4) + "alreadyPrinted.remove(array);" + newLine);
1179 _writeToFileOut(indentString(baseIndent, 4) + "return result.toString();" + newLine);
1180 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1181
1182 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine + newLine); // end of inner class
1183 _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return \"\" + null; }" + newLine);
1184 _writeToFileOut(indentString(baseIndent, 2) +
1185 "else if (o.getClass().isArray()) { return new ArrayToString().valueFor(o); }" + newLine);
1186 _writeToFileOut(indentString(baseIndent, 2) + "else { return o.toString(); }" + newLine);
1187 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1188 }
1189
1190 /** Helper to writeValueToString; writes a simple valueToString that does not handle arrays.
1191 * NOTE: This is currently unused. For the simple case, no valueToString method is generated.
1192 * @param sd The method's enclosing class.
1193 * @param baseIndent The base indent level (number of spaces).
1194 */
1195 private static void writeSimpleValueToString(SymbolData sd, int baseIndent, String methodName) {
1196 _writeToFileOut(newLine);
1197 _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
1198 _writeToFileOut(indentString(baseIndent, 1) +
1199 " * This method is automatically generated by the LanguageLevelConverter." + newLine);
1200 _writeToFileOut(indentString(baseIndent, 1) +
1201 " * As a helper to toString(), it generates a string for any object," + newLine);
1202 _writeToFileOut(indentString(baseIndent, 1) + " * including nulls and standard reference types." + newLine);
1203 _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
1204 _writeToFileOut(indentString(baseIndent, 1) + "private java.lang.String " + methodName + "(java.lang.Object o) {" +
1205 newLine + newLine);
1206 _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return \"\" + null; }" + newLine);
1207 _writeToFileOut(indentString(baseIndent, 2) + "else { return o.toString(); }" + newLine);
1208 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1209 }
1210
1211 /**
1212 * Write a method to compare any two objects, including arrays, nulls, and other reference types.
1213 *
1214 * @param sd The method's enclosing class.
1215 * @param baseIndent The base indent level (number of spaces).
1216 *
1217 * @return The name of the generated valueEquals method (__valueEquals by default).
1218 */
1219 private static String writeValueEquals(SymbolData sd, int baseIndent) {
1220 String methodName = sd.createUniqueMethodName("__valueEquals");
1221 if (_safeSupportCode) { writeSafeValueEquals(sd, baseIndent, methodName); }
1222 // else { writeSimpleValueEquals(sd, baseIndent, methodName); }
1223 return methodName;
1224 }
1225
1226 /** Helper to writeValueEquals; writes a valueEquals that correctly handles arbitrary arrays. */
1227 private static void writeSafeValueEquals(SymbolData sd, int baseIndent, String methodName) {
1228 String[] primitiveTypes = new String[]{"byte[]", "short[]", "char[]", "int[]", "long[]", "float[]", "double[]",
1229 "boolean[]"};
1230 boolean useGenerics = LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5);
1231
1232 _writeToFileOut(newLine);
1233 _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
1234 _writeToFileOut(indentString(baseIndent, 1) +
1235 " * This method is automatically generated by the LanguageLevelConverter." + newLine);
1236 _writeToFileOut(indentString(baseIndent, 1) +
1237 " * As a helper to equals(Object), it recursively compares any two objects," + newLine);
1238 _writeToFileOut(indentString(baseIndent, 1) +
1239 " * including nulls, arrays, and standard reference types." + newLine);
1240 _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
1241 _writeToFileOut(indentString(baseIndent, 1) + "private boolean " + methodName +
1242 "(java.lang.Object o1, java.lang.Object o2) {" + newLine + newLine);
1243 _writeToFileOut(indentString(baseIndent, 2) + "class ArrayEquals {" + newLine + newLine);
1244 _writeToFileOut(indentString(baseIndent, 3) +
1245 "public boolean valueFor(java.lang.Object o1, java.lang.Object o2) {" + newLine);
1246 _writeToFileOut(indentString(baseIndent, 4) +
1247 "if (o1 instanceof java.lang.Object[] && o2 instanceof java.lang.Object[]) {" + newLine);
1248 if (useGenerics) {
1249 _writeToFileOut(indentString(baseIndent, 5) + "return arrayEquals((java.lang.Object[]) o1, " +
1250 "(java.lang.Object[]) o2, new java.util.HashSet<java.lang.Object>());" + newLine);
1251 }
1252 else {
1253 _writeToFileOut(indentString(baseIndent, 5) + "return arrayEquals((java.lang.Object[]) o1, " +
1254 "(java.lang.Object[]) o2, new java.util.HashSet());" + newLine);
1255 }
1256 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1257
1258 for (String type : primitiveTypes) {
1259 _writeToFileOut(indentString(baseIndent, 4) + "else if (o1 instanceof " + type + " && o2 instanceof " +
1260 type + ") {" + newLine);
1261 _writeToFileOut(indentString(baseIndent, 5) + "return arrayEquals((" + type + ") o1, (" + type + ") o2);" +
1262 newLine);
1263 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1264 }
1265
1266 _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
1267 _writeToFileOut(indentString(baseIndent, 5) + "// o1 and o2 should be arrays, but if not, " +
1268 "or if they have different types, equals(Object) is called" + newLine);
1269 _writeToFileOut(indentString(baseIndent, 5) + "return o1.equals(o2);" + newLine);
1270 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1271
1272 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1273
1274 for (String type : primitiveTypes) {
1275 _writeToFileOut(indentString(baseIndent, 3) + "public boolean arrayEquals(" + type + " array1, " + type +
1276 " array2) {" + newLine);
1277 _writeToFileOut(indentString(baseIndent, 4) + "if (array1.length != array2.length) { return false; }" +
1278 newLine + newLine);
1279 _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
1280 _writeToFileOut(indentString(baseIndent, 5) + "for (int i = 0; i < array1.length; i++) {" + newLine);
1281 _writeToFileOut(indentString(baseIndent, 6) + "if (array1[i] != array2[i]) { return false; }" + newLine);
1282 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1283 _writeToFileOut(indentString(baseIndent, 5) + "return true;" + newLine);
1284 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1285 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1286 }
1287
1288 if (useGenerics) {
1289 _writeToFileOut(indentString(baseIndent, 3) + "public boolean arrayEquals(final java.lang.Object[] array1, " +
1290 "final java.lang.Object[] array2, java.util.HashSet<java.lang.Object> alreadyCompared) {" +
1291 newLine + newLine);
1292 }
1293 else {
1294 _writeToFileOut(indentString(baseIndent, 3) + "public boolean arrayEquals(final java.lang.Object[] array1," +
1295 " final java.lang.Object[] array2, java.util.HashSet alreadyCompared) {" + newLine + newLine);
1296 }
1297 _writeToFileOut(indentString(baseIndent, 4) + "class ArrayPair {" + newLine);
1298 _writeToFileOut(indentString(baseIndent, 5) + "public java.lang.Object[] array1() { return array1; }" + newLine);
1299 _writeToFileOut(indentString(baseIndent, 5) + "public java.lang.Object[] array2() { return array2; }" + newLine);
1300 _writeToFileOut(indentString(baseIndent, 5) + "public boolean equals(java.lang.Object o) {" + newLine);
1301 _writeToFileOut(indentString(baseIndent, 6) + "if ((o == null) || ! (o instanceof ArrayPair)) { return false; }" +
1302 newLine);
1303 _writeToFileOut(indentString(baseIndent, 6) +
1304 "else { return (array1.equals(((ArrayPair) o).array1())) && " +
1305 "(array2.equals(((ArrayPair) o).array2())); }" + newLine);
1306 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1307 _writeToFileOut(indentString(baseIndent, 5) +
1308 "public int hashCode() { return array1.hashCode() ^ (array2.hashCode() << 1); }" + newLine);
1309 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine + newLine);
1310 _writeToFileOut(indentString(baseIndent, 4) +
1311 "if (array1.length != array2.length) { return false; }" + newLine + newLine);
1312 _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
1313 _writeToFileOut(indentString(baseIndent, 5) + "ArrayPair currentPair = new ArrayPair();" + newLine);
1314 _writeToFileOut(indentString(baseIndent, 5) + "if (alreadyCompared.contains(currentPair)) { return true; }" +
1315 newLine);
1316 _writeToFileOut(indentString(baseIndent, 5) + "alreadyCompared.add(currentPair);" + newLine + newLine);
1317 _writeToFileOut(indentString(baseIndent, 5) + "boolean result = true;" + newLine);
1318 _writeToFileOut(indentString(baseIndent, 5) + "for (int i = 0; i < array1.length; i++) {" + newLine);
1319 _writeToFileOut(indentString(baseIndent, 6) +
1320 "if (array1[i] instanceof java.lang.Object[] && array2[i] instanceof java.lang.Object[]) {" +
1321 newLine);
1322 _writeToFileOut(indentString(baseIndent, 7) +
1323 "result = arrayEquals((java.lang.Object[]) array1[i], " +
1324 "(java.lang.Object[]) array2[i], alreadyCompared);" +
1325 newLine);
1326 _writeToFileOut(indentString(baseIndent, 6) + "}" + newLine);
1327 _writeToFileOut(indentString(baseIndent, 6) + "else {" + newLine);
1328 _writeToFileOut(indentString(baseIndent, 7) + "result = " + methodName + "(array1[i], array2[i]);"+ newLine);
1329 _writeToFileOut(indentString(baseIndent, 6) + "}" + newLine + newLine);
1330 _writeToFileOut(indentString(baseIndent, 6) + "if (!result) { break; }" + newLine);
1331 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine + newLine);
1332 _writeToFileOut(indentString(baseIndent, 5) + "alreadyCompared.remove(currentPair);" + newLine);
1333 _writeToFileOut(indentString(baseIndent, 5) + "return result;" + newLine);
1334 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1335 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1336
1337 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine + newLine); // end of inner class
1338 _writeToFileOut(indentString(baseIndent, 2) + "if (o1 == null) { return o2 == null; }" + newLine);
1339 _writeToFileOut(indentString(baseIndent, 2) + "else if (o2 == null) { return false; }" + newLine);
1340 _writeToFileOut(indentString(baseIndent, 2) +
1341 "else if (o1.getClass().isArray() && o2.getClass().isArray()) " +
1342 "{ return new ArrayEquals().valueFor(o1, o2); }" + newLine);
1343 _writeToFileOut(indentString(baseIndent, 2) + "else { return o1.equals(o2); }" + newLine);
1344 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1345 }
1346
1347 /** Helper to writeValueEquals; writes a simple valueEquals that does not handle arrays.
1348 * NOTE: This is currently unused. For the simple case, no valueEquals method is generated.
1349 */
1350 private static void writeSimpleValueEquals(SymbolData sd, int baseIndent, String methodName) {
1351 _writeToFileOut(newLine);
1352 _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
1353 _writeToFileOut(indentString(baseIndent, 1) +
1354 " * This method is automatically generated by the LanguageLevelConverter." + newLine);
1355 _writeToFileOut(indentString(baseIndent, 1) +
1356 " * As a helper to equals(Object), it compares any two objects," + newLine);
1357 _writeToFileOut(indentString(baseIndent, 1) + " * including nulls and standard reference types." + newLine);
1358 _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
1359 _writeToFileOut(indentString(baseIndent, 1) + "private boolean " +
1360 methodName + "(java.lang.Object o1, java.lang.Object o2) {" + newLine + newLine);
1361 _writeToFileOut(indentString(baseIndent, 2) + "if (o1 == null) { return o2 == null; }" + newLine);
1362 _writeToFileOut(indentString(baseIndent, 2) + "else if (o2 == null) { return false; }" + newLine);
1363 _writeToFileOut(indentString(baseIndent, 2) + "else { return o1.equals(o2); }" + newLine);
1364 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1365 }
1366
1367 /** Write a method to generate a hash code for any Object, including arrays, nulls, and other reference types.
1368 * @param sd The method's enclosing class.
1369 * @param baseIndent The base indent level (number of spaces).
1370 * @param valueEqualsName The name of the method generated by writeValueEquals()
1371 *
1372 * @return The name of the generated valueHashCode method (__valueHashCode by default).
1373 */
1374 private static String writeValueHashCode(SymbolData sd, int baseIndent, String valueEqualsName) {
1375 String methodName = sd.createUniqueMethodName("__valueHashCode");
1376 if (_safeSupportCode) { writeSafeValueHashCode(sd, baseIndent, valueEqualsName, methodName); }
1377 // else { writeSimpleValueHashCode(sd, baseIndent, valueEqualsName, methodName); }
1378 return methodName;
1379 }
1380
1381 /** Helper to writeValueHashCode; writes a valueHashCode that correctly handles arbitrary arrays. */
1382 private static void writeSafeValueHashCode(SymbolData sd, int baseIndent, String valueEqualsName, String methodName) {
1383 String[] primitiveTypes =
1384 new String[]{"byte[]", "short[]", "char[]", "int[]", "long[]", "float[]", "double[]", "boolean[]"};
1385 boolean useGenerics = LanguageLevelConverter.OPT.javaVersion().supports(JavaVersion.JAVA_5);
1386
1387 _writeToFileOut(newLine);
1388 _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
1389 _writeToFileOut(indentString(baseIndent, 1) +
1390 " * This method is automatically generated by the LanguageLevelConverter." + newLine);
1391 _writeToFileOut(indentString(baseIndent, 1) +
1392 " * As a helper to hashCode(), it recursively generates a hash code for any object," + newLine);
1393 _writeToFileOut(indentString(baseIndent, 1) +
1394 " * including nulls, arrays, and standard reference types." + newLine);
1395 _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
1396 _writeToFileOut(indentString(baseIndent, 1) + "private int " + methodName + "(java.lang.Object o) {" +
1397 newLine + newLine);
1398 _writeToFileOut(indentString(baseIndent, 2) + "class ArrayHashCode {" + newLine + newLine);
1399 _writeToFileOut(indentString(baseIndent, 3) + "public int valueFor(java.lang.Object o) {" + newLine);
1400 _writeToFileOut(indentString(baseIndent, 4) + "if (o instanceof java.lang.Object[]) {" + newLine);
1401 if (useGenerics) {
1402 _writeToFileOut(indentString(baseIndent, 5) +
1403 "return arrayHashCode((java.lang.Object[]) o, new java.util.LinkedList<java.lang.Object>());" +
1404 newLine);
1405 }
1406 else {
1407 _writeToFileOut(indentString(baseIndent, 5) +
1408 "return arrayHashCode((java.lang.Object[]) o, new java.util.LinkedList());" + newLine);
1409 }
1410 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1411
1412 for (String type : primitiveTypes) {
1413 _writeToFileOut(indentString(baseIndent, 4) + "else if (o instanceof " + type + ") {" + newLine);
1414 _writeToFileOut(indentString(baseIndent, 5) + "return arrayHashCode((" + type + ") o);" + newLine);
1415 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1416 }
1417
1418 _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
1419 _writeToFileOut(indentString(baseIndent, 5) + "// o should be an array, but if not, hashCode() is called" +
1420 newLine);
1421 _writeToFileOut(indentString(baseIndent, 5) + "return o.hashCode();" + newLine);
1422 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1423 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1424
1425 for (String type : primitiveTypes) {
1426 _writeToFileOut(indentString(baseIndent, 3) + "public int arrayHashCode(" + type + " array) {" + newLine);
1427 _writeToFileOut(indentString(baseIndent, 4) + "int result = 0;" + newLine);
1428 _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 0; i < array.length; i++) {" + newLine);
1429 if (type.equals("boolean[]")) {
1430 _writeToFileOut(indentString(baseIndent, 5) + "result = (result << 1) ^ (array[i] ? 1 : 0);" + newLine);
1431 }
1432 else {
1433 _writeToFileOut(indentString(baseIndent, 5) + "result = (result << 1) ^ (int) array[i];" + newLine);
1434 }
1435 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
1436 _writeToFileOut(indentString(baseIndent, 4) + "return result;" + newLine);
1437 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1438 }
1439
1440 if (useGenerics) {
1441 _writeToFileOut(indentString(baseIndent, 3) + "public int arrayHashCode(final java.lang.Object[] array, " +
1442 "final java.util.LinkedList<java.lang.Object> alreadyGenerated) {" + newLine + newLine);
1443 }
1444 else {
1445 _writeToFileOut(indentString(baseIndent, 3) + "public int arrayHashCode(final java.lang.Object[] array, " +
1446 "final java.util.LinkedList alreadyGenerated) {" + newLine + newLine);
1447 }
1448 _writeToFileOut(indentString(baseIndent, 4) + "class ArrayWrapper {" + newLine);
1449 _writeToFileOut(indentString(baseIndent, 5) + "public java.lang.Object[] array() { return array; }" + newLine);
1450 _writeToFileOut(indentString(baseIndent, 5) + "public boolean equals(java.lang.Object o) {" + newLine);
1451 _writeToFileOut(indentString(baseIndent, 6) + "return (o != null) && (o instanceof ArrayWrapper) && " +
1452 valueEqualsName + "(array, ((ArrayWrapper) o).array());" + newLine);
1453 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1454 _writeToFileOut(indentString(baseIndent, 5) +
1455 "public int hashCode() { return 0; } // This method should never be used -- " +
1456 "only here for consistency." + newLine);
1457 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine + newLine);
1458
1459 _writeToFileOut(indentString(baseIndent, 4) + "ArrayWrapper currentWrapper = new ArrayWrapper();" + newLine);
1460 _writeToFileOut(indentString(baseIndent, 4) + "if (alreadyGenerated.contains(currentWrapper)) { return -1; }" +
1461 newLine);
1462 _writeToFileOut(indentString(baseIndent, 4) + "alreadyGenerated.addLast(currentWrapper);" + newLine + newLine);
1463
1464 _writeToFileOut(indentString(baseIndent, 4) + "int result = 0;" + newLine);
1465 _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 0; i < array.length; i++) {" + newLine);
1466 _writeToFileOut(indentString(baseIndent, 5) + "if (array[i] instanceof java.lang.Object[]) {" + newLine);
1467 _writeToFileOut(indentString(baseIndent, 6) +
1468 "result = (result << 1) ^ (arrayHashCode((java.lang.Object[]) array[i], alreadyGenerated) >> 1);" +
1469 newLine);
1470 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1471 _writeToFileOut(indentString(baseIndent, 5) + "else {" + newLine);
1472 _writeToFileOut(indentString(baseIndent, 6) + "result = (result << 1) ^ " + methodName + "(array[i]);" + newLine);
1473 _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
1474 _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine + newLine);
1475 _writeToFileOut(indentString(baseIndent, 4) + "alreadyGenerated.removeLast();" + newLine);
1476 _writeToFileOut(indentString(baseIndent, 4) + "return result;" + newLine);
1477 _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
1478
1479 _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine + newLine); // end of inner class
1480 _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return 0; }" + newLine);
1481 _writeToFileOut(indentString(baseIndent, 2) +
1482 "else if (o.getClass().isArray()) { return new ArrayHashCode().valueFor(o); }" + newLine);
1483 _writeToFileOut(indentString(baseIndent, 2) + "else { return o.hashCode(); }" + newLine);
1484 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1485 }
1486
1487 /** Helper to writeValueHashCode; writes a valueHashCode that does not handle arrays.
1488 * NOTE: This is currently unused. For the simple case, no valueHashCode method is generated.
1489 */
1490 private static void writeSimpleValueHashCode(SymbolData sd, int baseIndent, String valueEqualsName,
1491 String methodName) {
1492 _writeToFileOut(newLine);
1493 _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
1494 _writeToFileOut(indentString(baseIndent, 1) +
1495 " * This method is automatically generated by the LanguageLevelConverter." + newLine);
1496 _writeToFileOut(indentString(baseIndent, 1) +
1497 " * As a helper to hashCode(), it generates a hash code for any object," + newLine);
1498 _writeToFileOut(indentString(baseIndent, 1) + " * including nulls and standard reference types." + newLine);
1499 _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
1500 _writeToFileOut(indentString(baseIndent, 1) + "private int " + methodName + "(java.lang.Object o) {" +
1501 newLine + newLine);
1502 _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return 0; }" + newLine);
1503 _writeToFileOut(indentString(baseIndent, 2) + "else { return o.hashCode(); }" + newLine);
1504 _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
1505 }
1506
1507 private static String indentString(int baseIndent, int indentCount) {
1508 int length = indentCount * indentWidth + baseIndent;
1509 StringBuffer result = new StringBuffer(length);
1510 for (int i = 0; i < length; i++) {
1511 result.append(' ');
1512 }
1513 return result.toString();
1514 }
1515
1516 // private static boolean _isElementaryFile() { return LanguageLevelConverter.isElementaryFile(_llv._file); }
1517 // private static boolean _isIntermediateFile() { return LanguageLevelConverter.isIntermediateFile(_llv._file); }
1518 // private static boolean _isAdvancedFile() { return LanguageLevelConverter.isAdvancedFile(_llv._file); }
1519
1520 private static LinkedList<MethodData> _getVariableAccessorListHelper(SymbolData currClass) {
1521 List<Pair<VariableData, MethodData>> accessorMappings = new Vector<Pair<VariableData, MethodData>>();
1522 LinkedList<SymbolData> classes = new LinkedList<SymbolData>();
1523 classes.add(currClass);
1524
1525 // Gather all accessor methods that have a matching signature with their variables
1526 while (classes.size() > 0) {
1527 SymbolData tempSd = classes.removeFirst();
1528 if (LanguageLevelVisitor.isJavaLibraryClass(tempSd.getName())) { break; }
1529
1530 for (int i = 0; i<tempSd.getVars().size(); i++) {
1531 VariableData tempVd = tempSd.getVars().get(i);
1532 MethodData md = tempSd.getMethod(tempVd.getName(), new TypeData[0]);
1533 if (md != null)
1534 accessorMappings.add(new Pair<VariableData, MethodData>(tempVd, md));
1535 }
1536 // Note that we don't need to check interface fields, because they are always static.
1537
1538 // Insure that we traverse the superclass hierarchy before we traverse the outer class hierarchy
1539 SymbolData superClass = tempSd.getSuperClass();
1540 if (superClass != null) classes.addFirst(superClass);
1541 Data outerData = tempSd.getOuterData();
1542 if (outerData != null) { classes.addLast(outerData.getSymbolData()); }
1543 }
1544
1545 // Eliminate those accessors that are inaccessible, that throw exceptions, that are static, that are shadowed,
1546 // or that have a different return type
1547 LinkedList<MethodData> allMethods = new LinkedList<MethodData>();
1548 for (int i = accessorMappings.size() - 1; i >= 0; i--) {
1549 VariableData vd = accessorMappings.get(i).getFirst();
1550 MethodData md = accessorMappings.get(i).getSecond();
1551 boolean canSeeMethod =
1552 TypeChecker.checkAccess(new NullLiteral(SourceInfo.NONE), md.getMav(), md.getName(),
1553 md.getSymbolData(), currClass, "method", false);
1554 //TODO: it is okay to throw Runtime exceptions or Errors) {
1555 if (canSeeMethod && (! md.hasModifier("static")) && (md.getThrown().length == 0) &&
1556 vd.getType().getSymbolData().isAssignableTo(md.getReturnType(), LanguageLevelConverter.OPT.javaVersion())) {
1557 boolean isShadowed = false;
1558 for (int j = i - 1; j >= 0; j--) {
1559 if (accessorMappings.get(j).getSecond().getName().equals(md.getName())) { isShadowed = true; break; }
1560 }
1561 if (!isShadowed) { allMethods.addFirst(md); }
1562 }
1563 }
1564 return allMethods;
1565 }
1566
1567 /** Reads _fileIn through the given (line, column) returning this text. On completion, the current cursor
1568 * (_fileInLine, fileInColumn) is one character after (line, column).
1569 * @param line The line number to read through.
1570 * @param column The column to read to (or 0 to read to through the end of the previous line).
1571 */
1572 private static String _readThroughIndex(int line, int column) {
1573 if (_fileInLine > line || (_fileInLine == line && _fileInColumn - 1 > column)) {
1574 throw new RuntimeException("Internal Program Error: Attempt to read in " + _llv._file.getName() +
1575 " at a point that is already past: line " + line + ", column " + column +
1576 "; (currently at " + _fileInLine + ", " + _fileInColumn + "). Please report this bug.");
1577 }
1578
1579 try {
1580 StringBuffer result = new StringBuffer();
1581 while (_fileInLine < line) {
1582 String l = _fileIn.readLine();
1583 if (l == null) {
1584 _fileOut.flush();
1585 throw new RuntimeException("Internal Program Error: Attempt to read in " + _llv._file.getName() +
1586 " past the end of file: line " + line + ", column " + column + "; (currently at " +
1587 _fileInLine + ", " + _fileInColumn + "). Please report this bug.");
1588 }
1589
1590 result.append(l).append(newLine);
1591
1592 _fileInLine++;
1593 _fileInColumn = 1;
1594 }
1595
1596 int lastLineLength = column - _fileInColumn + 1;
1597 char[] chars = new char[lastLineLength];
1598 int charsRead = _fileIn.read(chars, 0, lastLineLength);
1599 if (charsRead != lastLineLength) {
1600 _fileOut.flush();
1601 throw new RuntimeException("Internal Program Error: Attempt to read in " + _llv._file.getName() +
1602 " past the end of file: line " + line + ", column " + column + "; (currently at " +
1603 _fileInLine + ", " + _fileInColumn + "). Please report this bug.");
1604 }
1605 result.append(chars);
1606 _fileInLine = line;
1607 _fileInColumn = column + 1;
1608 return result.toString();
1609 }
1610 catch (IOException ioe) { throw new Augmentor.Exception(ioe); }
1611 }
1612
1613 /** Reads _fileIn through the given line & column and write to output. On completion, the current cursor is one
1614 * character after (line, column).
1615 * @param line The line number to read through.
1616 * @param column The column to read to (or 0 to read to through the end of the previous line).
1617 */
1618 private static void _readAndWriteThroughIndex(int line, int column) {
1619 String text = _readThroughIndex(line, column);
1620 _writeToFileOut(text, true); // yes, writing straight from input
1621 }
1622
1623 private static void _writeToFileOut(String s) { _writeToFileOut(s, false); }
1624
1625 /** Write the string to _fileOut. If fromInput is true, the string is coming straight from the input file,
1626 * which means the corresponding line number should be incremented as well.
1627 * @param s The string to write.
1628 * @param fromInput true if the corresponding line number should be incremented as well */
1629 private static void _writeToFileOut(String s, boolean fromInput) {
1630 try {
1631 String[] lines = s.split(newLine, -1);
1632 for(int i=0; i<lines.length-1; ++i) {
1633 _fileOut.write(lines[i]);
1634 // add line number to map if it doesn't exist yet
1635 if (_lineNumberMap.get(_fileOutCorrespondingLine)==null)
1636 _lineNumberMap.put(_fileOutCorrespondingLine, _fileOutLine);
1637 // end-of-line line number mapping; disabled since we output the entire map at the beginning of the file
1638 // _fileOut.write("//["+_fileOutCorrespondingLine+"]");
1639 _fileOut.write(newLine);
1640 ++_fileOutLine;
1641 if (fromInput) ++_fileOutCorrespondingLine; // true if we are copying straight from input
1642 }
1643 _fileOut.write(lines[lines.length-1]);
1644 }
1645 catch (IOException ioe) { throw new Augmentor.Exception(ioe); }
1646 }
1647
1648 /** Reads _fileIn through the specified (line, column) but leaves the file cursor unchanged.
1649 * @param line The line number to read through.
1650 * @param column The column to read to (or 0 to read to through the end of the previous line).
1651 */
1652 private static String _peek(int line, int column) {
1653
1654 try {
1655 _fileIn.mark(LanguageLevelConverter.INPUT_BUFFER_SIZE);
1656 // Save the cursor
1657 int fileInLine = _fileInLine;
1658 int fileInColumn = _fileInColumn;
1659 String text = _readThroughIndex(line, column);
1660 _fileIn.reset();
1661 // Reset the cursor
1662 _fileInLine = fileInLine;
1663 _fileInColumn = fileInColumn;
1664 return text;
1665 }
1666 catch (IOException ioe) { throw new Augmentor.Exception(ioe); }
1667 }
1668
1669 /** Returns a copy of the line number map that maps original dj* line numbers
1670 * to generated java line numbers.
1671 * @return copy of line number map */
1672 public static SortedMap<Integer,Integer> getLineNumberMap() {
1673 return new TreeMap<Integer,Integer>(_lineNumberMap);
1674 }
1675
1676 public static class MethodBodyAugmentor extends Augmentor {
1677
1678 /** Mandatory forwarding constructor. */
1679 protected MethodBodyAugmentor(SymbolData enclosing) { super(enclosing); }
1680
1681 /** Writes out implicit variableDeclarationModfiers that must be added to augmented file. */
1682 protected void augmentVariableDeclarationModifiers(VariableDeclaration that) { _writeToFileOut("final "); }
1683 }
1684
1685 public static class Exception extends RuntimeException {
1686 public Exception(java.lang.Exception nested) { super(nested); }
1687 }
1688
1689 /** Test class for the Augmentor class. */
1690 public static class AugmentorTest extends TestCase {
1691
1692 public AugmentorTest() {
1693 this("");
1694 }
1695 public AugmentorTest(String name) {
1696 super(name);
1697 }
1698
1699 private Augmentor _a;
1700 private Symboltable _s = LanguageLevelConverter.symbolTable; // Define a short synonym
1701 private File _f = new File("");
1702
1703 public void setUp() {
1704 LanguageLevelVisitor llv =
1705 new IntermediateVisitor(_f,
1706 new LinkedList<Pair<String, JExpressionIF>>(),
1707 new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1708 new LinkedList<Command>(),
1709 new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>());
1710 _a = new Augmentor(true, null, null, llv);
1711 LanguageLevelConverter.symbolTable.clear();
1712 Symboltable _s = LanguageLevelConverter.symbolTable;
1713 LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
1714 }
1715
1716 public void testFormalParameters2TypeDatas() {
1717 FormalParameter[] fp = new FormalParameter[0];
1718 TypeData[] result = formalParameters2TypeDatas(fp, _a._enclosingData);
1719 assertEquals("The result is empty", 0, result.length);
1720
1721 PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
1722 FormalParameter param =
1723 new FormalParameter(SourceInfo.NONE,
1724 new UninitializedVariableDeclarator(SourceInfo.NONE, intt,
1725 new Word(SourceInfo.NONE, "j")), false);
1726 SymbolData intData = SymbolData.INT_TYPE;
1727 _s.put("int", intData);
1728
1729 ClassOrInterfaceType stringt = new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.String", new Type[0]);
1730 FormalParameter param2 =
1731 new FormalParameter(SourceInfo.NONE,
1732 new UninitializedVariableDeclarator(SourceInfo.NONE, stringt,
1733 new Word(SourceInfo.NONE, "j")), false);
1734 SymbolData stringData = new SymbolData("java.lang.String");
1735 _s.put("java.lang.String", stringData);
1736
1737 fp = new FormalParameter[]{ param, param2 };
1738 result = formalParameters2TypeDatas(fp, _a._enclosingData);
1739 assertTrue("Arrays should be equal",
1740 LanguageLevelVisitor.arrayEquals(result, new TypeData[]{ intData, stringData }));
1741
1742 UninitializedVariableDeclarator vd =
1743 new UninitializedVariableDeclarator(SourceInfo.NONE,
1744 new ClassOrInterfaceType(SourceInfo.NONE, "Inner", new Type[0]),
1745 new Word(SourceInfo.NONE, "t"));
1746 //test an inner class
1747 FormalParameter param3 =
1748 new FormalParameter(SourceInfo.NONE, vd, false);
1749 fp = new FormalParameter[] {param3};
1750 SymbolData inner = new SymbolData("Inner");
1751 inner.setIsContinuation(false);
1752 _a._enclosingData = new SymbolData("me");
1753 _a._enclosingData.addInnerClass(inner);
1754 result = formalParameters2TypeDatas(fp, _a._enclosingData);
1755 assertTrue("Arrays should be equal", LanguageLevelVisitor.arrayEquals(result, new TypeData[] {inner}));
1756 }
1757
1758
1759 public void testIndentString() {
1760 assertEquals("Should return a string of 0 tabs", "", indentString(0, 0));
1761 assertEquals("Should return a string of 6 tabs", " ", indentString(2, 5));
1762 }
1763
1764 // public void testIsElementaryFile() {
1765 // _llv = new ElementaryVisitor(new File("elementary.dj0"), new LinkedList<Pair<String, JExpressionIF>>(), _s,
1766 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1767 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1768 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1769 // assertTrue("This is an elementary file", _isElementaryFile());
1770 // _llv = new IntermediateVisitor(new File("intermediate.dj1"),
1771 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1772 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1773 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1774 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1775 // assertFalse("This is an intermediate file", _isElementaryFile());
1776 // _llv = new AdvancedVisitor(new File("advanced.dj2"),
1777 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1778 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1779 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1780 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1781 // assertFalse("This is an advanced file", _isElementaryFile());
1782 // _llv = new ElementaryVisitor(new File("full.java"),
1783 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1784 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1785 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1786 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1787 // assertFalse("This is a full file", _isElementaryFile());
1788 // }
1789
1790 // public void testIsIntermediateFile() {
1791 // _llv = new ElementaryVisitor(new File("elementary.dj0"),
1792 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1793 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1794 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1795 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1796 // assertFalse("This is an elementary file", _isIntermediateFile());
1797 // _llv = new IntermediateVisitor(new File("intermediate.dj1"),
1798 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1799 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1800 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1801 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1802 // assertTrue("This is an intermediate file", _isIntermediateFile());
1803 // _llv = new AdvancedVisitor(new File("advanced.dj2"),
1804 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1805 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1806 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1807 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1808 // assertFalse("This is an advanced file", _isIntermediateFile());
1809 // _llv = new ElementaryVisitor(new File("full.java"),
1810 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1811 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1812 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1813 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1814 // assertFalse("This is a full file", _isIntermediateFile());
1815 // }
1816 //
1817 // public void testIsAdvancedFile() {
1818 // _llv = new ElementaryVisitor(new File("elementary.dj0"),
1819 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1820 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1821 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1822 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1823 // assertFalse("This is an elementary file", _isAdvancedFile());
1824 // _llv = new IntermediateVisitor(new File("intermediate.dj1"),
1825 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1826 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1827 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1828 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1829 // assertFalse("This is an intermediate file", _isAdvancedFile());
1830 // _llv = new AdvancedVisitor(new File("advanced.dj2"),
1831 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1832 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1833 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1834 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1835 // assertTrue("This is an advanced file", _isAdvancedFile());
1836 // _llv = new ElementaryVisitor(new File("full.java"),
1837 // new LinkedList<Pair<String, JExpressionIF>>(), _s,
1838 // new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
1839 // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(),
1840 // new Hashtable<SymbolData, LanguageLevelVisitor>());
1841 // assertFalse("This is a full file", _isAdvancedFile());
1842 // }
1843 //
1844 public void testGetVariableAccessorListHelper() {
1845 ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
1846 ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
1847
1848 SymbolData houston = new SymbolData("Houston");
1849 SymbolData texas = new SymbolData("Texas");
1850 houston.setSuperClass(texas);
1851
1852 //first, add a field to texas that has a public gettor. This one should be returned.
1853 texas.addVar(new VariableData("lone_star", _publicMav, SymbolData.INT_TYPE, true, texas));
1854 MethodData lone_star = new MethodData("lone_star", _publicMav,
1855 new TypeParameter[0], SymbolData.INT_TYPE,
1856 new VariableData[0],
1857 new String[0], texas,
1858 new NullLiteral(SourceInfo.NONE));
1859 texas.addMethod(lone_star);
1860
1861 //no gettor for cool, therefore, it should not be returned.
1862 //NOTE: gettor might be best spelled "getter", but whoever is typing believes it should be spelled this way.
1863 texas.addVar(new VariableData("cool", _publicMav, SymbolData.DOUBLE_TYPE, true, texas));
1864
1865 //now, add a private gettor for armidillo to texas. This should not be returned, because it is private.
1866 texas.addVar(new VariableData("armadillo", _publicMav, SymbolData.BOOLEAN_TYPE, true, texas));
1867 MethodData armadillo = new MethodData("armadillo", _privateMav,
1868 new TypeParameter[0],
1869 SymbolData.BOOLEAN_TYPE,
1870 new VariableData[0],
1871 new String[0], texas,
1872 new NullLiteral(SourceInfo.NONE));
1873 texas.addMethod(armadillo);
1874
1875 // Now add a field badRoad to Houston. Its gettor returns a supertype of its type, so it is okay to call.
1876 // Will be returned.
1877 houston.addVar(new VariableData("badRoad", _publicMav, SymbolData.CHAR_TYPE, true, houston));
1878 MethodData badRoad = new MethodData("badRoad", _publicMav,
1879 new TypeParameter[0],
1880 SymbolData.INT_TYPE,
1881 new VariableData[0],
1882 new String[0], houston,
1883 new NullLiteral(SourceInfo.NONE));
1884 houston.addMethod(badRoad);
1885
1886 LinkedList<MethodData> expected = new LinkedList<MethodData>();
1887 expected.add(badRoad);
1888 expected.add(lone_star);
1889 LinkedList<MethodData> actual = _getVariableAccessorListHelper(houston);
1890 // for(MethodData m : actual)
1891 // System.out.println(m.getName());
1892 assertEquals("Should return the right list of gettors", expected, actual);
1893
1894
1895 //if there aren't any fields or methods, that's still okay!
1896 SymbolData soLonely = new SymbolData("I have no fields!");
1897 assertEquals("Should return an empty list", 0, _getVariableAccessorListHelper(soLonely).size());
1898 }
1899
1900 }
1901 }