public static String getOrGuessSourceFile(SourceLineAnnotation source) { if (source.isSourceFileKnown()) return source.getSourceFile(); String baseClassName = source.getClassName(); int i = baseClassName.lastIndexOf('.'); baseClassName = baseClassName.substring(i + 1); int j = baseClassName.indexOf("$"); if (j >= 0) baseClassName = baseClassName.substring(0, j); return baseClassName + ".java"; }
private void setAffectedLines(final BugInstance warning, final Bug bug) { Iterator<BugAnnotation> annotationIterator = warning.annotationIterator(); while (annotationIterator.hasNext()) { BugAnnotation bugAnnotation = annotationIterator.next(); if (bugAnnotation instanceof SourceLineAnnotation) { SourceLineAnnotation annotation = (SourceLineAnnotation) bugAnnotation; bug.addLineRange(new LineRange(annotation.getStartLine(), annotation.getEndLine())); } } }
private String findSourceFile( final Project project, final SourceFinder sourceFinder, final SourceLineAnnotation sourceLine) { try { SourceFile sourceFile = sourceFinder.findSourceFile(sourceLine); return sourceFile.getFullFileName(); } catch (IOException exception) { StringBuilder sb = new StringBuilder("Can't resolve absolute file name for file "); sb.append(sourceLine.getSourceFile()); if (isFirstError) { sb.append(", dir list = "); sb.append(project.getSourceDirList()); isFirstError = false; } Logger.getLogger(getClass().getName()).log(Level.WARNING, sb.toString()); return sourceLine.getPackageName().replace(DOT, SLASH) + SLASH + sourceLine.getSourceFile(); } }
private void analyzeMethod( ClassContext classContext, Method method, Collection<InjectionSource> selectedSources) throws DataflowAnalysisException, CheckedAnalysisException { TaintDataflow dataflow = getTaintDataFlow(classContext, method); ConstantPoolGen cpg = classContext.getConstantPoolGen(); String currentMethod = getFullMethodName(classContext.getMethodGen(method)); for (Iterator<Location> i = getLocationIterator(classContext, method); i.hasNext(); ) { Location location = i.next(); InstructionHandle handle = location.getHandle(); Instruction instruction = handle.getInstruction(); if (!(instruction instanceof InvokeInstruction)) { continue; } InvokeInstruction invoke = (InvokeInstruction) instruction; TaintFrame fact = dataflow.getFactAtLocation(location); assert fact != null; if (!fact.isValid()) { continue; } SourceLineAnnotation sourceLine = SourceLineAnnotation.fromVisitedInstruction(classContext, method, handle); checkTaintSink(getFullMethodName(cpg, invoke), fact, sourceLine, currentMethod); InjectionPoint injectionPoint = getInjectionPoint(invoke, cpg, handle, selectedSources); for (int offset : injectionPoint.getInjectableArguments()) { Taint parameterTaint = fact.getStackValue(offset); int priority = getPriority(parameterTaint); if (priority == Priorities.IGNORE_PRIORITY) { continue; } BugInstance bugInstance = new BugInstance(this, injectionPoint.getBugType(), priority); bugInstance.addClassAndMethod(classContext.getJavaClass(), method); bugInstance.addSourceLine(sourceLine); if (injectionPoint.getInjectableMethod() != null) { bugInstance.addString(injectionPoint.getInjectableMethod()); } reportBug(bugInstance, parameterTaint, currentMethod); } } }
private static void addSourceLines(Collection<TaintLocation> locations, BugInstance bugInstance) { List<SourceLineAnnotation> annotations = new LinkedList<SourceLineAnnotation>(); for (TaintLocation location : locations) { SourceLineAnnotation taintSource = SourceLineAnnotation.fromVisitedInstruction( location.getMethodDescriptor(), location.getPosition()); annotations.add(taintSource); } Collections.sort(annotations); SourceLineAnnotation annotation = null; for (Iterator<SourceLineAnnotation> it = annotations.iterator(); it.hasNext(); ) { SourceLineAnnotation prev = annotation; annotation = it.next(); if (prev != null && prev.getClassName().equals(annotation.getClassName()) && prev.getStartLine() == annotation.getStartLine()) { // keep only one annotation per line it.remove(); } } for (SourceLineAnnotation sourceLine : annotations) { bugInstance.addSourceLine(sourceLine); } }
/** * Returns the parsed FindBugs analysis file. This scanner accepts files in the native FindBugs * format. * * @param file the FindBugs analysis file * @param sources a collection of folders to scan for source files * @param moduleName name of maven module * @param hashToMessageMapping mapping of hash codes to messages * @param categories mapping from bug types to their categories * @return the parsed result (stored in the module instance) * @throws IOException if the file could not be parsed * @throws DocumentException in case of a parser exception */ private Collection<FileAnnotation> parse( final InputStream file, final Collection<String> sources, final String moduleName, final Map<String, String> hashToMessageMapping, final Map<String, String> categories) throws IOException, DocumentException { SortedBugCollection collection = readXml(file); Project project = collection.getProject(); for (String sourceFolder : sources) { project.addSourceDir(sourceFolder); } SourceFinder sourceFinder = new SourceFinder(project); String actualName = extractModuleName(moduleName, project); TreeStringBuilder stringPool = new TreeStringBuilder(); List<FileAnnotation> annotations = new ArrayList<FileAnnotation>(); Collection<BugInstance> bugs = collection.getCollection(); for (BugInstance warning : bugs) { SourceLineAnnotation sourceLine = warning.getPrimarySourceLineAnnotation(); String message = warning.getMessage(); String type = warning.getType(); if (message.contains("TEST: Unknown")) { message = FindBugsMessages.getInstance().getShortMessage(type, LocaleProvider.getLocale()); } String category = categories.get(type); if (category == null) { // alternately, only if warning.getBugPattern().getType().equals("UNKNOWN") category = warning.getBugPattern().getCategory(); } Bug bug = new Bug( getPriority(warning), StringUtils.defaultIfEmpty( hashToMessageMapping.get(warning.getInstanceHash()), message), category, type, sourceLine.getStartLine(), sourceLine.getEndLine()); bug.setInstanceHash(warning.getInstanceHash()); bug.setRank(warning.getBugRank()); boolean ignore = setCloudInformation(collection, warning, bug); if (!ignore) { bug.setNotAProblem(false); bug.setFileName(findSourceFile(project, sourceFinder, sourceLine)); bug.setPackageName(warning.getPrimaryClass().getPackageName()); bug.setModuleName(actualName); setAffectedLines(warning, bug); annotations.add(bug); bug.intern(stringPool); } } return applyFilters(annotations); }
/** * implements the visitor to find stores to locals of synchronized collections * * @param seen the opcode of the currently parsed instruction */ @Override public void sawOpcode(int seen) { Integer tosIsSyncColReg = null; try { stack.mergeJumps(this); if (seen == INVOKESPECIAL) { if ("<init>".equals(getNameConstantOperand())) { Integer minVersion = syncCtors.get(getClassConstantOperand()); if ((minVersion != null) && (classVersion >= minVersion.intValue())) { tosIsSyncColReg = Integer.valueOf(-1); } } } else if (seen == INVOKESTATIC) { if ("java/util/Collections".equals(getClassConstantOperand())) { if (syncMethods.contains(getNameConstantOperand())) { tosIsSyncColReg = Integer.valueOf(-1); } } } else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); int reg = RegisterUtils.getAStoreReg(this, seen); if (item.getUserValue() != null) { if (!syncRegs.containsKey(Integer.valueOf(reg))) { CollectionRegInfo cri = new CollectionRegInfo( SourceLineAnnotation.fromVisitedInstruction(this), RegisterUtils.getLocalVariableEndRange( getMethod().getLocalVariableTable(), reg, getNextPC())); syncRegs.put(Integer.valueOf(reg), cri); } } else { CollectionRegInfo cri = syncRegs.get(Integer.valueOf(reg)); if (cri == null) { cri = new CollectionRegInfo( RegisterUtils.getLocalVariableEndRange( getMethod().getLocalVariableTable(), reg, getNextPC())); syncRegs.put(Integer.valueOf(reg), cri); } cri.setIgnore(); } } } else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) { int reg = RegisterUtils.getALoadReg(this, seen); CollectionRegInfo cri = syncRegs.get(Integer.valueOf(reg)); if ((cri != null) && !cri.getIgnore()) tosIsSyncColReg = Integer.valueOf(reg); } else if ((seen == PUTFIELD) || (seen == ARETURN)) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); syncRegs.remove(item.getUserValue()); } } if (syncRegs.size() > 0) { if ((seen == INVOKESPECIAL) || (seen == INVOKEINTERFACE) || (seen == INVOKEVIRTUAL) || (seen == INVOKESTATIC)) { String sig = getSigConstantOperand(); int argCount = Type.getArgumentTypes(sig).length; if (stack.getStackDepth() >= argCount) { for (int i = 0; i < argCount; i++) { OpcodeStack.Item item = stack.getStackItem(i); CollectionRegInfo cri = syncRegs.get(item.getUserValue()); if (cri != null) cri.setPriority(LOW_PRIORITY); } } } else if (seen == MONITORENTER) { // Assume if synchronized blocks are used then something tricky is going on. // There is really no valid reason for this, other than folks who use // synchronized blocks tend to know what's going on. if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); syncRegs.remove(item.getUserValue()); } } else if (seen == AASTORE) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); syncRegs.remove(item.getUserValue()); } } } int curPC = getPC(); Iterator<CollectionRegInfo> it = syncRegs.values().iterator(); while (it.hasNext()) { CollectionRegInfo cri = it.next(); if (cri.getEndPCRange() < curPC) { if (!cri.getIgnore()) { bugReporter.reportBug( new BugInstance(this, "LSYC_LOCAL_SYNCHRONIZED_COLLECTION", cri.getPriority()) .addClass(this) .addMethod(this) .addSourceLine(cri.getSourceLineAnnotation())); } it.remove(); } } } finally { TernaryPatcher.pre(stack, seen); stack.sawOpcode(this, seen); TernaryPatcher.post(stack, seen); if (tosIsSyncColReg != null) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); item.setUserValue(tosIsSyncColReg); } } } }
public static List<ErrorDescription> runFindBugs( CompilationInfo info, Preferences customSettings, String singleBug, FileObject sourceRoot, Iterable<? extends String> classNames, FindBugsProgress progress, SigFilesValidator validator) { List<ErrorDescription> result = new ArrayList<ErrorDescription>(); try { Class.forName( "org.netbeans.modules.findbugs.NbClassFactory", true, RunFindBugs.class.getClassLoader()); // NOI18N Project p = new Project(); URL[] binaryRoots = CacheBinaryForSourceQuery.findCacheBinaryRoots(sourceRoot.toURL()).getRoots(); if (classNames == null) { for (URL binary : binaryRoots) { try { p.addFile(new File(binary.toURI()).getAbsolutePath()); } catch (URISyntaxException ex) { Exceptions.printStackTrace(ex); } } } else { ClassPath binary = ClassPathSupport.createClassPath(binaryRoots); List<FileObject> sigFiles = new ArrayList<FileObject>(); for (String className : classNames) { FileObject classFO = binary.findResource(className.replace('.', '/') + ".sig"); // NOI18N if (classFO != null) { sigFiles.add(classFO); } else { LOG.log( Level.WARNING, "Cannot find sig file for: " + className); // TODO: should probably become FINE eventually } } assert validator != null; if (!validator.validate(sigFiles)) return null; for (FileObject classFO : sigFiles) { p.addFile(new File(classFO.toURI()).getAbsolutePath()); } addCompileRootAsSource(p, sourceRoot); } ClassPath compile = ClassPath.getClassPath(sourceRoot, ClassPath.COMPILE); for (FileObject compileRoot : compile.getRoots()) { addCompileRoot(p, compileRoot); } BugCollectionBugReporter r = new BugCollectionBugReporter(p) { @Override protected void emitLine(String line) { LOG.log(Level.FINE, line); } }; r.setPriorityThreshold(Integer.MAX_VALUE); r.setRankThreshold(Integer.MAX_VALUE); FindBugs2 engine = new FindBugs2(); engine.setProject(p); engine.setNoClassOk(true); engine.setBugReporter(r); if (progress != null) { engine.setProgressCallback(progress); } boolean inEditor = validator != null; Preferences settings = customSettings != null ? customSettings : NbPreferences.forModule(RunFindBugs.class).node("global-settings"); UserPreferences preferences; if (singleBug != null) { singleBug = singleBug.substring(PREFIX_FINDBUGS.length()); preferences = forSingleBug(singleBug); } else { preferences = readPreferences(settings, customSettings != null); } if (preferences == null) { // nothing enabled, stop return result; } engine.setUserPreferences(preferences); engine.setDetectorFactoryCollection(DetectorFactoryCollection.instance()); LOG.log(Level.FINE, "Running FindBugs"); engine.execute(); Map<FileObject, List<BugInstance>> file2Bugs = new HashMap<FileObject, List<BugInstance>>(); for (BugInstance b : r.getBugCollection().getCollection()) { if (singleBug != null && !singleBug.equals(b.getBugPattern().getType())) continue; if (singleBug == null && !settings.getBoolean( b.getBugPattern().getType(), customSettings == null && isEnabledByDefault(b.getBugPattern()))) { continue; } SourceLineAnnotation sourceLine = b.getPrimarySourceLineAnnotation(); FileObject sourceFile = null; if (sourceLine != null) { sourceFile = sourceRoot.getFileObject(sourceLine.getSourcePath()); if (sourceFile != null) { List<BugInstance> bugs = file2Bugs.get(sourceFile); if (bugs == null) { file2Bugs.put(sourceFile, bugs = new ArrayList<BugInstance>()); } bugs.add(b); } else { LOG.log( Level.WARNING, "{0}, location: {1}:{2}", new Object[] {b, sourceLine.getSourcePath(), sourceLine.getStartLine()}); } } } for (Entry<FileObject, List<BugInstance>> e : file2Bugs.entrySet()) { int[] lineOffsets = null; FileObject sourceFile = e.getKey(); DataObject d = DataObject.find(sourceFile); EditorCookie ec = d.getLookup().lookup(EditorCookie.class); Document doc = ec.getDocument(); JavaSource js = null; for (BugInstance b : e.getValue()) { SourceLineAnnotation sourceLine = b.getPrimarySourceLineAnnotation(); if (sourceLine.getStartLine() >= 0) { LazyFixList fixes = prepareFixes(b, inEditor, sourceFile, sourceLine.getStartLine(), null); if (doc != null) { result.add( ErrorDescriptionFactory.createErrorDescription( PREFIX_FINDBUGS + b.getType(), Severity.VERIFIER, b.getMessageWithoutPrefix(), b.getBugPattern().getDetailHTML(), fixes, doc, sourceLine.getStartLine())); } else { if (lineOffsets == null) { lineOffsets = computeLineMap(sourceFile, FileEncodingQuery.getEncoding(sourceFile)); } int edLine = 2 * (Math.min(sourceLine.getStartLine(), lineOffsets.length / 2) - 1); result.add( ErrorDescriptionFactory.createErrorDescription( PREFIX_FINDBUGS + b.getType(), Severity.VERIFIER, b.getMessageWithoutPrefix(), b.getBugPattern().getDetailHTML(), fixes, sourceFile, lineOffsets[edLine], lineOffsets[edLine + 1])); } } else { if (js == null) { js = JavaSource.forFileObject(sourceFile); } addByElementAnnotation(b, info, sourceFile, js, result, inEditor); } } } } catch (ClassNotFoundException ex) { Exceptions.printStackTrace(ex); } catch (IOException ex) { Exceptions.printStackTrace(ex); } catch (InterruptedException ex) { LOG.log(Level.FINE, null, ex); } return result; }
public boolean hasSourceFile(SourceLineAnnotation source) { return hasSourceFile(source.getPackageName(), getOrGuessSourceFile(source)); }
public static String getCanonicalName(SourceLineAnnotation source) { return getCanonicalName(source.getPackageName(), getOrGuessSourceFile(source)); }
public SourceFile findSourceFile(SourceLineAnnotation source) throws IOException { return findSourceFile(source.getPackageName(), getOrGuessSourceFile(source)); }
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(); }