KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > bcp > Invoke


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba.bcp;
21
22 import java.util.regex.Pattern JavaDoc;
23
24 import org.apache.bcel.Constants;
25 import org.apache.bcel.generic.ConstantPoolGen;
26 import org.apache.bcel.generic.Instruction;
27 import org.apache.bcel.generic.InstructionHandle;
28 import org.apache.bcel.generic.InvokeInstruction;
29
30 import edu.umd.cs.findbugs.annotations.Nullable;
31 import edu.umd.cs.findbugs.ba.AnalysisContext;
32 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
33 import edu.umd.cs.findbugs.ba.Edge;
34 import edu.umd.cs.findbugs.ba.Hierarchy;
35 import edu.umd.cs.findbugs.ba.RepositoryLookupFailureCallback;
36 import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
37
38 /**
39  * A PatternElement to match a method invocation.
40  * Currently, we don't allow variables in this element (for arguments
41  * and return value). This would be a good thing to add.
42  * We also don't distinguish between invokevirtual, invokeinterface,
43  * and invokespecial.
44  * <p/>
45  * <p> Invoke objects match by class name, method name, method signature,
46  * and <em>mode</em>.
47  * <p/>
48  * <p> Names and signatures may be matched in several ways:
49  * <ol>
50  * <li> By an exact match. This is the default behavior.
51  * <li> By a regular expression. If the string provided to the Invoke
52  * constructor begins with a "/" character, the rest of the string
53  * is treated as a regular expression.
54  * <li> As a subclass match. This only applies to class name matches.
55  * If the first character of a class name string is "+", then the
56  * rest of the string is treated as the name of a base class.
57  * Any subclass or subinterface of the named type will be accepted.
58  * </ol>
59  * <p/>
60  * <p> The <em>mode</em> specifies what kind of invocations in the Invoke
61  * element matches. It is specified as the bitwise combination of the
62  * following values:
63  * <ol>
64  * <li> <code>INSTANCE</code>, which matches ordinary instance method invocations
65  * <li> <code>STATIC</code>, which matches static method invocations
66  * <li> <code>CONSTRUCTOR</code>, which matches object constructor invocations
67  * </ol>
68  * The special mode <code>ORDINARY_METHOD</code> is equivalent to <code>INSTANCE|STATIC</code>.
69  * The special mode <code>ANY</code> is equivalent to <code>INSTANCE|STATIC|CONSTRUCTOR</code>.
70  *
71  * @author David Hovemeyer
72  * @see PatternElement
73  */

74 public class Invoke extends PatternElement {
75
76     /**
77      * Match ordinary (non-constructor) instance invocations.
78      */

79     public static final int INSTANCE = 1;
80
81     /**
82      * Match static invocations.
83      */

84     public static final int STATIC = 2;
85
86     /**
87      * Match object constructor invocations.
88      */

89     public static final int CONSTRUCTOR = 4;
90
91     /**
92      * Match ordinary methods (everything except constructors).
93      */

94     public static final int ORDINARY_METHOD = INSTANCE | STATIC;
95
96     /**
97      * Match both static and instance invocations.
98      */

99     public static final int ANY = INSTANCE | STATIC | CONSTRUCTOR;
100
101     private interface StringMatcher {
102         public boolean match(String JavaDoc s);
103     }
104
105     private static class ExactStringMatcher implements StringMatcher {
106         private String JavaDoc value;
107
108         public ExactStringMatcher(String JavaDoc value) {
109             this.value = value;
110         }
111
112         public boolean match(String JavaDoc s) {
113             return s.equals(value);
114         }
115     }
116
117     private static class RegexpStringMatcher implements StringMatcher {
118         private Pattern JavaDoc pattern;
119
120         public RegexpStringMatcher(String JavaDoc re) {
121             pattern = Pattern.compile(re);
122         }
123
124         public boolean match(String JavaDoc s) {
125             return pattern.matcher(s).matches();
126         }
127     }
128
129     private static class SubclassMatcher implements StringMatcher {
130         private String JavaDoc className;
131
132         public SubclassMatcher(String JavaDoc className) {
133             this.className = className;
134         }
135
136         public boolean match(String JavaDoc s) {
137             try {
138                 return Hierarchy.isSubtype(s, className);
139             } catch (ClassNotFoundException JavaDoc e) {
140                 AnalysisContext.reportMissingClass(e);
141                 return false;
142             }
143         }
144     }
145
146     private final StringMatcher classNameMatcher;
147     private final StringMatcher methodNameMatcher;
148     private final StringMatcher methodSigMatcher;
149     private final int mode;
150
151     /**
152      * Constructor.
153      *
154      * @param className the class name of the method; may be specified exactly,
155      * as a regexp, or as a subtype match
156      * @param methodName the name of the method; may be specified exactly or as a regexp
157      * @param methodSig the signature of the method; may be specified exactly or as a regexp
158      * @param mode the mode of invocation
159      */

160     public Invoke(String JavaDoc className, String JavaDoc methodName, String JavaDoc methodSig, int mode,
161                   @Nullable RepositoryLookupFailureCallback lookupFailureCallback) {
162         this.classNameMatcher = createClassMatcher(className);
163         this.methodNameMatcher = createMatcher(methodName);
164         this.methodSigMatcher = createMatcher(methodSig);
165         this.mode = mode;
166     }
167
168     private StringMatcher createClassMatcher(String JavaDoc s) {
169         return s.startsWith("+")
170                 ? new SubclassMatcher(s.substring(1))
171                 : createMatcher(s);
172     }
173
174     private StringMatcher createMatcher(String JavaDoc s) {
175         return s.startsWith("/")
176                 ? (StringMatcher) new RegexpStringMatcher(s.substring(1))
177                 : (StringMatcher) new ExactStringMatcher(s);
178     }
179
180     @Override JavaDoc
181          public MatchResult match(InstructionHandle handle, ConstantPoolGen cpg,
182                              ValueNumberFrame before, ValueNumberFrame after, BindingSet bindingSet) throws DataflowAnalysisException {
183
184         // See if the instruction is an InvokeInstruction
185
Instruction ins = handle.getInstruction();
186         if (!(ins instanceof InvokeInstruction))
187             return null;
188         InvokeInstruction inv = (InvokeInstruction) ins;
189
190         String JavaDoc methodName = inv.getMethodName(cpg);
191         boolean isStatic = inv.getOpcode() == Constants.INVOKESTATIC;
192         boolean isCtor = methodName.equals("<init>");
193
194         int actualMode = 0;
195
196         if (isStatic) actualMode |= STATIC;
197         if (isCtor) actualMode |= CONSTRUCTOR;
198         if (!isStatic && !isCtor) actualMode |= INSTANCE;
199
200         // Intersection of actual and desired modes must be nonempty.
201
if ((actualMode & mode) == 0)
202             return null;
203
204         // Check class name, method name, and method signature.
205
if (!methodNameMatcher.match(methodName) ||
206                 !methodSigMatcher.match(inv.getSignature(cpg)) ||
207                 !classNameMatcher.match(inv.getClassName(cpg)))
208             return null;
209
210         // It's a match!
211
return new MatchResult(this, bindingSet);
212
213     }
214
215     @Override JavaDoc
216          public boolean acceptBranch(Edge edge, InstructionHandle source) {
217         return true;
218     }
219
220     @Override JavaDoc
221          public int minOccur() {
222         return 1;
223     }
224
225     @Override JavaDoc
226          public int maxOccur() {
227         return 1;
228     }
229 }
230
231 // vim:ts=4
232
Popular Tags