001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2003-2007 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba.jsr305;
021:
022: import java.util.Collection;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Map;
026: import java.util.Set;
027: import java.util.TreeSet;
028:
029: import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
030: import edu.umd.cs.findbugs.ba.vna.ValueNumber;
031:
032: /**
033: * Set of ValueNumbers and their corresponding FlowValues.
034: *
035: * @author David Hovemeyer
036: */
037: public class TypeQualifierValueSet {
038: // States
039: enum State {
040: VALID, TOP, BOTTOM
041: };
042:
043: private static final FlowValue DEFAULT_FLOW_VALUE = FlowValue.UNKNOWN;
044:
045: private Map<ValueNumber, FlowValue> valueMap;
046: private Map<ValueNumber, Set<SourceSinkInfo>> whereAlways;
047: private Map<ValueNumber, Set<SourceSinkInfo>> whereNever;
048: private State state = State.VALID;
049:
050: public TypeQualifierValueSet() {
051: this .valueMap = new HashMap<ValueNumber, FlowValue>();
052: this .whereAlways = new HashMap<ValueNumber, Set<SourceSinkInfo>>();
053: this .whereNever = new HashMap<ValueNumber, Set<SourceSinkInfo>>();
054: this .state = State.TOP;
055: }
056:
057: public void modelSourceSink(SourceSinkInfo sourceSinkInfo) {
058: assert sourceSinkInfo != null;
059: ValueNumber vn = sourceSinkInfo.getValueNumber();
060: FlowValue flowValue = FlowValue
061: .flowValueFromWhen(sourceSinkInfo.getWhen());
062:
063: setValue(vn, flowValue);
064:
065: if (flowValue.isYes()) {
066: addSourceSinkInfo(whereAlways, vn, sourceSinkInfo);
067: }
068:
069: if (flowValue.isNo()) {
070: addSourceSinkInfo(whereNever, vn, sourceSinkInfo);
071: }
072: }
073:
074: private void setValue(ValueNumber vn, FlowValue flowValue) {
075: valueMap.put(vn, flowValue);
076: }
077:
078: private static void addSourceSinkInfo(
079: Map<ValueNumber, Set<SourceSinkInfo>> sourceSinkInfoSetMap,
080: ValueNumber vn, SourceSinkInfo sourceSinkInfo) {
081: Set<SourceSinkInfo> sourceSinkInfoSet = getOrCreateSourceSinkInfoSet(
082: sourceSinkInfoSetMap, vn);
083: sourceSinkInfoSet.add(sourceSinkInfo);
084: }
085:
086: public void pruneValue(ValueNumber vn) {
087: assert isValid();
088: valueMap.remove(vn);
089: whereAlways.remove(vn);
090: whereNever.remove(vn);
091: }
092:
093: public Set<SourceSinkInfo> getWhereAlways(ValueNumber vn) {
094: return getOrCreateSourceSinkInfoSet(whereAlways, vn);
095: }
096:
097: public Set<SourceSinkInfo> getWhereNever(ValueNumber vn) {
098: return getOrCreateSourceSinkInfoSet(whereNever, vn);
099: }
100:
101: private static Set<SourceSinkInfo> getOrCreateSourceSinkInfoSet(
102: Map<ValueNumber, Set<SourceSinkInfo>> sourceSinkInfoSetMap,
103: ValueNumber vn) {
104: Set<SourceSinkInfo> sourceSinkInfoSet = sourceSinkInfoSetMap
105: .get(vn);
106: if (sourceSinkInfoSet == null) {
107: sourceSinkInfoSet = new HashSet<SourceSinkInfo>();
108: sourceSinkInfoSetMap.put(vn, sourceSinkInfoSet);
109: }
110: return sourceSinkInfoSet;
111: }
112:
113: public FlowValue getValue(ValueNumber vn) {
114: FlowValue result = valueMap.get(vn);
115: return result != null ? result : FlowValue.TOP;
116: }
117:
118: public Collection<? extends ValueNumber> getValueNumbers() {
119: return valueMap.keySet();
120: }
121:
122: public boolean isValid() {
123: return state == State.VALID;
124: }
125:
126: public void makeValid() {
127: /*
128: this.state = State.VALID;
129: this.valueMap.clear();
130: this.whereAlways.clear();
131: this.whereNever.clear();
132: */
133: reset(State.VALID);
134: }
135:
136: public void makeSameAs(TypeQualifierValueSet source) {
137: /*
138: this.state = source.state;
139: this.valueMap.clear();
140: */
141: reset(source.state);
142: this .valueMap.putAll(source.valueMap);
143: copySourceSinkInfoSetMap(this .whereAlways, source.whereAlways);
144: copySourceSinkInfoSetMap(this .whereNever, source.whereNever);
145: }
146:
147: private void copySourceSinkInfoSetMap(
148: Map<ValueNumber, Set<SourceSinkInfo>> dest,
149: Map<ValueNumber, Set<SourceSinkInfo>> source) {
150: dest.keySet().retainAll(source.keySet());
151:
152: for (Map.Entry<ValueNumber, Set<SourceSinkInfo>> entry : source
153: .entrySet()) {
154: Set<SourceSinkInfo> locSet = getOrCreateSourceSinkInfoSet(
155: dest, entry.getKey());
156: locSet.clear();
157: locSet.addAll(entry.getValue());
158: }
159: }
160:
161: public boolean isTop() {
162: return state == State.TOP;
163: }
164:
165: public void setTop() {
166: /*
167: this.valueMap.clear();
168: this.state = State.TOP;
169: */
170: reset(State.TOP);
171: }
172:
173: public boolean isBottom() {
174: return state == State.BOTTOM;
175: }
176:
177: public void setBottom() {
178: /*
179: this.valueMap.clear();
180: this.state = State.BOTTOM;
181: */
182: reset(State.BOTTOM);
183: }
184:
185: private void reset(State state) {
186: valueMap.clear();
187: whereAlways.clear();
188: whereNever.clear();
189: this .state = state;
190: }
191:
192: public void propagateAcrossPhiNode(ValueNumber fromVN,
193: ValueNumber toVN) {
194: assert isValid();
195:
196: setValue(toVN, getValue(fromVN));
197:
198: // Propagate source/sink information
199: transferSourceSinkInfoSet(whereAlways, fromVN, toVN);
200: transferSourceSinkInfoSet(whereNever, fromVN, toVN);
201:
202: // Remove all information about the "from" value
203: valueMap.remove(fromVN);
204: whereAlways.remove(fromVN);
205: whereNever.remove(fromVN);
206: }
207:
208: private static void transferSourceSinkInfoSet(
209: Map<ValueNumber, Set<SourceSinkInfo>> sourceSinkInfoSetMap,
210: ValueNumber fromVN, ValueNumber toVN) {
211: Set<SourceSinkInfo> locSet = getOrCreateSourceSinkInfoSet(
212: sourceSinkInfoSetMap, fromVN);
213:
214: for (SourceSinkInfo loc : locSet) {
215: addSourceSinkInfo(sourceSinkInfoSetMap, toVN, loc);
216: }
217: }
218:
219: public void mergeWith(TypeQualifierValueSet fact)
220: throws DataflowAnalysisException {
221: if (!isValid() || !fact.isValid()) {
222: throw new DataflowAnalysisException(
223: "merging an invalid TypeQualifierValueSet");
224: }
225:
226: Set<ValueNumber> interesting = new HashSet<ValueNumber>();
227: interesting.addAll(this .valueMap.keySet());
228: interesting.addAll(fact.valueMap.keySet());
229:
230: for (ValueNumber vn : interesting) {
231: setValue(vn, FlowValue.meet(this .getValue(vn), fact
232: .getValue(vn)));
233: mergeSourceSinkInfoSets(this .whereAlways, fact.whereAlways,
234: vn);
235: mergeSourceSinkInfoSets(this .whereNever, fact.whereNever,
236: vn);
237: }
238: }
239:
240: private void mergeSourceSinkInfoSets(
241: Map<ValueNumber, Set<SourceSinkInfo>> sourceSinkInfoSetMapToUpdate,
242: Map<ValueNumber, Set<SourceSinkInfo>> otherSourceSinkInfoSetMap,
243: ValueNumber vn) {
244: if (!otherSourceSinkInfoSetMap.containsKey(vn)) {
245: return;
246: }
247: Set<SourceSinkInfo> sourceSinkInfoSetToUpdate = getOrCreateSourceSinkInfoSet(
248: sourceSinkInfoSetMapToUpdate, vn);
249: sourceSinkInfoSetToUpdate.addAll(getOrCreateSourceSinkInfoSet(
250: otherSourceSinkInfoSetMap, vn));
251: }
252:
253: /* (non-Javadoc)
254: * @see java.lang.Object#equals(java.lang.Object)
255: */
256: @Override
257: public boolean equals(Object obj) {
258: if (obj == null || obj.getClass() != this .getClass()) {
259: return false;
260: }
261: TypeQualifierValueSet other = (TypeQualifierValueSet) obj;
262: if (this .isValid() && other.isValid()) {
263: return this .valueMap.equals(other.valueMap);
264: } else {
265: return this .state == other.state;
266: }
267: }
268:
269: /* (non-Javadoc)
270: * @see java.lang.Object#hashCode()
271: */
272: @Override
273: public int hashCode() {
274: throw new UnsupportedOperationException();
275: }
276:
277: @Override
278: public String toString() {
279: if (state != State.VALID) {
280: return state.toString();
281: }
282:
283: TreeSet<ValueNumber> interesting = new TreeSet<ValueNumber>();
284: interesting.addAll(valueMap.keySet());
285:
286: StringBuffer buf = new StringBuffer();
287:
288: buf.append("{");
289:
290: for (ValueNumber vn : interesting) {
291: if (buf.length() > 1) {
292: buf.append(", ");
293: }
294: buf.append(valueNumberToString(vn));
295: }
296:
297: buf.append("}");
298:
299: return buf.toString();
300: }
301:
302: public String valueNumberToString(ValueNumber vn) {
303: StringBuffer buf = new StringBuffer();
304:
305: buf.append(vn.getNumber());
306: buf.append("->");
307: buf.append(getValue(vn).toString());
308: buf.append("[");
309: appendSourceSinkInfos(buf, "YES=",
310: getOrCreateSourceSinkInfoSet(whereAlways, vn));
311: buf.append(",");
312: appendSourceSinkInfos(buf, "NO=", getOrCreateSourceSinkInfoSet(
313: whereNever, vn));
314: buf.append("]");
315:
316: return buf.toString();
317: }
318:
319: private static void appendSourceSinkInfos(StringBuffer buf,
320: String key, Set<SourceSinkInfo> sourceSinkInfoSet) {
321: TreeSet<SourceSinkInfo> sortedLocSet = new TreeSet<SourceSinkInfo>();
322: sortedLocSet.addAll(sourceSinkInfoSet);
323: boolean first = true;
324: buf.append(key);
325: buf.append("(");
326: for (SourceSinkInfo loc : sortedLocSet) {
327: if (first) {
328: first = false;
329: } else {
330: buf.append(",");
331: }
332: buf.append(loc.getLocation().toCompactString());
333: }
334: buf.append(")");
335: }
336: }
|