1 19 20 package edu.umd.cs.findbugs.ba; 21 22 import java.util.ArrayList ; 23 import java.util.Collections ; 24 import java.util.HashMap ; 25 import java.util.HashSet ; 26 import java.util.Map ; 27 import java.util.Set ; 28 29 import org.apache.bcel.Constants; 30 import org.apache.bcel.Repository; 31 import org.apache.bcel.classfile.Field; 32 import org.apache.bcel.classfile.JavaClass; 33 import org.apache.bcel.classfile.Method; 34 import org.apache.bcel.generic.ConstantPoolGen; 35 import org.apache.bcel.generic.FieldInstruction; 36 import org.apache.bcel.generic.InvokeInstruction; 37 import org.apache.bcel.generic.MethodGen; 38 39 import edu.umd.cs.findbugs.FieldAnnotation; 40 import edu.umd.cs.findbugs.MethodAnnotation; 41 import edu.umd.cs.findbugs.SystemProperties; 42 import edu.umd.cs.findbugs.annotations.CheckReturnValue; 43 import edu.umd.cs.findbugs.annotations.NonNull; 44 import edu.umd.cs.findbugs.visitclass.DismantleBytecode; 45 import edu.umd.cs.findbugs.visitclass.PreorderVisitor; 46 47 52 public class XFactory { 53 54 public XFactory() {}; 55 56 private Map <XMethod,XMethod> methods = new HashMap <XMethod,XMethod>(); 57 58 private Set <ClassMember> deprecated = new HashSet <ClassMember>(); 59 private Set <? extends ClassMember> deprecatedView = Collections.unmodifiableSet(deprecated); 60 private Map <XField,XField> fields = new HashMap <XField,XField>(); 61 62 private Set <XMethod> methodsView = Collections 63 .unmodifiableSet(methods.keySet()); 64 65 private Set <XField> fieldsView = Collections 66 .unmodifiableSet(fields.keySet()); 67 68 private Set <XMethod> calledMethods = new HashSet <XMethod>(); 69 private boolean calledMethodsIsInterned = false; 70 71 public void addCalledMethod(XMethod m) { 72 if (calledMethods.add(m) && !m.isResolved()) 73 calledMethodsIsInterned = false; 74 } 75 76 public boolean isCalled(XMethod m) { 77 if (!calledMethodsIsInterned) { 78 Set <XMethod> tmp = new HashSet <XMethod>(); 79 for(XMethod m2 : calledMethods) 80 tmp.add(intern(m2)); 81 calledMethodsIsInterned = true; 82 } 83 return calledMethods.contains(m); 84 } 85 86 public boolean isInterned(XMethod m) { 87 return methods.containsKey(m); 88 } 89 90 public @CheckReturnValue @NonNull XMethod intern(XMethod m) { 91 XMethod m2 = methods.get(m); 92 if (m2 != null) return m2; 93 94 methods.put(m,m); 95 return m; 96 } 97 98 public @CheckReturnValue @NonNull XField intern(XField f) { 99 XField f2 = fields.get(f); 100 if (f2 != null) return f2; 101 102 fields.put(f,f); 103 return f; 104 } 105 public Set <XMethod> getMethods() { 106 return methodsView; 107 } 108 109 public Set <XField> getFields() { 110 return fieldsView; 111 } 112 113 120 public static XMethod createXMethod(String className, Method method) { 121 XFactory xFactory = AnalysisContext.currentXFactory(); 122 String methodName = method.getName(); 123 String methodSig = method.getSignature(); 124 int accessFlags = method.getAccessFlags(); 125 boolean isStatic = method.isStatic(); 126 XMethod m; 127 if (isStatic) 128 m = new StaticMethod(className, methodName, methodSig, accessFlags); 129 else 130 m = new InstanceMethod(className, methodName, methodSig, accessFlags); 131 132 XMethod m2 = xFactory.intern(m); 133 ((AbstractMethod) m2).markAsResolved(); 136 return m2; 137 } 138 139 146 public static XMethod createXMethod(JavaClass javaClass , Method method) { 147 return createXMethod(javaClass.getClassName(), method); 148 } 149 156 public static XMethod createXMethod(String className, String methodName, String methodSig, boolean isStatic) { 157 XMethod m; 158 if (isStatic) 159 m = new StaticMethod(className, methodName, methodSig, Constants.ACC_STATIC); 160 else 161 m = new InstanceMethod(className, methodName, methodSig, 0); 162 XFactory xFactory = AnalysisContext.currentXFactory(); 163 m = xFactory.intern(m); 164 m = xFactory.resolve(m); 165 return m; 166 } 167 168 public static XMethod createXMethod(MethodAnnotation ma) { 169 return createXMethod(ma.getClassName(), ma.getMethodName(), ma.getMethodSignature(), ma.isStatic()); 170 } 171 172 static class RecursionDepth { 173 private static final int MAX_DEPTH = 50; 174 private int depth = 0; 175 ArrayList <Object > list = new ArrayList <Object >(); 176 public String toString() { 177 return list.toString(); 178 } 179 public void dump() { 180 System.out.println("Recursive calls" ); 181 for(Object o : list) 182 System.out.println(" resolve " + o); 183 } 184 public boolean enter(Object value) { 185 if (depth > MAX_DEPTH) 186 return false; 187 if (DEBUG_CIRCULARITY) list.add(value); 188 depth++; 189 return true; 190 } 191 public void exit() { 192 depth--; 193 if (DEBUG_CIRCULARITY) list.remove(list.size()-1); 194 assert depth >= 0; 195 } 196 } 197 static ThreadLocal <RecursionDepth> recursionDepth = new ThreadLocal <RecursionDepth>() { 198 @Override 199 public RecursionDepth initialValue() { 200 return new RecursionDepth(); 201 } 202 }; 203 212 public static XField createXField(String className, String fieldName, String fieldSignature, boolean isStatic) { 213 XFactory xFactory =AnalysisContext.currentXFactory(); 214 XField f; 215 216 if (isStatic) { 217 int accessFlags = 0; 218 if (fieldName.toUpperCase().equals(fieldName)) 219 accessFlags = Constants.ACC_FINAL; 220 f = new StaticField(className, fieldName, fieldSignature, accessFlags); 221 } 222 else { 223 int accessFlags = 0; 224 if (fieldName.startsWith("this$")) accessFlags = Constants.ACC_FINAL; 225 f = new InstanceField(className, fieldName, fieldSignature, accessFlags); 226 } 227 f = xFactory.intern(f); 228 f = xFactory.resolve(f); 229 return f; 230 } 231 232 public static boolean DEBUG_CIRCULARITY = SystemProperties.getBoolean("circularity.debug"); 233 237 private @NonNull XField resolve(XField f) { 238 if (f.isResolved()) return f; 239 if (f.isStatic()) return f; 240 if (f.getName().startsWith("this$")) return f; 241 try { 242 if (!recursionDepth.get().enter(f)) { 243 fail("recursive cycle trying to resolve " + f, null, null); 244 return f; 245 } 246 247 XField f2 = f; 248 String classname = f.getClassName(); 249 try { 250 JavaClass superClass = Repository.lookupClass(classname).getSuperClass(); 251 if (superClass == null) return f; 252 253 if (classname.equals(superClass.getClassName())) return f; 254 f2 = createXField(superClass.getClassName(), f.getName(), f.getSignature(), f.isStatic()); 255 f2 = intern(f2); 256 if (f2.isResolved()) { 257 fields.put(f, f2); 258 return f2; 259 } 260 261 262 } catch (ClassNotFoundException e) { 263 AnalysisContext.reportMissingClass(e); 264 } 265 return f; 266 } finally { 267 recursionDepth.get().exit(); 268 } 269 } 270 271 private static void fail(String s, JavaClass jClass, JavaClass superClass) { 272 AnalysisContext.logError(s); 273 if (DEBUG_CIRCULARITY) { 274 System.out.println(s); 275 recursionDepth.get().dump(); 276 277 } 278 if (jClass != null) 279 System.out.println(jClass); 280 if (superClass != null) 281 System.out.println(superClass); 282 System.exit(1); 283 } 284 290 private @NonNull XMethod resolve(XMethod m) { 291 if (m.isResolved()) return m; 292 try { 294 if (!recursionDepth.get().enter(m)) { 295 fail("recursive cycle trying to resolve " + m, null, null); 296 return m; 297 } 298 299 String className = m.getClassName(); 300 301 String methodName = m.getName(); 302 if (className.charAt(0)=='[' || methodName.equals("<init>") || methodName.equals("<clinit>") || methodName.startsWith("access$")) { 303 ((AbstractMethod)m).markAsResolved(); 304 return m; 305 } 306 try { 307 JavaClass javaClass = Repository.lookupClass(className); 308 if (!javaClass.getClassName().equals(className)) { 309 fail("Looked up " + className + ", got a class named " + javaClass.getClassName(), javaClass, null); 310 return m; 311 } 312 JavaClass superClass = javaClass.getSuperClass(); 313 if (superClass == null) return m; 314 String superClassName = superClass.getClassName(); 315 if (!javaClass.getSuperclassName().equals(superClassName)) 316 fail("requested superclass of " + className + ", expecting to get " + javaClass.getSuperclassName() 317 + ", instead got " + superClassName, javaClass, superClass); 318 if (superClass.getSuperclassName().equals(className) 319 || className.equals(superClassName)) { 320 fail("superclass of " + className + " is " + superClassName, javaClass, superClass); 321 return m; 322 } 323 XMethod m2 = createXMethod(superClassName, methodName, m.getSignature(), m.isStatic()); 324 if (m2.isResolved()) { 325 methods.put(m, m2); 326 return m2; 327 } 328 } catch (ClassNotFoundException e) { 329 AnalysisContext.reportMissingClass(e); 330 } 331 return m; 333 } finally { 334 recursionDepth.get().exit(); 335 } 336 337 } 338 339 public static XField createXField(FieldInstruction fieldInstruction, ConstantPoolGen cpg) { 340 String className = fieldInstruction.getClassName(cpg); 341 String fieldName = fieldInstruction.getName(cpg); 342 String fieldSig = fieldInstruction.getSignature(cpg); 343 344 int opcode = fieldInstruction.getOpcode(); 345 return createXField(className, fieldName, fieldSig, opcode == Constants.GETSTATIC 346 || opcode == Constants.PUTSTATIC ); 347 } 348 public static XField createReferencedXField(DismantleBytecode visitor) { 349 return createXField(visitor.getDottedClassConstantOperand(), 350 visitor.getNameConstantOperand(), 351 visitor.getSigConstantOperand(), 352 visitor.getRefFieldIsStatic()); 353 } 354 public static XMethod createReferencedXMethod(DismantleBytecode visitor) { 355 return createXMethod(visitor.getDottedClassConstantOperand(), 356 visitor.getNameConstantOperand(), 357 visitor.getSigConstantOperand(), 358 visitor.getOpcode() == Constants.INVOKESTATIC); 359 } 360 361 public static XField createXField(FieldAnnotation f) { 362 return createXField(f.getClassName(), f.getFieldName(), f.getFieldSignature(), f.isStatic()); 363 } 364 365 public static XField createXField(JavaClass javaClass, Field field) { 366 return createXField(javaClass.getClassName(), field); 367 } 368 375 public static XField createXField(String className, Field field) { 376 String fieldName = field.getName(); 377 String fieldSig = field.getSignature(); 378 int accessFlags = field.getAccessFlags(); 379 XFactory xFactory = AnalysisContext.currentXFactory(); 380 XField f; 381 if (field.isStatic()) 382 f = new StaticField(className, fieldName, fieldSig, accessFlags); 383 else 384 f = new InstanceField(className, fieldName, fieldSig, accessFlags); 385 XField f2 = xFactory.intern(f); 386 ((AbstractField) f2).markAsResolved(); 389 return f2; 390 } 391 398 public static XMethod createXMethod(InvokeInstruction invokeInstruction, ConstantPoolGen cpg) { 399 String className = invokeInstruction.getClassName(cpg); 400 String methodName = invokeInstruction.getName(cpg); 401 String methodSig = invokeInstruction.getSignature(cpg); 402 403 return createXMethod(className, methodName, methodSig, invokeInstruction.getOpcode() == Constants.INVOKESTATIC); 404 } 405 406 413 public static XMethod createXMethod(PreorderVisitor visitor) { 414 JavaClass javaClass = visitor.getThisClass(); 415 Method method = visitor.getMethod(); 416 XMethod m = createXMethod(javaClass, method); 417 return m; 418 } 419 420 427 public static XField createXField(PreorderVisitor visitor) { 428 JavaClass javaClass = visitor.getThisClass(); 429 Field field = visitor.getField(); 430 XField f = createXField(javaClass, field); 431 return f; 432 } 433 434 public static XMethod createXMethod(MethodGen methodGen) { 435 return createXMethod(methodGen.getClassName(), methodGen.getMethod()); 436 437 } 438 439 442 public void deprecate(ClassMember m) { 443 deprecated.add(m); 444 445 } 446 public Set <? extends ClassMember> getDeprecated() { 447 return deprecatedView; 448 } 449 450 } 451 | Popular Tags |