private boolean isGenericCollection(ClassDescriptor operandClass) { String dottedClassName = operandClass.getDottedClassName(); if (baseGenericTypes.contains(dottedClassName)) return true; String found = null; for (String c : baseGenericTypes) { if (Subtypes2.instanceOf(operandClass, c)) { found = c; break; } } if (found == null) return false; if (dottedClassName.startsWith("java.util.") || dottedClassName.startsWith("com.google.common.collect.")) return true; try { XClass xclass = Global.getAnalysisCache().getClassAnalysis(XClass.class, operandClass); String sig = xclass.getSourceSignature(); if (sig == null) return false; String typeParameter = null; List<String> split = GenericUtilities.split(sig, true); if (sig.charAt(0) == '<') { int end = sig.indexOf(':'); if (end > 0) typeParameter = sig.substring(1, end); } if (DEBUG) System.out.println(dottedClassName + " " + typeParameter + " " + split); for (String s : split) { int i = s.indexOf('<'); if (i < 0) continue; if (s.charAt(0) != 'L') throw new IllegalStateException("unexpected non signature: " + s); ClassDescriptor c = DescriptorFactory.createClassDescriptor(s.substring(1, i)); String superTypeParameter = s.substring(i + 1); if (isGenericCollection(c) && (typeParameter == null || superTypeParameter.startsWith("T" + typeParameter))) { if (DEBUG) System.out.println(operandClass + " is a subtype of " + s); return true; } } if (DEBUG) System.out.println("Not a subtype"); } catch (CheckedAnalysisException e1) { AnalysisContext.logError( "Error checking for weird generic parameterization of " + operandClass, e1); } return false; }
public static void reportMissingClass(ClassDescriptor c) { requireNonNull(c, "argument is null"); if (!analyzingApplicationClass()) { return; } String missing = c.getDottedClassName(); if (missing.length() == 1) { System.out.println(c); } if (skipReportingMissingClass(missing)) { return; } RepositoryLookupFailureCallback lookupFailureCallback = getCurrentLookupFailureCallback(); if (lookupFailureCallback != null) { lookupFailureCallback.reportMissingClass(c); } }
public static double isDeepSerializable(JavaClass x) throws ClassNotFoundException { if (storedException != null) throw storedException; if (x.getClassName().equals("java.lang.Object")) return 0.4; if (DEBUG) { System.out.println("checking " + x.getClassName()); } double result = Analyze.deepInstanceOf(x, serializable); if (result >= 0.9) { if (DEBUG) { System.out.println("Direct high serializable result: " + result); } return result; } if (x.isFinal()) return result; double collectionResult = Analyze.deepInstanceOf(x, collection); double mapResult = Analyze.deepInstanceOf(x, map); if (x.isInterface() || x.isAbstract()) { result = Math.max(result, Math.max(mapResult, collectionResult) * 0.95); if (result >= 0.9) { return result; } } ClassDescriptor classDescriptor = DescriptorFactory.createClassDescriptor(x); Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2(); Set<ClassDescriptor> directSubtypes = subtypes2.getDirectSubtypes(classDescriptor); directSubtypes.remove(classDescriptor); double confidence = 0.6; if (x.isAbstract() || x.isInterface()) { confidence = 0.8; result = Math.max(result, 0.4); } else if (directSubtypes.isEmpty()) confidence = 0.2; double confidence2 = (1 + confidence) / 2; result = Math.max(result, confidence2 * collectionResult); if (result >= 0.9) { if (DEBUG) { System.out.println("High collection result: " + result); } return result; } result = Math.max(result, confidence2 * mapResult); if (result >= 0.9) { if (DEBUG) { System.out.println("High map result: " + result); } return result; } result = Math.max(result, confidence2 * 0.5 * Analyze.deepInstanceOf(x, comparator)); if (result >= 0.9) { if (DEBUG) { System.out.println("High comparator result: " + result); } return result; } for (ClassDescriptor subtype : directSubtypes) { JavaClass subJavaClass = Repository.lookupClass(subtype.getDottedClassName()); result = Math.max(result, confidence * Analyze.deepInstanceOf(subJavaClass, serializable)); // result = Math.max(result, confidence * isDeepSerializable(subJavaClass)); if (result >= 0.9) { return result; } } if (DEBUG) { System.out.println("No high results; max: " + result); } return result; }
private TypeQualifierValue(ClassDescriptor typeQualifier, @CheckForNull Object value) { this.typeQualifier = typeQualifier; this.value = value; boolean isStrict = false; // will be set to true if this is a strict // type qualifier value boolean isExclusive = false; // will be set to true if this is an // exclusive type qualifier value boolean isExhaustive = false; // will be set to true if this is an // exhaustive type qualifier value TypeQualifierValidator<A> validator = null; Class<A> qualifierClass = null; A proxy = null; try { XClass xclass = Global.getAnalysisCache().getClassAnalysis(XClass.class, typeQualifier); // Annotation elements appear as abstract methods in the annotation // class (interface). // So, if the type qualifier annotation has specified a default When // value, // it will appear as an abstract method called "when". XMethod whenMethod = xclass.findMethod("when", "()Ljavax/annotation/meta/When;", false); if (whenMethod == null) { isStrict = true; } for (XMethod xmethod : xclass.getXMethods()) { if (xmethod.getName().equals("value") && xmethod.getSignature().startsWith("()")) { isExhaustive = xmethod.getAnnotation(EXHAUSTIVE_ANNOTATION) != null; if (isExhaustive) { // exhaustive qualifiers are automatically exclusive isExclusive = true; } else { // see if there is an explicit @Exclusive annotation isExclusive = xmethod.getAnnotation(EXCLUSIVE_ANNOTATION) != null; } break; } } } catch (MissingClassException e) { AnalysisContext.currentAnalysisContext() .getLookupFailureCallback() .reportMissingClass(e.getClassNotFoundException()); } catch (CheckedAnalysisException e) { AnalysisContext.logError( "Error looking up annotation class " + typeQualifier.toDottedClassName(), e); } this.isStrict = isStrict; this.isExclusive = isExclusive; this.isExhaustive = isExhaustive; ClassDescriptor checkerName = DescriptorFactory.createClassDescriptor(typeQualifier.getClassName() + "$Checker"); try { Global.getAnalysisCache().getClassAnalysis(ClassData.class, checkerName); // found it. // System.out.println(checkerName); SecurityManager m = System.getSecurityManager(); if (m == null) System.setSecurityManager(new ValidationSecurityManager()); Class<?> c = validatorLoader.loadClass(checkerName.getDottedClassName()); if (TypeQualifierValidator.class.isAssignableFrom(c)) { Class<? extends TypeQualifierValidator> checkerClass = c.asSubclass(TypeQualifierValidator.class); validator = getValidator(checkerClass); qualifierClass = getQualifierClass(typeQualifier); InvocationHandler handler = new InvocationHandler() { public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { if (arg1.getName() == "value") return TypeQualifierValue.this.value; throw new UnsupportedOperationException("Can't handle " + arg1); } }; proxy = qualifierClass.cast( Proxy.newProxyInstance(validatorLoader, new Class[] {qualifierClass}, handler)); } } catch (ClassNotFoundException e) { assert true; // ignore } catch (CheckedAnalysisException e) { assert true; // ignore } catch (Exception e) { AnalysisContext.logError("Unable to construct type qualifier checker " + checkerName, e); } catch (Throwable e) { AnalysisContext.logError( "Unable to construct type qualifier checker " + checkerName + " due to " + e.getClass().getSimpleName() + ":" + e.getMessage()); } this.validator = validator; this.typeQualifierClass = qualifierClass; this.proxy = proxy; }
/** * @param typeQualifier * @return * @throws ClassNotFoundException */ @SuppressWarnings("unchecked") private Class<A> getQualifierClass(ClassDescriptor typeQualifier) throws ClassNotFoundException { return (Class<A>) validatorLoader.loadClass(typeQualifier.getDottedClassName()); }