001 /*BEGIN_COPYRIGHT_BLOCK
002 *
003 * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 * * Redistributions of source code must retain the above copyright
009 * notice, this list of conditions and the following disclaimer.
010 * * Redistributions in binary form must reproduce the above copyright
011 * notice, this list of conditions and the following disclaimer in the
012 * documentation and/or other materials provided with the distribution.
013 * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014 * names of its contributors may be used to endorse or promote products
015 * derived from this software without specific prior written permission.
016 *
017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028 *
029 * This software is Open Source Initiative approved Open Source Software.
030 * Open Source Initative Approved is a trademark of the Open Source Initiative.
031 *
032 * This file is part of DrJava. Download the current version of this project
033 * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034 *
035 * END_COPYRIGHT_BLOCK*/
036
037 package edu.rice.cs.javalanglevels;
038
039 import edu.rice.cs.javalanglevels.tree.*;
040 import edu.rice.cs.javalanglevels.parser.*;
041 import edu.rice.cs.javalanglevels.util.*;
042 import java.util.*;
043 import junit.framework.TestCase;
044
045 /** Represents the data for a given variable (including fields). */
046 public class VariableData {
047
048 /**The name of this variable*/
049 private String _name;
050
051 /** The modifiers and visibility. */
052 private ModifiersAndVisibility _modifiersAndVisibility;
053
054 /** The type of this variable represented by a SymbolData. */
055 private SymbolData _type;
056
057 /** True if this variable has been given a value*/
058 private boolean _hasBeenAssigned;
059
060 /** True if this variable has an initializer*/
061 private boolean _hasInitializer;
062
063 /** The data that this variable belongs to. For a formal parameter, it is the enclosing class rather than the
064 * enclosing method. */
065 private Data _enclosingData;
066
067 /** True iff this is a field we had generated. */
068 private boolean _generated;
069
070 /** True iff this is a method parameter. */
071 private boolean _isLocalVariable;
072
073 /** An instance corresponding to this; generated on demand. */
074 private InstanceData _instance;
075
076 /** Constructor for VariableData. hasInitializer and generated are set to {@code false}.
077 * @param name The name of the variable
078 * @param modifiersAndVisibility The modifiersAndVisibility
079 * @param type The SymbolData type of the variable.
080 * @param hasBeenAssigned true if this variable has a value
081 * @param enclosingData the enclosing data
082 */
083 public VariableData(String name, ModifiersAndVisibility modifiersAndVisibility, SymbolData type,
084 boolean hasBeenAssigned, Data enclosingData) {
085 _name = name;
086 _modifiersAndVisibility = modifiersAndVisibility;
087 _type = type;
088 _hasBeenAssigned = hasBeenAssigned;
089 _enclosingData = enclosingData;
090 _hasInitializer = false;
091 _generated = false;
092 _isLocalVariable = false;
093 _instance = null;
094 }
095
096 /** This constructor is only used when reading method parameters in a class file because class files only store the
097 * types of method parameters.
098 */
099 public VariableData(SymbolData type) {
100 _name = "";
101 _modifiersAndVisibility = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
102 _type = type;
103 _hasBeenAssigned = false;
104 _isLocalVariable = true;
105 _instance = null;
106 }
107
108 /** Make a copy of this VariableData erasing all visibility modifiers and setting hasBeenAssigned to true. Used in
109 * LanguageLevelVisitor.createConstructor to generate the parameter list of the created constructor.
110 * @return a new Variable Data identical to this except for erasing visibility modifiers. */
111 public VariableData copyWithoutVisibility() {
112 String[] mavStrings = _modifiersAndVisibility.getModifiers();
113 LinkedList<String> newMavList = new LinkedList<String>();
114 int size = 0;
115 for (int i = 0; i < mavStrings.length; i++) {
116 String mod = mavStrings[i];
117 if (! isVisibility(mod)) {
118 newMavList.add(mod);
119 size++;
120 }
121 }
122 String[] newMavStrings = newMavList.toArray(new String[size]);
123 ModifiersAndVisibility newMav = new ModifiersAndVisibility(SourceInfo.NONE, newMavStrings);
124 return new VariableData(_name, newMav, _type, true, _enclosingData);
125 }
126
127 /** Checks the values of the fields*/
128 public boolean equals(Object obj) {
129 if (obj == null) return false;
130 else if (obj.getClass() != this.getClass()) {
131 // System.err.println("VariableData.equals: Class equality failure");
132 return false;
133 }
134
135 VariableData vd = (VariableData) obj;
136
137 if (! _name.equals(vd.getName())) {
138 // System.err.println("VariableData.equals: name equality failure");
139 return false;
140 }
141 if (! _modifiersAndVisibility.equals(vd.getMav())) {
142 // System.err.println("VariableData.equals: modifiersAndVisibility equality failure");
143 return false;
144 }
145
146 if (! _type.equals(vd.getType())) {
147 // System.err.println("VariableData.equals: type equality failure");
148 return false;
149 }
150
151 if (_hasBeenAssigned != vd.hasValue()) {
152 // System.err.println("VariableData.equals: hasBeenAssigned equality failure");
153 return false;
154 }
155 if (_hasInitializer != vd._hasInitializer) {
156 // System.err.println("VariableData.equals: hasInitializer equality failure");
157 return false;
158 }
159 Data otherEnclosingData = vd.getEnclosingData();
160
161 if (_enclosingData == null) {
162 if (otherEnclosingData == null) return true;
163 else {
164 // System.err.println("VariableData.equals: enclosingData failure");
165 return false;
166 }
167 } // formerly .equals but led to infinite loop when _enclosingData is a VariableData
168 else if (_enclosingData != otherEnclosingData) {
169 // System.err.println("VariableData.equals: enclosingData failure");
170 return false;
171 }
172
173 return true;
174 }
175
176 /**Hash on the name and enclosing data, since within each enclosing data, the variable name should be unique*/
177 public int hashCode() { return getEnclosingData().hashCode() ^ getName().hashCode(); }
178
179 /**@return a readable representation of the Variable data*/
180 public String toString() {
181 return "VariableData(" + _name + ", " + Arrays.toString(_modifiersAndVisibility.getModifiers()) + ", " + _type +
182 ", " + _hasBeenAssigned + ")";
183 }
184
185 /**@return the name of this field or variable*/
186 public String getName() { return _name; }
187
188 /**Set the name of this variable to the specified string. */
189 public void setName(String s) { _name = s; }
190
191 /**@return the modifiers and visibility. */
192 public ModifiersAndVisibility getMav() { return _modifiersAndVisibility; }
193
194 /**Set the modifiers and visibility to the specified value. */
195 public void setMav(ModifiersAndVisibility mav) { _modifiersAndVisibility = mav; }
196
197 /** @return the SymbolData representing the type of this variable. */
198 public SymbolData getType() { return _type;
199 /* The following appears to break the Augmentor visitor. Why? */
200 // if (_type != null) return _type;
201 // return SymbolData.NOT_FOUND;
202 }
203
204 /** Sets the SymbolData representing the type of this variable. */
205 public void setType(SymbolData type) { _type = type; }
206
207 /** Assumes _type != null
208 * @return the InstanceData corresponding to the type of this variable. */
209 public InstanceData getInstanceData() {
210 assert _type != null;
211 if (_instance == null) _instance = _type.getInstanceData();
212 return _instance;
213 }
214
215 /** @return the enclosing data. */
216 public Data getEnclosingData() { return _enclosingData; }
217
218 /** Sets the enclosing data to the specified value. */
219 public void setEnclosingData(Data d) { _enclosingData = d; }
220
221 /** @return the _isLocalVariable flag.*/
222 public boolean isLocalVariable() { return _isLocalVariable; }
223
224 /** Sets the isLocalVariable flag to the specified value. */
225 public void setIsLocalVariable(boolean b) { _isLocalVariable = b; }
226
227 /** Adds "final" to the modifiers and visibility for this class, if it is not already there. */
228 public void setFinal() {
229 String[] newModifiers = Utilities.catenate(_modifiersAndVisibility.getModifiers(), new String[]{"final"});
230 // System.err.println("modifiers with 'final' = " + Arrays.toString(newModifiers));
231 _modifiersAndVisibility = new ModifiersAndVisibility(SourceInfo.NONE, newModifiers);
232 }
233
234 /** Adds "private" to the modifiers and visibility for this class, if it is not already there. */
235 public void setPrivate() {
236 if (! hasModifier("private")) {
237 String[] modifiers = _modifiersAndVisibility.getModifiers();
238 String[] newModifiers = new String[modifiers.length + 1];
239 newModifiers[0] = "private";
240 for (int i = 1; i <= modifiers.length; i++) {
241 newModifiers[i] = modifiers[i-1];
242 }
243 _modifiersAndVisibility = new ModifiersAndVisibility(SourceInfo.NONE, newModifiers);
244 }
245 }
246
247 /** Add the specified modifier to the modifiers and visibility for this class, if it is not already there. */
248 public void addModifier(String s) {
249 if (! hasModifier(s)) {
250 String[] modifiers = _modifiersAndVisibility.getModifiers();
251 String[] newModifiers = new String[modifiers.length + 1];
252 newModifiers[0] = s;
253 for (int i = 1; i <= modifiers.length; i++) {
254 newModifiers[i] = modifiers[i-1];
255 }
256 _modifiersAndVisibility = new ModifiersAndVisibility(SourceInfo.NONE, newModifiers);
257 }
258 }
259
260 /** Adds "private" and "final" to the modifiers and visibility for this class, if it is not already there. */
261 public void setPrivateAndFinal() {
262 setPrivate();
263 setFinal();
264 }
265
266 /** Adds "final" and "static" to the modifiers and visibility for this class, if it is not already there. */
267 public void setFinalAndStatic() {
268 setFinal();
269 addModifier("static");
270 }
271
272 /** Returns true if this VariableData is final. */
273 public boolean isFinal() { return hasModifier("final"); }
274
275 /** Returns true if this VariableData is private. */
276 public boolean isPrivate() { return hasModifier("private"); }
277
278 /** Returns true if this VariableData is static. */
279 public boolean isStatic() { return hasModifier("static"); }
280
281 public static boolean isVisibility(String s) {
282 return s.equals("private") || s.equals("protected") || s.equals("public");
283 }
284
285 /** Returns true if this variable has the modifier specified. */
286 public boolean hasModifier(String modifier) {
287 String[] mavStrings = _modifiersAndVisibility.getModifiers();
288 for (int i = 0; i < mavStrings.length; i++) {
289 if (mavStrings[i].equals(modifier)) {
290 return true;
291 }
292 }
293 return false;
294 }
295
296 /**Set the generated flag to the specified value*/
297 public void setGenerated(boolean value) { _generated = value; }
298
299 /**@return the generated flag*/
300 public boolean isGenerated() { return _generated; }
301
302 /** Returns true iff this variable was declared with an initial value */
303 public boolean hasInitializer() { return _hasInitializer; }
304
305 /** Set the "hasInitializer" flag */
306 public void setHasInitializer(boolean value) { _hasInitializer = value; }
307
308 /** Returns true if this VariableData has been given a value. */
309 public boolean hasValue() { return _hasBeenAssigned; }
310
311 /** Set _hasBeenAssigned flag. */
312 public void setHasValue() { _hasBeenAssigned = true; }
313
314 /** If this VariableData has not been given a value, set _hasBeenAssigned to true, and return true. Otherwise,
315 * return false to indicate it already has a value and should not be reassigned. */
316 public boolean gotValue() {
317 if (hasValue()) { return false; }
318 _hasBeenAssigned = true;
319 return true;
320 }
321
322 /** If this VariableData has a value, set _hasBeenAssigned to false, and return true. Otherwise, return false. */
323 public boolean lostValue() {
324 if (hasValue()) {
325 _hasBeenAssigned = false;
326 return true;
327 }
328 return false;
329 }
330
331 /** Test the methods defined in the above class. */
332 public static class VariableDataTest extends TestCase {
333
334 private VariableData _vd;
335 private VariableData _vd2;
336
337 private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
338 private ModifiersAndVisibility
339 _publicMav2 = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
340 private ModifiersAndVisibility
341 _protectedMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
342 public VariableDataTest() { this(""); }
343 public VariableDataTest(String name) { super(name); }
344
345 public void testEquals() {
346 _vd = new VariableData("v", _publicMav, SymbolData.INT_TYPE, true, null);
347
348 //check variables that are equal;
349 _vd2 = new VariableData("v", _publicMav2, SymbolData.INT_TYPE, true, null);
350 assertTrue("Equals should return true if two VariableDatas are equal", _vd.equals(_vd2));
351 assertTrue("Equals should return true in opposite direction as well", _vd2.equals(_vd));
352
353 //comparison to null
354 _vd2 = null;
355 assertFalse("Equals should return false if VariableData is compared to null",_vd.equals(null));
356
357 //different names
358 _vd2 = new VariableData("q", _publicMav, SymbolData.INT_TYPE, true, null);
359 assertFalse("Equals should return false if variable names are different", _vd.equals(_vd2));
360
361 //different MAV
362 _vd2 = new VariableData("v", _protectedMav, SymbolData.INT_TYPE, true, null);
363 assertFalse("Equals should return false if variable modifiers are different", _vd.equals(_vd2));
364
365 //different types
366 _vd2 = new VariableData("v", _publicMav, SymbolData.BOOLEAN_TYPE, true, null);
367 assertFalse("Equals should return false if variable types are different", _vd.equals(_vd2));
368 }
369 }
370 }