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.bcp;
021:
022: import org.apache.bcel.generic.InstructionHandle;
023:
024: import edu.umd.cs.findbugs.ba.BasicBlock;
025:
026: /**
027: * PatternElementMatch represents matching a PatternElement against
028: * a single instruction. The "prev" field points to the previous
029: * PatternElementMatch. By building up sequences of PatternElementMatch objects
030: * in this way, we can implement nondeterministic matching without
031: * having to copy anything.
032: */
033: public class PatternElementMatch {
034: private final PatternElement patternElement;
035: private final InstructionHandle matchedInstruction;
036: private final BasicBlock basicBlock;
037: private final int matchCount;
038: private final PatternElementMatch prev;
039:
040: /**
041: * Constructor.
042: *
043: * @param patternElement the PatternElement being matched
044: * @param matchedInstruction the instruction which matched the PatternElement
045: * @param basicBlock the basic block containing the matched instruction
046: * @param matchCount the index (starting at zero) of the instructions
047: * matching the PatternElement; multiple instructions can match the
048: * same PatternElement
049: * @param prev the previous PatternElementMatch
050: */
051: public PatternElementMatch(PatternElement patternElement,
052: InstructionHandle matchedInstruction,
053: BasicBlock basicBlock, int matchCount,
054: PatternElementMatch prev) {
055: this .patternElement = patternElement;
056: this .matchedInstruction = matchedInstruction;
057: this .basicBlock = basicBlock;
058: this .matchCount = matchCount;
059: this .prev = prev;
060: }
061:
062: /**
063: * Get the PatternElement.
064: */
065: public PatternElement getPatternElement() {
066: return patternElement;
067: }
068:
069: /**
070: * Get the matched instruction.
071: */
072: public InstructionHandle getMatchedInstructionInstructionHandle() {
073: return matchedInstruction;
074: }
075:
076: /**
077: * Get the basic block containing the matched instruction.
078: */
079: public BasicBlock getBasicBlock() {
080: return basicBlock;
081: }
082:
083: /*
084: * Get the index of this instruction in terms of how many instructions
085: * have matched this PatternElement. (0 for the first instruction to
086: * match the PatternElement, etc.)
087: */
088: public int getMatchCount() {
089: return matchCount;
090: }
091:
092: /**
093: * Get the previous PatternMatchElement.
094: */
095: public PatternElementMatch getPrev() {
096: return prev;
097: }
098:
099: /**
100: * Get the <em>first</em> instruction matched by the PatternElement with given label.
101: */
102: public InstructionHandle getLabeledInstruction(String label) {
103: PatternElementMatch first = getFirstLabeledMatch(label);
104: return first != null ? first
105: .getMatchedInstructionInstructionHandle() : null;
106: }
107:
108: /**
109: * Get <em>first</em> match element with given label,
110: * if any.
111: */
112: public PatternElementMatch getFirstLabeledMatch(String label) {
113: PatternElementMatch cur = this , result = null;
114: while (cur != null) {
115: String elementLabel = cur.patternElement.getLabel();
116: if (elementLabel != null && elementLabel.equals(label))
117: result = cur;
118: cur = cur.prev;
119: }
120: return result;
121: }
122:
123: /**
124: * Get <em>last</em> match element with given label,
125: * if any.
126: */
127: public PatternElementMatch getLastLabeledMatch(String label) {
128: PatternElementMatch cur = this ;
129: while (cur != null) {
130: String elementLabel = cur.patternElement.getLabel();
131: if (elementLabel != null && elementLabel.equals(label))
132: return cur;
133: cur = cur.prev;
134: }
135: return null;
136: }
137:
138: /**
139: * Return whether or not the most recently matched instruction
140: * allows trailing edges.
141: */
142: public boolean allowTrailingEdges() {
143: return patternElement.allowTrailingEdges();
144: }
145:
146: @Override
147: public String toString() {
148: StringBuffer buf = new StringBuffer();
149: PatternElementMatch cur = this ;
150: buf.append(cur.patternElement.toString());
151: buf.append(", ");
152: buf.append(cur.matchedInstruction.toString());
153: buf.append(", ");
154: buf.append(cur.matchCount);
155: return buf.toString();
156: }
157:
158: @Override
159: public int hashCode() {
160: // Do the simplest thing possible that works
161: throw new UnsupportedOperationException();
162: }
163:
164: @Override
165: public boolean equals(Object o) {
166: if (!(o instanceof PatternElementMatch))
167: return false;
168: PatternElementMatch lhs = this ;
169: PatternElementMatch rhs = (PatternElementMatch) o;
170:
171: while (lhs != null && rhs != null) {
172: if (lhs.patternElement != rhs.patternElement
173: || lhs.matchedInstruction != rhs.matchedInstruction
174: || lhs.matchCount != rhs.matchCount)
175: return false;
176:
177: lhs = lhs.prev;
178: rhs = rhs.prev;
179: }
180:
181: return lhs == rhs;
182: }
183: }
184:
185: // vim:ts=4
|