1 package edu.umd.cs.findbugs; 2 3 import java.util.HashSet ; 4 import java.util.Set ; 5 6 import org.apache.bcel.Repository; 7 import org.apache.bcel.classfile.JavaClass; 8 9 import edu.umd.cs.findbugs.ba.AnalysisContext; 10 import edu.umd.cs.findbugs.ba.ch.Subtypes; 11 12 public class DeepSubtypeAnalysis { 13 static private JavaClass serializable; 14 15 static private JavaClass collection; 16 static private JavaClass comparator; 17 18 static private JavaClass map; 19 static private JavaClass remote; 20 static private ClassNotFoundException storedException; 21 22 static { 23 try { 24 serializable = AnalysisContext.lookupSystemClass("java.io.Serializable"); 25 collection = AnalysisContext.lookupSystemClass("java.util.Collection"); 26 map = AnalysisContext.lookupSystemClass("java.util.Map"); 27 comparator = AnalysisContext.lookupSystemClass("java.util.Comparator"); 28 29 } catch (ClassNotFoundException e) { 30 storedException = e; 31 } 32 try { 33 remote = AnalysisContext.lookupSystemClass("java.rmi.Remote"); 34 } catch (ClassNotFoundException e) { 35 if (storedException == null) storedException = e; 36 } 37 } 38 39 private static boolean containsConcreteClasses(Set <JavaClass> s) { 40 for (JavaClass c : s) 41 if (!c.isInterface() && !c.isAbstract()) 42 return true; 43 return false; 44 } 45 46 public static double isDeepSerializable(String refSig) 47 throws ClassNotFoundException { 48 if (storedException != null) 49 throw storedException; 50 51 if (isPrimitiveComponentClass(refSig)) 52 return 1.0; 53 54 String refName = getComponentClass(refSig); 55 if (refName.equals("java.lang.Object")) 56 return 0.99; 57 58 JavaClass refJavaClass = Repository.lookupClass(refName); 59 return isDeepSerializable(refJavaClass); 60 } 61 62 public static double isDeepRemote(String refSig) { 63 if (remote == null) return 0.1; 64 65 String refName = getComponentClass(refSig); 66 if (refName.equals("java.lang.Object")) 67 return 0.99; 68 69 JavaClass refJavaClass; 70 try { 71 refJavaClass = Repository.lookupClass(refName); 72 return deepInstanceOf(refJavaClass, remote); 73 } catch (ClassNotFoundException e) { 74 return 0.99; 75 } 76 77 78 } 79 private static boolean isPrimitiveComponentClass(String refSig) { 80 int c = 0; 81 while (c < refSig.length() && refSig.charAt(c) == '[') { 82 c++; 83 } 84 85 return c >= refSig.length() || refSig.charAt(c) != 'L'; 91 } 92 93 public static String getComponentClass(String refSig) { 94 while (refSig.charAt(0) == '[') 95 refSig = refSig.substring(1); 96 97 if (refSig.charAt(0) == 'L') 99 return refSig.substring(1, refSig.length() - 1).replace('/', '.'); 100 return refSig; 101 } 102 103 public static double isDeepSerializable(JavaClass x) 104 throws ClassNotFoundException { 105 if (storedException != null) 106 throw storedException; 107 108 double result = deepInstanceOf(x, serializable); 109 if (result >= 0.9) 110 return result; 111 result = Math.max(result, deepInstanceOf(x, collection)); 112 if (result >= 0.9) 113 return result; 114 result = Math.max(result, deepInstanceOf(x, map)); 115 if (result >= 0.9) 116 return result; 117 result = Math.max(result, 0.5*deepInstanceOf(x, comparator)); 118 if (result >= 0.9) 119 return result; 120 return result; 121 } 122 123 134 135 public static double deepInstanceOf(String x, String y) 136 throws ClassNotFoundException { 137 return deepInstanceOf(AnalysisContext.currentAnalysisContext().lookupClass(x), 138 AnalysisContext.currentAnalysisContext().lookupClass(y)); 139 } 140 141 152 public static double deepInstanceOf(JavaClass x, JavaClass y) 153 throws ClassNotFoundException { 154 155 if (x.equals(y)) 156 return 1.0; 157 boolean xIsSubtypeOfY = Repository.instanceOf(x, y); 158 if (xIsSubtypeOfY) 159 return 1.0; 160 boolean yIsSubtypeOfX = Repository.instanceOf(y, x); 161 if (!yIsSubtypeOfX) { 162 if (x.isFinal() || y.isFinal()) 163 return 0.0; 164 if (!x.isInterface() && !y.isInterface()) 165 return 0.0; 166 } 167 168 Subtypes subtypes = AnalysisContext.currentAnalysisContext() 169 .getSubtypes(); 170 subtypes.addClass(x); 171 subtypes.addClass(y); 172 173 Set <JavaClass> xSubtypes = subtypes.getTransitiveSubtypes(x); 174 175 Set <JavaClass> ySubtypes = subtypes.getTransitiveSubtypes(y); 176 177 boolean emptyIntersection = true; 178 179 boolean concreteClassesInXButNotY = false; 180 for(JavaClass s : xSubtypes) { 181 if (ySubtypes.contains(s)) emptyIntersection = false; 182 else if (!s.isInterface() && !s.isAbstract()) 183 concreteClassesInXButNotY = true; 184 } 185 186 187 if (emptyIntersection) { 188 if (concreteClassesInXButNotY) { 189 if (x.isAbstract() || x.isInterface()) return 0.2; 190 return 0.1; 191 } 192 return 0.3; 193 } 194 195 197 if (!concreteClassesInXButNotY) { 198 return 0.99; 200 } 201 202 return 0.7; 204 205 } 206 } 207 | Popular Tags |