2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.util;
21 import gov.nasa.jpf.vm.ClassInfo;
22 import gov.nasa.jpf.vm.MethodInfo;
23 import gov.nasa.jpf.vm.Types;
25 import java.util.BitSet;
28 * utility class that can match methods/args against specs.
29 * argument signatures can be given in dot notation (like javap), arguments
30 * can be marked with a preceeding '^'
31 * if the class or name part are omitted, "*" is assumed
32 * a preceeding '!' means the match is inverted
36 * "java.util.HashMap.add(java.lang.Object,^java.lang.Object)"
39 * Note: with a single '*' we can't tell if this is for the typename
40 * or the method, so something like "java.*" is probably not doing
41 * what you expect - it uses the wildcard for the method and 'java' for
44 * <2do> we should extend this to allow alternatives
46 public class MethodSpec extends FeatureSpec {
48 static class MethodParseData extends ParseData {
52 static final char MARK = '^'; // to mark arguments
54 String sigSpec; // this is only the argument part, including parenthesis
58 * factory method that includes the parser
60 public static MethodSpec createMethodSpec (String s){
61 MethodParseData d = new MethodParseData();
66 s = parseInversion(s,d);
68 int i = s.indexOf(('('));
69 if (i >= 0){ // we have a signature part
70 int j = s.lastIndexOf(')');
72 d.sigSpec = s.substring(i, j+1);
73 s = s.substring(0, i);
76 return null; // error, unbalanced parenthesis
80 parseTypeAndName(s,d);
83 return new MethodSpec(src, d.typeSpec, d.nameSpec, d.sigSpec, d.matchInverted);
84 } catch (IllegalArgumentException iax){
90 public MethodSpec (String rawSpec, String cls, String name, String argSig, boolean inverted){
91 super(rawSpec,cls,name,inverted);
94 parseSignature(argSig);
99 * assumed to be comma separated type list using fully qualified dot notation
100 * like javap, but arguments can be marked with preceeding '^',
101 * like "(java.lang.String,^int[])"
102 * spec includes parenthesis
104 void parseSignature (String spec){
106 StringBuilder sb = new StringBuilder();
107 String al = spec.substring(1, spec.length()-1);
108 String[] args = al.split(",");
112 for (String a : args){
115 if (a.charAt(0) == MARK){
117 m = new BitSet(args.length);
122 String tc = Types.getTypeSignature(a, false);
127 // error in arg type spec
132 sigSpec = sb.toString();
138 public String toString() {
139 StringBuilder sb = new StringBuilder();
140 sb.append("MethodSpec {");
141 sb.append("matchInverted:");
142 sb.append(matchInverted);
143 if (clsSpec != null){
144 sb.append(",clsSpec:\"");
148 if (nameSpec != null){
149 sb.append(",nameSpec:\"");
153 if (sigSpec != null){
154 sb.append(",sigSpec:\"");
158 if (markedArgs != null){
159 sb.append(",marked:");
160 sb.append(markedArgs);
163 return sb.toString();
167 public BitSet getMarkedArgs () {
171 public boolean isMarkedArg(int idx){
172 return (markedArgs == null || markedArgs.get(idx));
179 public boolean matches (Object feature){
180 if (feature instanceof MethodInfo){
181 return matches((MethodInfo)feature);
187 public boolean matches (MethodInfo mi){
188 boolean isMatch = false;
190 ClassInfo ci = mi.getClassInfo();
191 if (isMatchingType(ci)){
192 if (nameSpec.matches(mi.getName())){
193 if (sigSpec != null){
194 // sigSpec includes '(',')' but not return type
195 isMatch = mi.getSignature().startsWith(sigSpec);
196 } else { // no sigSpec -> matches all signatures
202 return (isMatch != matchInverted);
205 public boolean matches (String clsName, String mthName){
206 boolean isMatch = clsSpec.matches(clsName) && nameSpec.matches(mthName);
207 return isMatch != matchInverted;
210 public boolean matchesClass (String clsName){
211 return clsSpec.matches(clsName) != matchInverted;