001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003,2004 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 org.apache.bcel.generic.InstructionHandle;
023:
024: import edu.umd.cs.findbugs.annotations.NonNull;
025:
026: /**
027: * A class representing a location in the CFG for a method.
028: * Essentially, it represents a static instruction, <em>with the important caveat</em>
029: * that CFGs have inlined JSR subroutines, meaning that a single InstructionHandle
030: * in a CFG may represent several static locations. To this end, a Location
031: * is comprised of both an InstructionHandle and the BasicBlock that
032: * contains it.
033: * <p/>
034: * <p> Location objects may be compared with each other using the equals() method,
035: * and may be used as keys in tree and hash maps and sets.
036: * Note that <em>it is only valid to compare Locations produced from the same CFG</em>.
037: *
038: * @author David Hovemeyer
039: * @see CFG
040: */
041: public class Location implements Comparable<Location> {
042: private final InstructionHandle handle;
043: private final BasicBlock basicBlock;
044:
045: /**
046: * Constructor.
047: *
048: * @param handle the instruction
049: * @param basicBlock the basic block containing the instruction
050: */
051: public Location(@NonNull
052: InstructionHandle handle, @NonNull
053: BasicBlock basicBlock) {
054: if (handle == null)
055: throw new NullPointerException("handle cannot be null");
056: if (basicBlock == null)
057: throw new NullPointerException("basicBlock cannot be null");
058: this .handle = handle;
059: this .basicBlock = basicBlock;
060: }
061:
062: public static Location getFirstLocation(@NonNull
063: BasicBlock basicBlock) {
064: InstructionHandle location = basicBlock.getFirstInstruction();
065: if (location == null)
066: return null;
067: return new Location(location, basicBlock);
068: }
069:
070: public static Location getLastLocation(@NonNull
071: BasicBlock basicBlock) {
072: InstructionHandle lastInstruction = basicBlock
073: .getLastInstruction();
074: /*
075: if (lastInstruction == null)
076: lastInstruction = basicBlock.getExceptionThrower();
077: if (lastInstruction == null)
078: lastInstruction = basicBlock.getFirstInstruction();
079: */
080: if (lastInstruction == null)
081: return null;
082: return new Location(lastInstruction, basicBlock);
083: }
084:
085: /**
086: * Get the instruction handle.
087: */
088: public InstructionHandle getHandle() {
089: return handle;
090: }
091:
092: /**
093: * Get the basic block.
094: */
095: public BasicBlock getBasicBlock() {
096: return basicBlock;
097: }
098:
099: /**
100: * Return whether or not the Location is positioned at the
101: * first instruction in the basic block.
102: */
103: public boolean isFirstInstructionInBasicBlock() {
104: return !basicBlock.isEmpty()
105: && handle == basicBlock.getFirstInstruction();
106: }
107:
108: /**
109: * Return whether or not the Location is positioned at the
110: * last instruction in the basic block.
111: */
112: public boolean isLastInstructionInBasicBlock() {
113: return !basicBlock.isEmpty()
114: && handle == basicBlock.getLastInstruction();
115: }
116:
117: public int compareTo(Location other) {
118: int cmp = basicBlock.getLabel() - other.basicBlock.getLabel();
119: if (false && cmp != 0)
120: return cmp;
121:
122: int pos = handle.getPosition() - other.handle.getPosition();
123: if (pos != 0)
124: return pos;
125: return cmp;
126: }
127:
128: @Override
129: public int hashCode() {
130: return System.identityHashCode(basicBlock)
131: + handle.getPosition();
132: }
133:
134: @Override
135: public boolean equals(Object o) {
136: if (!(o instanceof Location))
137: return false;
138: Location other = (Location) o;
139: return basicBlock == other.basicBlock && handle == other.handle;
140: }
141:
142: @Override
143: public String toString() {
144: return handle.toString() + " in basic block "
145: + basicBlock.getLabel();
146: }
147:
148: /**
149: * @return a compact string of the form "bb:xx", where "bb" is the
150: * basic block number and "xx" is the bytecode offset
151: */
152: public String toCompactString() {
153: return basicBlock.getLabel() + ":" + handle.getPosition();
154: }
155: }
156:
157: //vim:ts=4
|