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.ConstantPoolGen;
023: import org.apache.bcel.generic.InstructionHandle;
024:
025: import edu.umd.cs.findbugs.SystemProperties;
026: import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
027: import edu.umd.cs.findbugs.ba.Edge;
028: import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
029:
030: /**
031: * A PatternElement is an element of a ByteCodePattern.
032: * It potentially matches some number of bytecode instructions.
033: */
034: public abstract class PatternElement {
035: private static final boolean DEBUG = SystemProperties
036: .getBoolean("bcp.debug");
037:
038: private PatternElement next;
039: private String label;
040: private String dominatedBy;
041: private int index;
042: private boolean allowTrailingEdges = true;
043:
044: /**
045: * Get the next PatternElement.
046: */
047: public PatternElement getNext() {
048: return next;
049: }
050:
051: /**
052: * Set the next PatternElement.
053: */
054: public void setNext(PatternElement patternElement) {
055: this .next = patternElement;
056: }
057:
058: /**
059: * Set a label for this PatternElement.
060: *
061: * @param label the label
062: * @return this object
063: */
064: public PatternElement label(String label) {
065: this .label = label;
066: return this ;
067: }
068:
069: /**
070: * Get the label of this PatternElement.
071: *
072: * @return the label, or null if the PatternElement is not labeled
073: */
074: public String getLabel() {
075: return label;
076: }
077:
078: /**
079: * Set the label of another pattern element whose first
080: * matched instruction must dominate the instruction(s) matched
081: * by this element.
082: */
083: public PatternElement dominatedBy(String dominatedBy) {
084: this .dominatedBy = dominatedBy;
085: return this ;
086: }
087:
088: /**
089: * Get the label of the pattern element whose first
090: * matched instruction must dominate the instruction(s) matched
091: * by this element.
092: */
093: public String getDominatedBy() {
094: return dominatedBy;
095: }
096:
097: /**
098: * Set the index. This is just for debugging.
099: */
100: public void setIndex(int index) {
101: this .index = index;
102: }
103:
104: /**
105: * Set whether or not this PatternElement allows trailing edges to be matched.
106: * By default, trailing edges may be matched. When this value is set
107: * to false, it ensures that the successor instruction must be in the
108: * same basic block.
109: *
110: * @param allowTrailingEdges true if trailing edges may be matched,
111: * false if trailing edges will never be matched
112: */
113: public PatternElement setAllowTrailingEdges(
114: boolean allowTrailingEdges) {
115: this .allowTrailingEdges = allowTrailingEdges;
116: return this ;
117: }
118:
119: /**
120: * Return whether or not this PatternElement may match trailing edges.
121: */
122: public boolean allowTrailingEdges() {
123: return allowTrailingEdges;
124: }
125:
126: /**
127: * Look up a variable definition in given BindingSet.
128: *
129: * @param varName the name of the variable
130: * @param bindingSet the BindingSet to look in
131: * @return the Variable, or null if no Variable is bound to the name
132: */
133: public static Variable lookup(String varName, BindingSet bindingSet) {
134: if (bindingSet == null)
135: return null;
136: Binding binding = bindingSet.lookup(varName);
137: return (binding != null) ? binding.getVariable() : null;
138: }
139:
140: /**
141: * Return whether or not this element matches the given
142: * instruction with the given Bindings in effect.
143: *
144: * @param handle the instruction
145: * @param cpg the ConstantPoolGen from the method
146: * @param before the ValueNumberFrame representing values in the Java stack frame
147: * just before the execution of the instruction
148: * @param after the ValueNumberFrame representing values in the Java stack frame
149: * just after the execution of the instruction
150: * @param bindingSet the set of Bindings
151: * @return if the match is successful, returns a MatchResult with the PatternElement
152: * and BindingSet; if the match is not successful, returns null
153: */
154: public abstract MatchResult match(InstructionHandle handle,
155: ConstantPoolGen cpg, ValueNumberFrame before,
156: ValueNumberFrame after, BindingSet bindingSet)
157: throws DataflowAnalysisException;
158:
159: /**
160: * Return whether or not it is acceptable to take the given branch.
161: *
162: * @param edge the Edge representing the branch
163: * @param source the source instruction of the branch
164: * @return true if the Edge is acceptable, false if not
165: */
166: public abstract boolean acceptBranch(Edge edge,
167: InstructionHandle source);
168:
169: /**
170: * Return the minimum number of instructions this PatternElement
171: * must match in the ByteCodePattern.
172: */
173: public abstract int minOccur();
174:
175: /**
176: * Return the maximum number of instructions this PatternElement
177: * must match in the ByteCodePattern.
178: */
179: public abstract int maxOccur();
180:
181: /**
182: * Add a variable definition to the given BindingSet, or if
183: * there is an existing definition, make sure it is consistent with
184: * the new definition.
185: *
186: * @param varName the name of the variable
187: * @param variable the Variable which should be added or checked for consistency
188: * @param bindingSet the existing set of bindings
189: * @return the updated BindingSet (if the variable is consistent with the
190: * previous bindings), or null if the new variable is inconsistent with
191: * the previous bindings
192: */
193: protected static BindingSet addOrCheckDefinition(String varName,
194: Variable variable, BindingSet bindingSet) {
195: Variable existingVariable = lookup(varName, bindingSet);
196: if (existingVariable == null) {
197: bindingSet = new BindingSet(new Binding(varName, variable),
198: bindingSet);
199: } else {
200: if (!existingVariable.sameAs(variable)) {
201: if (DEBUG)
202: System.out.println("\tConflicting variable "
203: + varName + ": " + variable + " != "
204: + existingVariable);
205: return null;
206: }
207: }
208:
209: return bindingSet;
210: }
211:
212: @Override
213: public String toString() {
214: StringBuffer buf = new StringBuffer();
215: String className = this .getClass().getName();
216: buf.append(className.substring(className.lastIndexOf('.') + 1));
217: buf.append('(');
218: buf.append(index);
219: buf.append(')');
220: return buf.toString();
221: }
222: }
223:
224: // vim:ts=4
|