1 19 20 package edu.umd.cs.findbugs.ba; 21 22 import java.util.HashMap ; 23 import java.util.HashSet ; 24 import java.util.Map ; 25 import java.util.Set ; 26 import java.util.TreeSet ; 27 28 import org.apache.bcel.Repository; 29 import org.apache.bcel.classfile.JavaClass; 30 import org.apache.bcel.classfile.Method; 31 32 import edu.umd.cs.findbugs.SystemProperties; 33 import edu.umd.cs.findbugs.annotations.CheckForNull; 34 import edu.umd.cs.findbugs.ba.ch.Subtypes; 35 import edu.umd.cs.findbugs.util.MapCache; 36 37 40 public class AnnotationDatabase<AnnotationEnum extends AnnotationEnumeration<AnnotationEnum>> { 41 static final boolean DEBUG = SystemProperties.getBoolean("annotations.debug");; 42 43 46 public static final String FIELD = "Field"; 47 48 51 public static final String METHOD = "Method"; 52 53 56 public static final String PARAMETER = "Parameter"; 57 58 61 public static final String ANY = "Any"; 62 63 private static final String DEFAULT_ANNOTATION_ANNOTATION_CLASS = "DefaultAnnotation"; 64 65 private Map <Object , AnnotationEnum> directAnnotations = new HashMap <Object , AnnotationEnum>(); 66 67 private Set <Object > syntheticElements = new HashSet <Object >(); 68 69 private final Map <String , Map <String , AnnotationEnum>> defaultAnnotation = new HashMap <String , Map <String , AnnotationEnum>>(); 70 71 private Subtypes subtypes; 72 public AnnotationDatabase() { 73 defaultAnnotation.put(ANY, 74 new HashMap <String , AnnotationEnum>()); 75 defaultAnnotation.put(PARAMETER, 76 new HashMap <String , AnnotationEnum>()); 77 defaultAnnotation.put(METHOD, 78 new HashMap <String , AnnotationEnum>()); 79 defaultAnnotation.put(FIELD, 80 new HashMap <String , AnnotationEnum>()); 81 subtypes = AnalysisContext.currentAnalysisContext().getSubtypes(); 82 83 } 84 85 public void loadAuxiliaryAnnotations() { 86 87 } 88 private final Set <AnnotationEnum> seen = new HashSet <AnnotationEnum>(); 89 public void addSyntheticElement(Object o) { 90 syntheticElements.add(o); 91 if (DEBUG) 92 System.out.println("Synthetic element: " + o); 93 } 94 95 public void addDirectAnnotation(Object o, AnnotationEnum n) { 96 directAnnotations.put(o, n); 97 seen.add(n); 98 } 99 100 public void addDefaultAnnotation(String target, String c, 101 AnnotationEnum n) { 102 if (!defaultAnnotation.containsKey(target)) 103 return; 104 if (DEBUG) 105 System.out.println("Default annotation " + target + " " + c + " " + n); 106 defaultAnnotation.get(target).put(c, n); 107 seen.add(n); 108 } 109 110 public boolean anyAnnotations(AnnotationEnum n) { 111 return seen.contains(n); 112 } 113 114 Map <Object , AnnotationEnum> cachedMinimal = new MapCache<Object , AnnotationEnum>(20000); 116 Map <Object , AnnotationEnum> cachedMaximal= new MapCache<Object , AnnotationEnum>(20000); 117 @CheckForNull 118 public AnnotationEnum getResolvedAnnotation(Object o, boolean getMinimal) { 119 Map <Object , AnnotationEnum> cache; 120 if (getMinimal) cache = cachedMinimal; 121 else cache = cachedMaximal; 122 123 if (cache.containsKey(o)) { 124 return cache.get(o); 125 } 126 AnnotationEnum n = getUncachedResolvedAnnotation(o, getMinimal); 127 if (DEBUG) System.out.println("TTT: " + o + " " + n); 128 cache.put(o,n); 129 return n; 130 } 131 132 public boolean annotationIsDirect(Object o) { 133 return directAnnotations.containsKey(o); 134 } 135 @CheckForNull 136 public AnnotationEnum getUncachedResolvedAnnotation(final Object o, boolean getMinimal) { 137 138 AnnotationEnum n = directAnnotations.get(o); 139 if (n != null) 140 return n; 141 142 try { 143 144 String className; 145 String kind; 146 boolean isParameterToInitMethodofAnonymousInnerClass = false; 147 boolean isSyntheticMethod = false; 148 if (o instanceof XMethod || o instanceof XMethodParameter) { 149 150 XMethod m; 151 if (o instanceof XMethod) { 152 m = (XMethod) o; 153 isSyntheticMethod = syntheticElements.contains(m); 154 kind = METHOD; 155 className = m.getClassName(); 156 } else if (o instanceof XMethodParameter) { 157 m = ((XMethodParameter) o).getMethod(); 158 isSyntheticMethod = syntheticElements.contains(m); 160 className = m.getClassName(); 161 kind = PARAMETER; 162 if (m.getName().equals("<init>")) { 163 int i = className.lastIndexOf("$"); 164 if (i+1 < className.length() 165 && Character.isDigit(className.charAt(i+1))) 166 isParameterToInitMethodofAnonymousInnerClass = true; 167 } 168 } else 169 throw new IllegalStateException ("impossible"); 170 171 172 173 if (!m.isStatic() && !m.getName().equals("<init>")) { 174 JavaClass c = Repository.lookupClass(className); 175 TreeSet <AnnotationEnum> inheritedAnnotations = new TreeSet <AnnotationEnum>(); 177 if (c.getSuperclassNameIndex() > 0) { 178 179 n = lookInOverriddenMethod(o, c.getSuperclassName(), m, getMinimal); 180 if (n != null) 181 inheritedAnnotations.add(n); 182 } 183 for(String implementedInterface : c.getInterfaceNames()) { 184 n = lookInOverriddenMethod(o, implementedInterface, m, getMinimal); 185 if (n != null) 186 inheritedAnnotations.add(n); 187 } 188 if (DEBUG) System.out.println("# of inherited annotations : " + inheritedAnnotations.size()); 189 if (!inheritedAnnotations.isEmpty()) { 190 if (inheritedAnnotations.size() == 1) 191 return inheritedAnnotations.first(); 192 if (!getMinimal) 193 return inheritedAnnotations.last(); 194 195 AnnotationEnum min = inheritedAnnotations.first(); 196 if (min.getIndex() == 0) { 197 inheritedAnnotations.remove(min); 198 min = inheritedAnnotations.first(); 199 } 200 return min; 201 } 202 if (! classDefinesMethod(c, m) ) return null; 205 if (DEBUG) System.out.println("looking for default annotations: " + c.getClassName() + " defines " + m); 206 } } else if (o instanceof XField) { 209 210 className = ((XField) o).getClassName(); 211 kind = FIELD; 212 } else if (o instanceof String ) { 213 className = (String ) o; 214 kind = "CLASS"; 215 } else throw new IllegalArgumentException ("Can't look up annotation for " + o.getClass().getName()); 216 217 if (isParameterToInitMethodofAnonymousInnerClass) return null; 220 if (isSyntheticMethod) return null; 221 222 if (syntheticElements.contains(o)) return null; 224 if (syntheticElements.contains(className)) return null; 225 226 227 n = defaultAnnotation.get(kind).get(className); 229 if (DEBUG) 230 System.out.println("Default annotation for " + kind + " is " + n); 231 if (n != null) 232 return n; 233 234 n = defaultAnnotation.get(ANY).get(className); 235 if (DEBUG) 236 System.out.println("Default annotation for any is " + n); 237 if (n != null) 238 return n; 239 240 241 int p = className.lastIndexOf('.'); 242 className = className.substring(0,p+1) + "package-info"; 243 n = defaultAnnotation.get(kind).get(className); 244 if (DEBUG) 245 System.out.println("Default annotation for " + kind + " is " + n); 246 if (n != null) 247 return n; 248 249 n = defaultAnnotation.get(ANY).get(className); 250 if (DEBUG) 251 System.out.println("Default annotation for any is " + n); 252 if (n != null) 253 return n; 254 255 256 257 return n; 258 } catch (ClassNotFoundException e) { 259 AnalysisContext.reportMissingClass(e); 260 return null; 261 } 262 263 } 264 265 private boolean classDefinesMethod(JavaClass c, XMethod m) { 266 for(Method definedMethod : c.getMethods()) 267 if (definedMethod.getName().equals(m.getName()) 268 && definedMethod.getSignature().equals(m.getSignature()) 269 && definedMethod.isStatic() == m.isStatic()) 270 return true; 271 return false; 272 } 273 274 private AnnotationEnum lookInOverriddenMethod(final Object originalQuery, 275 String classToLookIn, XMethod originalMethod, boolean getMinimal) { 276 try { 277 AnnotationEnum n; 278 XMethod superMethod = XFactory.createXMethod(classToLookIn, originalMethod.getName(), 280 originalMethod.getSignature(), originalMethod.isStatic()); 281 if (!superMethod.isResolved()) return null; 282 if (DEBUG) 283 System.out.println("Looking for overridden method " + superMethod); 284 285 Object probe; 286 if (originalQuery instanceof XMethod) 287 probe = superMethod; 288 else if (originalQuery instanceof XMethodParameter) 289 probe = new XMethodParameter(superMethod, 290 ((XMethodParameter) originalQuery).getParameterNumber()); 291 else 292 throw new IllegalStateException ("impossible"); 293 294 n = getResolvedAnnotation(probe, getMinimal); 295 return n; 296 } catch (RuntimeException e) { 297 e.printStackTrace(); 298 throw e; 299 } 300 } 301 302 boolean addClassOnly = false; 303 public boolean setAddClassOnly(boolean newValue) { 304 boolean oldValue = addClassOnly; 305 addClassOnly = newValue; 306 return oldValue; 307 } 308 protected void addDefaultMethodAnnotation(String cName, AnnotationEnum annotation) { 309 subtypes.addNamedClass(cName); 310 311 if (addClassOnly) return; 312 313 addDefaultAnnotation(AnnotationDatabase.METHOD, cName, annotation); 314 315 316 } 317 318 protected void addFieldAnnotation(String cName, String mName, String mSig, boolean isStatic, AnnotationEnum annotation) { 319 subtypes.addNamedClass(cName); 320 if (addClassOnly) return; 321 XField m = XFactory.createXField(cName, mName, mSig, isStatic); 322 addDirectAnnotation(m, annotation); 323 } 324 325 protected void addMethodAnnotation(String cName, String mName, String mSig, boolean isStatic, AnnotationEnum annotation) { 326 subtypes.addNamedClass(cName); 327 if (addClassOnly) return; 328 XMethod m = XFactory.createXMethod(cName, mName, mSig, isStatic); 329 addDirectAnnotation(m, annotation); 330 } 331 protected void addMethodParameterAnnotation(String cName, String mName, String mSig, boolean isStatic, int param, AnnotationEnum annotation) { 332 subtypes.addNamedClass(cName); 333 if (addClassOnly) return; 334 XMethod m = XFactory.createXMethod(cName, mName, mSig, isStatic); 335 addDirectAnnotation(new XMethodParameter(m, param), annotation); 336 } 337 } 338 | Popular Tags |