1 19 20 package edu.umd.cs.findbugs; 21 22 import java.io.IOException ; 23 24 import org.apache.bcel.Constants; 25 import org.apache.bcel.classfile.JavaClass; 26 27 import edu.umd.cs.findbugs.ba.AnalysisContext; 28 import edu.umd.cs.findbugs.ba.Hierarchy; 29 import edu.umd.cs.findbugs.ba.JavaClassAndMethod; 30 import edu.umd.cs.findbugs.ba.SignatureConverter; 31 import edu.umd.cs.findbugs.ba.SourceInfoMap; 32 import edu.umd.cs.findbugs.ba.XFactory; 33 import edu.umd.cs.findbugs.ba.XMethod; 34 import edu.umd.cs.findbugs.classfile.MethodDescriptor; 35 import edu.umd.cs.findbugs.util.ClassName; 36 import edu.umd.cs.findbugs.visitclass.DismantleBytecode; 37 import edu.umd.cs.findbugs.visitclass.PreorderVisitor; 38 import edu.umd.cs.findbugs.xml.XMLAttributeList; 39 import edu.umd.cs.findbugs.xml.XMLOutput; 40 41 50 public class MethodAnnotation extends PackageMemberAnnotation { 51 private static final long serialVersionUID = 1L; 52 53 private static final boolean UGLY_METHODS = SystemProperties.getBoolean("ma.ugly"); 54 55 private static final String DEFAULT_ROLE = "METHOD_DEFAULT"; 56 57 private String methodName; 58 private String methodSig; 59 private String fullMethod; 60 private boolean isStatic; 61 62 63 71 public MethodAnnotation(String className, String methodName, String methodSig, boolean isStatic) { 72 super(className, DEFAULT_ROLE); 73 this.methodName = methodName; 74 if (methodSig.indexOf(".") >= 0) { 75 assert false : "signatures should not be dotted: " + methodSig; 76 methodSig = methodSig.replace('.','/'); 77 } 78 this.methodSig = methodSig; 79 this.isStatic = isStatic; 80 fullMethod = null; 81 sourceLines = null; 82 } 83 84 90 public static MethodAnnotation fromVisitedMethod(PreorderVisitor visitor) { 91 String className = visitor.getDottedClassName(); 92 MethodAnnotation result = new MethodAnnotation( 93 className, 94 visitor.getMethodName(), 95 visitor.getMethodSig(), 96 visitor.getMethod().isStatic()); 97 98 SourceLineAnnotation srcLines = SourceLineAnnotation.fromVisitedMethod(visitor); 100 result.setSourceLines(srcLines); 101 102 return result; 103 } 104 105 112 public static MethodAnnotation fromCalledMethod(DismantleBytecode visitor) { 113 String className = visitor.getDottedClassConstantOperand(); 114 String methodName = visitor.getNameConstantOperand(); 115 String methodSig = visitor.getSigConstantOperand(); 116 117 return fromCalledMethod(className, methodName, methodSig, 118 visitor.getOpcode() == Constants.INVOKESTATIC); 119 } 120 121 133 public static MethodAnnotation fromForeignMethod( 134 String className, String methodName, String methodSig, boolean isStatic) { 135 136 138 className = ClassName.toDottedClassName(className); 139 140 MethodAnnotation methodAnnotation = 143 new MethodAnnotation(className, methodName, methodSig, isStatic); 144 145 SourceLineAnnotation sourceLines = null; 147 try { 148 JavaClass targetClass = AnalysisContext.currentAnalysisContext() 149 .lookupClass(className); 150 JavaClassAndMethod targetMethod = Hierarchy.findMethod(targetClass, methodName, methodSig); 151 if (targetMethod != null) { 152 sourceLines = SourceLineAnnotation.forEntireMethod( 153 targetMethod.getJavaClass(), targetMethod.getMethod()); 154 } 155 } catch (ClassNotFoundException e) { 156 } 158 159 if (sourceLines == null) { 161 SourceInfoMap.SourceLineRange range = AnalysisContext.currentAnalysisContext() 162 .getSourceInfoMap() 163 .getMethodLine(className, methodName, methodSig); 164 if (range != null) { 165 sourceLines = new SourceLineAnnotation( 166 className, 167 AnalysisContext.currentAnalysisContext().lookupSourceFile(className), 168 range.getStart(), 169 range.getEnd(), 170 -1, 171 -1); 172 } 173 } 174 175 if (sourceLines == null) { 179 sourceLines = SourceLineAnnotation.createUnknown(className); 180 } 181 182 methodAnnotation.setSourceLines(sourceLines); 183 184 return methodAnnotation; 185 } 186 187 199 public static MethodAnnotation fromCalledMethod( 200 String className, String methodName, String methodSig, boolean isStatic) { 201 202 MethodAnnotation methodAnnotation = 203 fromForeignMethod(className, methodName, methodSig, isStatic); 204 methodAnnotation.setDescription("METHOD_CALLED"); 205 return methodAnnotation; 206 207 } 208 209 215 public static MethodAnnotation fromXMethod(XMethod xmethod) { 216 return fromForeignMethod( 217 xmethod.getClassName(), 218 xmethod.getName(), 219 xmethod.getSignature(), 220 xmethod.isStatic()); 221 } 222 223 229 public static BugAnnotation fromMethodDescriptor(MethodDescriptor methodDescriptor) { 230 return fromForeignMethod( 231 methodDescriptor.getClassName(), 232 methodDescriptor.getName(), 233 methodDescriptor.getSignature(), 234 methodDescriptor.isStatic()); 235 } 236 237 240 public String getMethodName() { 241 return methodName; 242 } 243 244 public String getJavaSourceMethodName() { 245 if (methodName.equals("<clinit>")) return "<static initializer>"; 246 if (methodName.equals("<init>")) { 247 String result = getClassName(); 248 int pos = Math.max(result.lastIndexOf('$'),result.lastIndexOf('.')); 249 return className.substring(pos+1); 250 } 251 return methodName; 252 } 253 256 public String getMethodSignature() { 257 return methodSig; 258 } 259 260 265 public boolean isStatic() { 266 return isStatic; 267 } 268 269 274 public XMethod toXMethod() { 275 return XFactory.createXMethod(className, methodName, methodSig, isStatic); 276 } 277 278 279 public void accept(BugAnnotationVisitor visitor) { 280 visitor.visitMethodAnnotation(this); 281 } 282 283 @Override 284 protected String formatPackageMember(String key, ClassAnnotation primaryClass) { 285 if (key.equals("")) 286 return UGLY_METHODS ? getUglyMethod() : getFullMethod(primaryClass); 287 else if (key.equals("givenClass")) return getNameInClass(primaryClass); 288 else if (key.equals("shortMethod") ) 289 return className + "." + methodName + "()"; 290 else if (key.equals("hash")){ 291 String tmp= getNameInClass(true, primaryClass, true); 292 293 return className + "." + tmp; 294 } 295 else if (key.equals("returnType")) { 296 int i = methodSig.indexOf(')'); 297 String returnType = methodSig.substring(i+1); 298 String pkgName = primaryClass == null ? "" : primaryClass.getPackageName(); 299 SignatureConverter converter = new SignatureConverter(returnType); 300 return shorten(pkgName, converter.parseNext()); 301 } else 302 throw new IllegalArgumentException ("unknown key " + key); 303 } 304 305 String nameInClass = null; 306 312 public String getNameInClass(ClassAnnotation primaryClass) { 313 if (nameInClass == null) { 314 nameInClass = getNameInClass(true, primaryClass, false); 315 } 316 return nameInClass; 317 } 318 319 333 public String getNameInClass(boolean shortenPackages, ClassAnnotation primaryClass, boolean useJVMMethodName) { 334 if (primaryClass == null) shortenPackages = false; 335 StringBuffer result = new StringBuffer (); 337 if (useJVMMethodName) 338 result.append(getMethodName()); 339 else result.append(getJavaSourceMethodName()); 340 result.append('('); 341 342 SignatureConverter converter = new SignatureConverter(methodSig); 344 345 if (converter.getFirst() != '(') 346 throw new IllegalStateException ("bad method signature " + methodSig); 347 converter.skip(); 348 349 String pkgName = null; 350 if (shortenPackages) 351 pkgName = primaryClass.getPackageName(); 352 boolean needsComma = false; 353 while (converter.getFirst() != ')') { 354 if (needsComma) 355 result.append(','); 356 if (shortenPackages) 357 result.append(shorten(pkgName, converter.parseNext())); 358 else 359 result.append(converter.parseNext()); 360 needsComma = true; 361 } 362 converter.skip(); 363 364 result.append(')'); 365 return result.toString(); 366 } 367 368 369 375 public String getFullMethod(ClassAnnotation primaryClass) { 376 if (fullMethod == null) { 377 fullMethod = className + "." + getNameInClass(primaryClass); 378 } 379 380 return fullMethod; 381 } 382 383 private String getUglyMethod() { 384 return className + "." + methodName + " : " + methodSig.replace('/', '.'); 385 } 386 387 @Override 388 public int hashCode() { 389 return className.hashCode() + methodName.hashCode() + methodSig.hashCode(); 390 } 391 392 @Override 393 public boolean equals(Object o) { 394 if (!(o instanceof MethodAnnotation)) 395 return false; 396 MethodAnnotation other = (MethodAnnotation) o; 397 return className.equals(other.className) 398 && methodName.equals(other.methodName) 399 && methodSig.equals(other.methodSig); 400 } 401 402 public int compareTo(BugAnnotation o) { 403 if (!(o instanceof MethodAnnotation)) return this.getClass().getName().compareTo(o.getClass().getName()); 405 MethodAnnotation other = (MethodAnnotation) o; 406 int cmp; 407 cmp = className.compareTo(other.className); 408 if (cmp != 0) 409 return cmp; 410 cmp = methodName.compareTo(other.methodName); 411 if (cmp != 0) 412 return cmp; 413 return methodSig.compareTo(other.methodSig); 414 } 415 416 419 420 private static final String ELEMENT_NAME = "Method"; 421 422 public void writeXML(XMLOutput xmlOutput) throws IOException { 423 } 424 425 public void writeXML(XMLOutput xmlOutput, boolean addMessages) throws IOException { 426 XMLAttributeList attributeList = new XMLAttributeList() 427 .addAttribute("classname", getClassName()) 428 .addAttribute("name", getMethodName()) 429 .addAttribute("signature", getMethodSignature()) 430 .addAttribute("isStatic", String.valueOf(isStatic())); 431 432 String role = getDescription(); 433 if (!role.equals(DEFAULT_ROLE)) 434 attributeList.addAttribute("role", role); 435 436 if (sourceLines == null && !addMessages) { 437 xmlOutput.openCloseTag(ELEMENT_NAME, attributeList); 438 } else { 439 xmlOutput.openTag(ELEMENT_NAME, attributeList); 440 if (sourceLines != null) { 441 sourceLines.writeXML(xmlOutput); 442 } 443 if (addMessages) { 444 xmlOutput.openTag(MESSAGE_TAG); 445 xmlOutput.writeText(this.toString()); 446 xmlOutput.closeTag(MESSAGE_TAG); 447 } 448 xmlOutput.closeTag(ELEMENT_NAME); 449 } 450 } 451 } 452 453 | Popular Tags |