001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.reflect.eval;
019:
020: import java.lang.reflect.Method;
021: import java.util.Map;
022: import java.util.TreeMap;
023:
024: import spoon.reflect.declaration.CtField;
025: import spoon.reflect.declaration.CtSimpleType;
026: import spoon.reflect.declaration.ModifierKind;
027: import spoon.reflect.reference.CtFieldReference;
028: import spoon.reflect.reference.CtTypeReference;
029: import spoon.reflect.reference.CtVariableReference;
030: import spoon.support.util.RtHelper;
031:
032: /**
033: * This class represents symbolic values that can be used by
034: * {@link spoon.reflect.eval.SymbolicEvaluator}.
035: */
036: public class SymbolicInstance<T> {
037:
038: /**
039: * The true literal symbolic instance.
040: */
041: public final static SymbolicInstance<Boolean> TRUE = new SymbolicInstance<Boolean>(
042: "true");
043: /**
044: * The false literal symbolic instance.
045: */
046: public final static SymbolicInstance<Boolean> FALSE = new SymbolicInstance<Boolean>(
047: "false");
048: /**
049: * The null literal symbolic instance.
050: */
051: public final static SymbolicInstance<?> NULL = new SymbolicInstance<Object>(
052: "null");
053: /**
054: * The 0 literal symbolic instance.
055: */
056: public final static SymbolicInstance<?> ZERO = new SymbolicInstance<Object>(
057: "0");
058: /**
059: * The strictly positive domain symbolic instance.
060: */
061: public final static SymbolicInstance<?> POS_DOMAIN = new SymbolicInstance<Object>(
062: ">0");
063: /**
064: * The positive domain symbolic instance.
065: */
066: public final static SymbolicInstance<?> ZEROPOS_DOMAIN = new SymbolicInstance<Object>(
067: ">=0");
068: /**
069: * The strictly negative domain symbolic instance.
070: */
071: public final static SymbolicInstance<?> NEG_DOMAIN = new SymbolicInstance<Object>(
072: "<0");
073: /**
074: * The positive domain symbolic instance.
075: */
076: public final static SymbolicInstance<?> ZERONEG_DOMAIN = new SymbolicInstance<Object>(
077: "<=0");
078:
079: /**
080: * Creates a literal symbolic instance.
081: */
082: public SymbolicInstance(String literal) {
083: this .literal = literal;
084: }
085:
086: String literal = null;
087:
088: static long id = 0;
089:
090: /**
091: * Gets the next id to be attributed to the created instance.
092: */
093: private static long getNextId() {
094: return id++;
095: }
096:
097: /**
098: * Resets the id counter.
099: */
100: public static void resetIds() {
101: id = 0;
102: }
103:
104: private String symbolName = null;
105:
106: /**
107: * Helper method to get the symbol's unique Id from its type and its name.
108: *
109: * @param concreteType
110: * the type
111: * @param name
112: * the name (can be null)
113: * @return a unique Id or the type id if name is null
114: */
115: public static String getSymbolId(CtTypeReference<?> concreteType,
116: String name) {
117: CtTypeReference<?> t = concreteType;
118: if (name != null) {
119: return t.getQualifiedName() + "$" + name;
120: }
121: return t.getQualifiedName();
122: }
123:
124: /**
125: * Gets the unique Id of this abstract instance.
126: */
127: public String getId() {
128: if (literal != null) {
129: return literal;
130: }
131: return getSymbolId(concreteType, symbolName);
132: }
133:
134: /**
135: * Tests the equality.
136: */
137: @Override
138: public boolean equals(Object obj) {
139: SymbolicInstance<?> i = (SymbolicInstance<?>) obj;
140:
141: boolean b = false;
142: if ((concreteType != null) && (i != null)) {
143: b = concreteType.equals(i.concreteType)
144: && fields.equals(i.fields)
145: && (isExternal == i.isExternal);
146: } else if ((concreteType == null) && (i != null)) {
147: b = (i.concreteType == null)
148: && ((literal == null) ? false : literal
149: .equals(i.literal));
150: }
151: return b;
152: }
153:
154: /**
155: * Tests the equality by reference.
156: */
157: public boolean equalsRef(Object obj) {
158: if (this == obj) {
159: return true;
160: }
161: SymbolicInstance<?> i = (SymbolicInstance<?>) obj;
162: boolean b = getId().equals(i.getId());
163: return b;
164: }
165:
166: /**
167: * Creates a new abstract instance (logical value).
168: *
169: * @param evaluator
170: * the evaluator
171: * @param concreteType
172: * the type of the instance
173: * @param isType
174: * tells if it is a type instance or a regular instance
175: */
176: public SymbolicInstance(SymbolicEvaluator evaluator,
177: CtTypeReference<T> concreteType, boolean isType) {
178: this .concreteType = concreteType;
179: CtSimpleType<T> type = concreteType.getDeclaration();
180: // TODO: check that enums are working properly
181: if (!concreteType.isPrimitive()
182: && (type != null)
183: && !Enum.class.isAssignableFrom(concreteType
184: .getActualClass())) {
185: for (CtFieldReference<?> fr : concreteType.getAllFields()) {
186: CtField<?> f = fr.getDeclaration();
187: // skip external fields
188: if (f == null) {
189: continue;
190: }
191:
192: CtTypeReference<?> fieldType = f.getType();
193:
194: // TODO: check this
195: if (fieldType == null) {
196: fields.put(fr, null);
197: continue;
198: }
199:
200: if (isType && f.hasModifier(ModifierKind.STATIC)) {
201: SymbolicInstance<?> r = evaluator.evaluate(f
202: .getDefaultExpression());
203: fields.put(fr, r == null ? null : r.getId());
204: }
205: if (!isType && !f.hasModifier(ModifierKind.STATIC)) {
206: SymbolicInstance<?> r = evaluator.evaluate(f
207: .getDefaultExpression());
208: fields.put(fr, r == null ? null : r.getId());
209: }
210: }
211: } else {
212: isExternal = true;
213: if (!isType) {
214: for (CtTypeReference<?> t : evaluator
215: .getStatefullExternals()) {
216: if (t.isAssignableFrom(concreteType)) {
217: for (Method m : RtHelper
218: .getAllMethods(concreteType
219: .getActualClass())) {
220: if (m.getName().startsWith("get")
221: && (m.getParameterTypes().length == 0)) {
222: CtFieldReference<?> f = concreteType
223: .getFactory()
224: .Field()
225: .createReference(
226: concreteType,
227: concreteType
228: .getFactory()
229: .Type()
230: .createReference(
231: m
232: .getReturnType()),
233: m.getName()
234: .substring(3));
235: fields.put(f, null);
236: }
237: }
238: }
239: }
240: }
241: }
242: // evaluator.getHeap().get(
243: // evaluator,
244: // concreteType.getFactory().Type()
245: // .createReference(
246: // m.getReturnType()));
247:
248: if (isType) {
249: this .symbolName = "type";
250: } else {
251: this .symbolName = "" + getNextId();
252: }
253: }
254:
255: /**
256: * Tells if this logical value is stateful or not.
257: */
258: public boolean isStateful() {
259: return !fields.isEmpty();
260: }
261:
262: private boolean isExternal = false;
263:
264: private CtTypeReference<T> concreteType;
265:
266: private Map<CtVariableReference<?>, String> fields = new TreeMap<CtVariableReference<?>, String>();
267:
268: // private Map<String, AbstractInstance> properties;
269:
270: /**
271: * Gets the type of the abstract instance.
272: */
273: public CtTypeReference<T> getConcreteType() {
274: return concreteType;
275: }
276:
277: /**
278: * Gets the value of a field belonging to this instance, as an abstract
279: * instance id.
280: *
281: * @return null if non-existing field
282: */
283: public String getFieldValue(CtVariableReference<?> fref) {
284: return fields.get(fref);
285: }
286:
287: /**
288: * Gets the value of a field belonging to this instance and identified by
289: * its name, as an abstract instance id.
290: *
291: * @return null if non-existing field
292: */
293: public String getFieldValue(String fname) {
294: for (CtVariableReference<?> v : fields.keySet()) {
295: if (v.getSimpleName().equals(fname)) {
296: return fields.get(v);
297: }
298: }
299: return null;
300: }
301:
302: // /**
303: // * Sets the value of an assumed property belonging to this instance.
304: // */
305: // public void setPropertyValue(String propertyName, AbstractInstance value)
306: // {
307: // if (value == null)
308: // return;
309: // if (properties == null)
310: // properties = new HashMap<String, AbstractInstance>();
311: // properties.put(propertyName, value);
312: // }
313: //
314: // /**
315: // * Gets the value of an assumed property belonging to this instance.
316: // */
317: // public AbstractInstance getPropertyValue(String propertyName) {
318: // if (properties == null)
319: // return null;
320: // return properties.get(propertyName);
321: // }
322:
323: /**
324: * Sets the value of a field belonging to this instance, and stores the
325: * instance on the heap.
326: */
327: public void setFieldValue(SymbolicHeap heap,
328: CtVariableReference<?> fref, SymbolicInstance<?> value) {
329: if (fields.containsKey(fref) || isExternal()) {
330: fields.put(fref, value.getId());
331: heap.store(value);
332: } else {
333: // TODO: JJ - recheck this
334: throw new RuntimeException("unknown field '" + fref
335: + "' for target " + this );
336: }
337: }
338:
339: /**
340: * Tells if this instance is a wrapper for an instance external from the
341: * evaluator (regular Java object).
342: */
343: public boolean isExternal() {
344: return isExternal;
345: }
346:
347: /**
348: * A string representation.
349: */
350: @Override
351: public String toString() {
352: if (literal != null) {
353: return "#" + literal + "#";
354: }
355: return "#" + getId() + fields + "#";
356: }
357:
358: /**
359: * Gets a copy of this instance (if the instance is stateless, returns
360: * this).
361: */
362: public SymbolicInstance<T> getClone() {
363: if (!isStateful()) {
364: return this ;
365: }
366: return new SymbolicInstance<T>(this );
367: }
368:
369: /**
370: * Creates a copy of the given instance.
371: */
372: public SymbolicInstance(SymbolicInstance<T> i) {
373: concreteType = i.concreteType;
374: isExternal = i.isExternal;
375: symbolName = i.symbolName;
376: fields.putAll(i.fields);
377: }
378:
379: /**
380: * Gets the name of this symbolic instance.
381: */
382: public String getSymbolName() {
383: return symbolName;
384: }
385:
386: /**
387: * Gets the fields for this instance.
388: */
389: public Map<CtVariableReference<?>, String> getFields() {
390: return fields;
391: }
392: }
|