private List<String> findFullyQualifiedSourceFileNames( IClassPathBuilder builder, IClassPath classPath) { List<ClassDescriptor> appClassList = builder.getAppClassList(); progress.startScanningClasses(appClassList.size()); List<String> fullyQualifiedSourceFileNameList = new LinkedList<String>(); for (ClassDescriptor classDesc : appClassList) { try { String fullyQualifiedSourceFileName = findFullyQualifiedSourceFileName(classPath, classDesc); fullyQualifiedSourceFileNameList.add(fullyQualifiedSourceFileName); } catch (IOException e) { errorLogger.logError("Couldn't scan class " + classDesc.toDottedClassName(), e); } catch (CheckedAnalysisException e) { errorLogger.logError("Couldn't scan class " + classDesc.toDottedClassName(), e); } } progress.doneScanningClasses(); return fullyQualifiedSourceFileNameList; }
private String findFullyQualifiedSourceFileName(IClassPath classPath, ClassDescriptor classDesc) throws IOException, CheckedAnalysisException { try { // Open and parse the class file to attempt // to discover the source file name. ICodeBaseEntry codeBaseEntry = classPath.lookupResource(classDesc.toResourceName()); ClassParserUsingASM classParser = new ClassParserUsingASM( new ClassReader(codeBaseEntry.openResource()), classDesc, codeBaseEntry); ClassInfo.Builder classInfoBuilder = new ClassInfo.Builder(); classParser.parse(classInfoBuilder); ClassInfo classInfo = classInfoBuilder.build(); // Construct the fully-qualified source file name // based on the package name and source file name. String packageName = classDesc.getPackageName(); String sourceFile = classInfo.getSource(); if (!packageName.equals("")) { packageName = packageName.replace('.', '/'); packageName += "/"; } String fullyQualifiedSourceFile = packageName + sourceFile; return fullyQualifiedSourceFile; } catch (CheckedAnalysisException e) { errorLogger.logError("Could scan class " + classDesc.toDottedClassName(), e); throw e; } finally { progress.finishClass(); } }
/* (non-Javadoc) * @see edu.umd.cs.findbugs.ba.INullnessAnnotationDatabase#addDefaultAnnotation(java.lang.String, java.lang.String, edu.umd.cs.findbugs.ba.NullnessAnnotation) */ public void addDefaultAnnotation(Target target, String c, NullnessAnnotation n) { if (DEBUG) { System.out.println("addDefaultAnnotation: target=" + target + ", c=" + c + ", n=" + n); } ClassDescriptor classDesc = DescriptorFactory.instance().getClassDescriptorForDottedClassName(c); ClassInfo xclass; // Get the XClass (really a ClassInfo object) try { xclass = (ClassInfo) Global.getAnalysisCache().getClassAnalysis(XClass.class, classDesc); } catch (MissingClassException e) { // // AnalysisContext.currentAnalysisContext().getLookupFailureCallback().reportMissingClass(e.getClassDescriptor()); return; } catch (CheckedAnalysisException e) { // AnalysisContext.logError("Error adding built-in nullness annotation", e); return; } if (n == NullnessAnnotation.NONNULL && target == AnnotationDatabase.Target.PARAMETER) { xclass.addAnnotation(new AnnotationValue(PARAMETERS_ARE_NONNULL_BY_DEFAULT)); return; } else if (n == NullnessAnnotation.NONNULL && target == AnnotationDatabase.Target.METHOD) { xclass.addAnnotation(new AnnotationValue(RETURN_VALUES_ARE_NONNULL_BY_DEFAULT)); return; } // Get the default annotation type ClassDescriptor defaultAnnotationType; if (target == AnnotationDatabase.Target.ANY) { defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION; } else if (target == AnnotationDatabase.Target.FIELD) { defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION_FOR_FIELDS; } else if (target == AnnotationDatabase.Target.METHOD) { defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION_FOR_METHODS; } else if (target == AnnotationDatabase.Target.PARAMETER) { defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION_FOR_PARAMETERS; } else { throw new IllegalArgumentException("Unknown target for default annotation: " + target); } // Get the JSR-305 nullness annotation type ClassDescriptor nullnessAnnotationType = getNullnessAnnotationClassDescriptor(n); // Construct an AnnotationValue containing the default annotation AnnotationValue annotationValue = new AnnotationValue(defaultAnnotationType); AnnotationVisitor v = annotationValue.getAnnotationVisitor(); v.visit("value", Type.getObjectType(nullnessAnnotationType.getClassName())); v.visitEnd(); if (DEBUG) { System.out.println("Adding AnnotationValue " + annotationValue + " to class " + xclass); } // Destructively add the annotation to the ClassInfo object xclass.addAnnotation(annotationValue); }
/* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(typeQualifier.toString()); if (value != null) { buf.append(':'); buf.append(value.toString()); } return buf.toString(); }
/* (non-Javadoc) * @see edu.umd.cs.findbugs.classfile.IErrorLogger#reportMissingClass(edu.umd.cs.findbugs.classfile.ClassDescriptor) */ public void reportMissingClass(ClassDescriptor classDescriptor) { if (DEBUG_MISSING_CLASSES) { System.out.println("Missing class: " + classDescriptor); new Throwable().printStackTrace(System.out); } if (verbosityLevel == SILENT) { return; } logMissingClass(classDescriptor.toDottedClassName()); }
/** * Find a method in given class. * * @param classDesc the class descriptor * @param methodName the name of the method * @param methodSig the signature of the method * @param isStatic are we looking for a static method? * @return the JavaClassAndMethod, or null if no such method exists in the class */ public static @CheckForNull XMethod findMethod( ClassDescriptor classDesc, String methodName, String methodSig, boolean isStatic) { if (DEBUG_METHOD_LOOKUP) { System.out.println("Check " + classDesc.getClassName()); } try { XClass xClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, classDesc); return xClass.findMethod(methodName, methodSig, isStatic); } catch (CheckedAnalysisException e) { AnalysisContext.logError("Error looking for " + classDesc + "." + methodName + methodSig, e); return null; } }
private boolean isJunit3TestCase(XClass jClass) throws ClassNotFoundException { ClassDescriptor sDesc = jClass.getSuperclassDescriptor(); if (sDesc == null) { return false; } String sName = sDesc.getClassName(); if (sName.equals("junit/framework/TestCase")) { return true; } if (sName.equals("java/lang/Object")) { return false; } try { XClass sClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, sDesc); if (sClass == null) { return false; } return isJunit3TestCase(sClass); } catch (CheckedAnalysisException e) { return false; } }
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); } }
@Override public void visit(Method obj) { int accessFlags = obj.getAccessFlags(); boolean isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0; if (getMethodName().equals("<init>") && getMethodSig().equals("()V") && (accessFlags & ACC_PUBLIC) != 0) hasPublicVoidConstructor = true; if (!getMethodName().equals("<init>") && isSynthetic(obj)) foundSynthetic = true; // System.out.println(methodName + isSynchronized); if (getMethodName().equals("readExternal") && getMethodSig().equals("(Ljava/io/ObjectInput;)V")) { sawReadExternal = true; if (DEBUG && !obj.isPrivate()) System.out.println("Non-private readExternal method in: " + getDottedClassName()); } else if (getMethodName().equals("writeExternal") && getMethodSig().equals("(Ljava/io/Objectoutput;)V")) { sawWriteExternal = true; if (DEBUG && !obj.isPrivate()) System.out.println("Non-private writeExternal method in: " + getDottedClassName()); } else if (getMethodName().equals("readResolve") && getMethodSig().startsWith("()") && isSerializable) { sawReadResolve = true; if (!getMethodSig().equals("()Ljava/lang/Object;")) bugReporter.reportBug( new BugInstance(this, "SE_READ_RESOLVE_MUST_RETURN_OBJECT", HIGH_PRIORITY) .addClassAndMethod(this)); else if (obj.isStatic()) bugReporter.reportBug( new BugInstance(this, "SE_READ_RESOLVE_IS_STATIC", HIGH_PRIORITY) .addClassAndMethod(this)); else if (obj.isPrivate()) try { Set<ClassDescriptor> subtypes = AnalysisContext.currentAnalysisContext() .getSubtypes2() .getSubtypes(getClassDescriptor()); if (subtypes.size() > 1) { BugInstance bug = new BugInstance(this, "SE_PRIVATE_READ_RESOLVE_NOT_INHERITED", NORMAL_PRIORITY) .addClassAndMethod(this); boolean nasty = false; for (ClassDescriptor subclass : subtypes) if (!subclass.equals(getClassDescriptor())) { XClass xSub = AnalysisContext.currentXFactory().getXClass(subclass); if (xSub != null && xSub.findMethod("readResolve", "()Ljava/lang/Object;", false) == null && xSub.findMethod("writeReplace", "()Ljava/lang/Object;", false) == null) { bug.addClass(subclass).describe(ClassAnnotation.SUBCLASS_ROLE); nasty = true; } } if (nasty) bug.setPriority(HIGH_PRIORITY); else if (!getThisClass().isPublic()) bug.setPriority(LOW_PRIORITY); bugReporter.reportBug(bug); } } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } } else if (getMethodName().equals("readObject") && getMethodSig().equals("(Ljava/io/ObjectInputStream;)V") && isSerializable) { sawReadObject = true; if (!obj.isPrivate()) bugReporter.reportBug( new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY) .addClassAndMethod(this)); } else if (getMethodName().equals("readObjectNoData") && getMethodSig().equals("()V") && isSerializable) { if (!obj.isPrivate()) bugReporter.reportBug( new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY) .addClassAndMethod(this)); } else if (getMethodName().equals("writeObject") && getMethodSig().equals("(Ljava/io/ObjectOutputStream;)V") && isSerializable) { sawWriteObject = true; if (!obj.isPrivate()) bugReporter.reportBug( new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY) .addClassAndMethod(this)); } if (isSynchronized) { if (getMethodName().equals("readObject") && getMethodSig().equals("(Ljava/io/ObjectInputStream;)V") && isSerializable) bugReporter.reportBug( new BugInstance(this, "RS_READOBJECT_SYNC", NORMAL_PRIORITY).addClass(this)); else if (getMethodName().equals("writeObject") && getMethodSig().equals("(Ljava/io/ObjectOutputStream;)V") && isSerializable) writeObjectIsSynchronized = true; else foundSynchronizedMethods = true; } super.visit(obj); }
/** * Throw a ClassNotFoundException to indicate that class named by given ClassDescriptor cannot be * found. The exception message is formatted in a way that can be decoded by * ClassNotFoundExceptionParser. * * @param classDescriptor ClassDescriptor naming a class that cannot be found * @throws ClassNotFoundException * @see edu.umd.cs.findbugs.ba.ClassNotFoundExceptionParser * @deprecated Use {@link ClassDescriptor#throwClassNotFoundException(ClassDescriptor)} instead */ @Deprecated public static void throwClassNotFoundException(ClassDescriptor classDescriptor) throws ClassNotFoundException { ClassDescriptor.throwClassNotFoundException(classDescriptor); }
@Override public int hashCode() { int result = typeQualifier.hashCode(); if (value != null) result += 37 * value.hashCode(); return result; }
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 void analyzeMethod(ClassContext classContext, Method method) throws CFGBuilderException, DataflowAnalysisException { if (isSynthetic(method) || !prescreen(classContext, method)) return; XMethod xmethod = XFactory.createXMethod(classContext.getJavaClass(), method); if (xmethod.isSynthetic()) return; BugAccumulator accumulator = new BugAccumulator(bugReporter); CFG cfg = classContext.getCFG(method); TypeDataflow typeDataflow = classContext.getTypeDataflow(method); ValueNumberDataflow vnDataflow = classContext.getValueNumberDataflow(method); ConstantPoolGen cpg = classContext.getConstantPoolGen(); MethodGen methodGen = classContext.getMethodGen(method); if (methodGen == null) return; String fullMethodName = methodGen.getClassName() + "." + methodGen.getName(); String sourceFile = classContext.getJavaClass().getSourceFileName(); if (DEBUG) { System.out.println("\n" + fullMethodName); } // Process each instruction for (Iterator<Location> iter = cfg.locationIterator(); iter.hasNext(); ) { Location location = iter.next(); InstructionHandle handle = location.getHandle(); Instruction ins = handle.getInstruction(); // Only consider invoke instructions if (!(ins instanceof InvokeInstruction)) continue; InvokeInstruction inv = (InvokeInstruction) ins; XMethod invokedMethod = XFactory.createXMethod(inv, cpg); String invokedMethodName = invokedMethod.getName(); String argSignature = invokedMethod.getSignature(); argSignature = argSignature.substring(0, argSignature.indexOf(')') + 1); String call = invokedMethodName + argSignature; SignatureParser sigParser = new SignatureParser(inv.getSignature(cpg)); Collection<Info> collection = callMap.get(call); if (!callMap.containsKey(call)) continue; for (Info info : collection) { Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2(); if (DEBUG) System.out.println( "at " + handle.getPosition() + " Checking call to " + info.interfaceForCall + " : " + invokedMethod); try { if (!subtypes2.isSubtype(invokedMethod.getClassDescriptor(), info.interfaceForCall)) continue; } catch (ClassNotFoundException e) { if (info.interfaceForCall.getClassName().equals("java/util/Collection") && invokedMethod.getClassName().equals("com.google.common.collect.Multiset")) { assert true; // we know this is OK without needing to find definition of Multiset } else { AnalysisContext.reportMissingClass(e); continue; } } boolean allMethod; int typeArgument; if (info.typeIndex >= 0) { allMethod = false; typeArgument = info.typeIndex; } else { allMethod = true; typeArgument = -(1 + info.typeIndex); } int pos = info.argumentIndex; int lhsPos; if (inv instanceof INVOKESTATIC) lhsPos = sigParser.getSlotsFromTopOfStackForParameter(0); else lhsPos = sigParser.getTotalArgumentSize(); int stackPos = sigParser.getSlotsFromTopOfStackForParameter(pos); TypeFrame frame = typeDataflow.getFactAtLocation(location); if (!frame.isValid()) { // This basic block is probably dead continue; } Type operandType = frame.getStackValue(stackPos); if (operandType.equals(TopType.instance())) { // unreachable continue; } if (operandType.equals(NullType.instance())) { // ignore continue; } ValueNumberFrame vnFrame = vnDataflow.getFactAtLocation(location); if (!vnFrame.isValid()) { AnalysisContext.logError("Invalid value number frame in " + xmethod); continue; } ValueNumber objectVN = vnFrame.getStackValue(lhsPos); ValueNumber argVN = vnFrame.getStackValue(stackPos); if (objectVN.equals(argVN)) { String bugPattern = "DMI_COLLECTIONS_SHOULD_NOT_CONTAIN_THEMSELVES"; int priority = HIGH_PRIORITY; if (invokedMethodName.equals("removeAll")) { bugPattern = "DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION"; priority = NORMAL_PRIORITY; } else if (invokedMethodName.endsWith("All")) { bugPattern = "DMI_VACUOUS_SELF_COLLECTION_CALL"; priority = NORMAL_PRIORITY; } if (invokedMethodName.startsWith("contains")) { InstructionHandle next = handle.getNext(); if (next != null) { Instruction nextIns = next.getInstruction(); if (nextIns instanceof InvokeInstruction) { XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg); if (nextMethod.getName().equals("assertFalse")) continue; } } } accumulator.accumulateBug( new BugInstance(this, bugPattern, priority) .addClassAndMethod(methodGen, sourceFile) .addCalledMethod(methodGen, (InvokeInstruction) ins) .addOptionalAnnotation( ValueNumberSourceInfo.findAnnotationFromValueNumber( method, location, objectVN, vnFrame, "INVOKED_ON")), SourceLineAnnotation.fromVisitedInstruction( classContext, methodGen, sourceFile, handle)); } // Only consider generic... Type objectType = frame.getStackValue(lhsPos); if (!(objectType instanceof GenericObjectType)) continue; GenericObjectType operand = (GenericObjectType) objectType; int expectedTypeParameters = 1; String simpleName = info.interfaceForCall.getSimpleName(); if (simpleName.toLowerCase().endsWith("map") || simpleName.equals("Hashtable")) expectedTypeParameters = 2; else if (simpleName.equals("Table")) expectedTypeParameters = 3; // ... containers if (!operand.hasParameters()) continue; if (operand.getNumParameters() != expectedTypeParameters) continue; ClassDescriptor operandClass = DescriptorFactory.getClassDescriptor(operand); if (!isGenericCollection(operandClass)) continue; if (expectedTypeParameters == 2 && Subtypes2.instanceOf(operandClass, Map.class) && !TypeFrameModelingVisitor.isStraightGenericMap(operandClass)) continue; Type expectedType; if (allMethod) expectedType = operand; else expectedType = operand.getParameterAt(typeArgument); Type actualType = frame.getStackValue(stackPos); Type equalsType = actualType; if (allMethod) { if (!(actualType instanceof GenericObjectType)) { continue; } equalsType = ((GenericObjectType) actualType).getParameterAt(typeArgument); } IncompatibleTypes matchResult = compareTypes(expectedType, actualType, allMethod); boolean parmIsObject = expectedType.getSignature().equals("Ljava/lang/Object;"); boolean selfOperation = !allMethod && operand.equals(actualType) && !parmIsObject; if (!allMethod && !parmIsObject && actualType instanceof GenericObjectType) { GenericObjectType p2 = (GenericObjectType) actualType; List<? extends ReferenceType> parameters = p2.getParameters(); if (parameters != null && parameters.equals(operand.getParameters())) selfOperation = true; } if (!selfOperation && (matchResult == IncompatibleTypes.SEEMS_OK || matchResult.getPriority() == Priorities.IGNORE_PRIORITY)) continue; if (invokedMethodName.startsWith("contains") || invokedMethodName.equals("remove")) { InstructionHandle next = handle.getNext(); if (next != null) { Instruction nextIns = next.getInstruction(); if (nextIns instanceof InvokeInstruction) { XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg); if (nextMethod.getName().equals("assertFalse")) continue; } } } else if (invokedMethodName.equals("get") || invokedMethodName.equals("remove")) { InstructionHandle next = handle.getNext(); if (next != null) { Instruction nextIns = next.getInstruction(); if (nextIns instanceof InvokeInstruction) { XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg); if (nextMethod.getName().equals("assertNull")) continue; } } } boolean noisy = false; if (invokedMethodName.equals("get")) { UnconditionalValueDerefDataflow unconditionalValueDerefDataflow = classContext.getUnconditionalValueDerefDataflow(method); UnconditionalValueDerefSet unconditionalDeref = unconditionalValueDerefDataflow.getFactAtLocation(location); ValueNumberFrame vnAfter = vnDataflow.getFactAfterLocation(location); ValueNumber top = vnAfter.getTopValue(); noisy = unconditionalDeref.getValueNumbersThatAreUnconditionallyDereferenced().contains(top); } // Prepare bug report SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation.fromVisitedInstruction( classContext, methodGen, sourceFile, handle); // Report a bug that mentions each of the failed arguments in // matches if (expectedType instanceof GenericObjectType) expectedType = ((GenericObjectType) expectedType).getUpperBound(); int priority = matchResult.getPriority(); if (!operandClass.getClassName().startsWith("java/util") && priority == Priorities.HIGH_PRIORITY) priority = Math.max(priority, Priorities.NORMAL_PRIORITY); if (TestCaseDetector.likelyTestCase(xmethod)) priority = Math.max(priority, Priorities.NORMAL_PRIORITY); else if (selfOperation) priority = Priorities.HIGH_PRIORITY; ClassDescriptor expectedClassDescriptor = DescriptorFactory.createClassOrObjectDescriptorFromSignature( expectedType.getSignature()); ClassDescriptor actualClassDescriptor = DescriptorFactory.createClassOrObjectDescriptorFromSignature(equalsType.getSignature()); ClassSummary classSummary = AnalysisContext.currentAnalysisContext().getClassSummary(); Set<XMethod> targets = null; try { targets = Hierarchy2.resolveVirtualMethodCallTargets( actualClassDescriptor, "equals", "(Ljava/lang/Object;)Z", false, false); boolean allOk = targets.size() > 0; for (XMethod m2 : targets) if (!classSummary.mightBeEqualTo(m2.getClassDescriptor(), expectedClassDescriptor)) allOk = false; if (allOk) priority += 2; } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } String bugPattern = "GC_UNRELATED_TYPES"; BugInstance bug = new BugInstance(this, bugPattern, priority) .addClassAndMethod(methodGen, sourceFile) .addFoundAndExpectedType(actualType, expectedType) .addCalledMethod(methodGen, (InvokeInstruction) ins) .addOptionalAnnotation( ValueNumberSourceInfo.findAnnotationFromValueNumber( method, location, objectVN, vnFrame, "INVOKED_ON")) .addOptionalAnnotation( ValueNumberSourceInfo.findAnnotationFromValueNumber( method, location, argVN, vnFrame, "ARGUMENT")) .addEqualsMethodUsed(targets); if (noisy) { WarningPropertySet<WarningProperty> propertySet = new WarningPropertySet<WarningProperty>(); propertySet.addProperty(GeneralWarningProperty.NOISY_BUG); propertySet.decorateBugInstance(bug); } accumulator.accumulateBug(bug, sourceLineAnnotation); } } accumulator.reportAccumulatedBugs(); }
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; }
@Override public boolean equals(Object o) { if (!(o instanceof TypeQualifierValue)) return false; TypeQualifierValue other = (TypeQualifierValue) o; return typeQualifier.equals(other.typeQualifier) && Util.nullSafeEquals(value, other.value); }
/** * Lookup a class. <em>Use this method instead of Repository.lookupClass().</em> * * @param classDescriptor descriptor specifying the class to look up * @return the class * @throws ClassNotFoundException if the class can't be found */ public JavaClass lookupClass(@Nonnull ClassDescriptor classDescriptor) throws ClassNotFoundException { return lookupClass(classDescriptor.toDottedClassName()); }
/** * @param typeQualifier * @return * @throws ClassNotFoundException */ @SuppressWarnings("unchecked") private Class<A> getQualifierClass(ClassDescriptor typeQualifier) throws ClassNotFoundException { return (Class<A>) validatorLoader.loadClass(typeQualifier.getDottedClassName()); }