001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003-2005 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;
021:
022: import java.util.Locale;
023: import java.util.Set;
024:
025: import org.apache.bcel.generic.InstructionHandle;
026:
027: import edu.umd.cs.findbugs.graph.AbstractEdge;
028:
029: /**
030: * An edge of a control flow graph.
031: *
032: * @author David Hovemeyer
033: * @see BasicBlock
034: * @see CFG
035: */
036: public class Edge extends AbstractEdge<Edge, BasicBlock> implements
037: EdgeTypes, Debug {
038:
039: /* ----------------------------------------------------------------------
040: * Fields
041: * ---------------------------------------------------------------------- */
042:
043: private int type;
044: private int flags;
045:
046: /* ----------------------------------------------------------------------
047: * Public methods
048: * ---------------------------------------------------------------------- */
049:
050: /**
051: * Constructor.
052: *
053: * @param source source basic block
054: * @param dest destination basic block
055: */
056: public Edge(BasicBlock source, BasicBlock dest) {
057: super (source, dest);
058: }
059:
060: public int getId() {
061: return getLabel();
062: }
063:
064: /**
065: * Get the type of edge.
066: */
067: public int getType() {
068: return type;
069: }
070:
071: /**
072: * Set the type of edge.
073: */
074: public void setType(int type) {
075: this .type = type;
076: }
077:
078: /**
079: * Get the edge flags.
080: */
081: public int getFlags() {
082: return flags;
083: }
084:
085: /**
086: * Set the edge flags.
087: */
088: public void setFlags(int flags) {
089: this .flags = flags;
090: }
091:
092: /**
093: * Return if given edge flag is set.
094: *
095: * @param flag the edge flag
096: * @return true if the flag is set, false otherwise
097: */
098: public boolean isFlagSet(int flag) {
099: return (this .flags & flag) != 0;
100: }
101:
102: /**
103: * Is the edge an exception edge?
104: */
105: public boolean isExceptionEdge() {
106: return type == HANDLED_EXCEPTION_EDGE
107: || type == UNHANDLED_EXCEPTION_EDGE;
108: }
109:
110: @Override
111: public boolean equals(Object o) {
112: if (o == null || this .getClass() != o.getClass())
113: return false;
114: Edge other = (Edge) o;
115: return this .getSource() == other.getSource()
116: && this .getTarget() == other.getTarget()
117: && this .getType() == other.getType();
118: }
119:
120: @Override
121: public int hashCode() {
122: return 2003 * getSource().getLabel() + getTarget().getLabel();
123: }
124:
125: /**
126: * Compare with other edge.
127: */
128: @Override
129: public int compareTo(Edge other) {
130: int cmp = super .compareTo(other);
131: if (cmp != 0)
132: return cmp;
133: return type - other.type;
134: }
135:
136: @Override
137: public String toString() {
138: return formatAsString(false);
139: }
140:
141: public boolean isBackwardInBytecode() {
142: BasicBlock source = getSource();
143: BasicBlock target = getTarget();
144:
145: InstructionHandle sourceInstruction = source
146: .getLastInstruction();
147: InstructionHandle targetInstruction = target
148: .getFirstInstruction();
149:
150: if (targetInstruction == null || sourceInstruction == null)
151: return false;
152: return targetInstruction.getPosition() < sourceInstruction
153: .getPosition();
154:
155: }
156:
157: public boolean sourceIsTopOfLoop(Set<Integer> positions) {
158: BasicBlock source = getSource();
159:
160: InstructionHandle sourceInstruction = source
161: .getLastInstruction();
162:
163: if (sourceInstruction == null)
164: return false;
165: return positions.contains(sourceInstruction.getPosition());
166:
167: }
168:
169: /**
170: * Return a string representation of the edge.
171: */
172: public String formatAsString(boolean reverse) {
173: BasicBlock source = getSource();
174: BasicBlock target = getTarget();
175:
176: StringBuffer buf = new StringBuffer();
177: buf.append(reverse ? "REVERSE_EDGE(" : "EDGE(");
178: buf.append(getLabel());
179: buf.append(") type ");
180: buf.append(edgeTypeToString(type));
181: buf.append(" from block ");
182: buf.append(reverse ? target.getLabel() : source.getLabel());
183: buf.append(" to block ");
184: buf.append(reverse ? source.getLabel() : target.getLabel());
185: InstructionHandle sourceInstruction = source
186: .getLastInstruction();
187: InstructionHandle targetInstruction = target
188: .getFirstInstruction();
189: String exInfo = " -> ";
190: if (targetInstruction == null && target.isExceptionThrower()) {
191: targetInstruction = target.getExceptionThrower();
192: exInfo = " => ";
193: }
194: if (sourceInstruction != null && targetInstruction != null) {
195: buf.append(" [bytecode ");
196: buf.append(sourceInstruction.getPosition());
197: buf.append(exInfo);
198: buf.append(targetInstruction.getPosition());
199: buf.append(']');
200: } else if (source.isExceptionThrower()) {
201: if (type == FALL_THROUGH_EDGE)
202: buf.append(" [successful check]");
203: else {
204: buf.append(" [failed check for ");
205: buf.append(source.getExceptionThrower().getPosition());
206: if (targetInstruction != null) {
207: buf.append(" to ");
208: buf.append(targetInstruction.getPosition());
209: }
210: buf.append(']');
211: }
212: }
213: return buf.toString();
214: }
215:
216: /**
217: * Get string representing given edge type.
218: */
219: public static String edgeTypeToString(int edgeType) {
220: switch (edgeType) {
221: case FALL_THROUGH_EDGE:
222: return "FALL_THROUGH";
223: case IFCMP_EDGE:
224: return "IFCMP";
225: case SWITCH_EDGE:
226: return "SWITCH";
227: case SWITCH_DEFAULT_EDGE:
228: return "SWITCH_DEFAULT";
229: case JSR_EDGE:
230: return "JSR";
231: case RET_EDGE:
232: return "RET";
233: case GOTO_EDGE:
234: return "GOTO";
235: case RETURN_EDGE:
236: return "RETURN";
237: case UNHANDLED_EXCEPTION_EDGE:
238: return "UNHANDLED_EXCEPTION";
239: case HANDLED_EXCEPTION_EDGE:
240: return "HANDLED_EXCEPTION";
241: case START_EDGE:
242: return "START";
243: case BACKEDGE_TARGET_EDGE:
244: return "BACKEDGE_TARGET_EDGE";
245: case BACKEDGE_SOURCE_EDGE:
246: return "BACKEDGE_SOURCE_EDGE";
247: case EXIT_EDGE:
248: return "EXIT_EDGE";
249: }
250: throw new IllegalStateException("unknown edge type: "
251: + edgeType);
252: }
253:
254: /**
255: * Get numeric edge type from string representation.
256: */
257: public static int stringToEdgeType(String s) {
258: s = s.toUpperCase(Locale.ENGLISH);
259:
260: if (s.equals("FALL_THROUGH"))
261: return FALL_THROUGH_EDGE;
262: else if (s.equals("IFCMP"))
263: return IFCMP_EDGE;
264: else if (s.equals("SWITCH"))
265: return SWITCH_EDGE;
266: else if (s.equals("SWITCH_DEFAULT"))
267: return SWITCH_DEFAULT_EDGE;
268: else if (s.equals("JSR"))
269: return JSR_EDGE;
270: else if (s.equals("RET"))
271: return RET_EDGE;
272: else if (s.equals("GOTO"))
273: return GOTO_EDGE;
274: else if (s.equals("RETURN"))
275: return RETURN_EDGE;
276: else if (s.equals("UNHANDLED_EXCEPTION"))
277: return UNHANDLED_EXCEPTION_EDGE;
278: else if (s.equals("HANDLED_EXCEPTION"))
279: return HANDLED_EXCEPTION_EDGE;
280: else if (s.equals("START"))
281: return START_EDGE;
282: else if (s.equals("BACKEDGE_TARGET_EDGE"))
283: return BACKEDGE_TARGET_EDGE;
284: else if (s.equals("BACKEDGE_SOURCE_EDGE"))
285: return BACKEDGE_SOURCE_EDGE;
286: else if (s.equals("EXIT_EDGE"))
287: return EXIT_EDGE;
288: else
289: throw new IllegalArgumentException("Unknown edge type: "
290: + s);
291: }
292: }
293:
294: // vim:ts=4
|