Пример #1
0
  @Override
  public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, LockSet fact)
      throws DataflowAnalysisException {

    Instruction ins = handle.getInstruction();
    short opcode = ins.getOpcode();
    if (opcode == Constants.MONITORENTER || opcode == Constants.MONITOREXIT) {
      ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock));

      modifyLock(frame, fact, opcode == Constants.MONITORENTER ? 1 : -1);

    } else if (opcode == Constants.INVOKEVIRTUAL || opcode == Constants.INVOKEINTERFACE) {

      InvokeInstruction inv = (InvokeInstruction) ins;
      String name = inv.getMethodName(methodGen.getConstantPool());
      String sig = inv.getSignature(methodGen.getConstantPool());
      ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock));

      if ("()V".equals(sig) && ("lock".equals(name) || "lockInterruptibly".equals(name))) {
        modifyLock(frame, fact, 1);
      } else if ("()V".equals(sig) && ("unlock".equals(name))) {
        modifyLock(frame, fact, -1);
      }

    } else if ((ins instanceof ReturnInstruction) && isSynchronized && !isStatic) {

      lockOp(fact, vna.getThisValue().getNumber(), -1);
    }
  }
  /**
   * @param classContext
   * @param method
   */
  private void analyzeMethod(ClassContext classContext, Method method)
      throws MethodUnprofitableException, CFGBuilderException, DataflowAnalysisException {
    if (method.isSynthetic()
        || (method.getAccessFlags() & Constants.ACC_BRIDGE) == Constants.ACC_BRIDGE) return;
    CFG cfg = classContext.getCFG(method);
    TypeDataflow typeDataflow = classContext.getTypeDataflow(method);
    ConstantPoolGen constantPoolGen = classContext.getConstantPoolGen();

    locationLoop:
    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;
      if (ins instanceof INVOKEINTERFACE) continue;

      InvokeInstruction inv = (InvokeInstruction) ins;
      TypeFrame frame = typeDataflow.getFactAtLocation(location);

      String methodName = inv.getMethodName(constantPoolGen);
      if (methodName.toLowerCase().indexOf("unsupported") >= 0) continue;
      String methodSig = inv.getSignature(constantPoolGen);
      if (methodSig.equals("()Ljava/lang/UnsupportedOperationException;")) continue;

      Set<XMethod> targets;
      try {

        targets = Hierarchy2.resolveMethodCallTargets(inv, frame, constantPoolGen);
      } catch (ClassNotFoundException e) {
        AnalysisContext.reportMissingClass(e);
        continue locationLoop;
      }
      if (targets.isEmpty()) continue locationLoop;
      int priority = targets.size() == 1 ? Priorities.HIGH_PRIORITY : Priorities.NORMAL_PRIORITY;
      for (XMethod m : targets) {
        if (!m.isUnsupported()) continue locationLoop;
        XClass xc = AnalysisContext.currentXFactory().getXClass(m.getClassDescriptor());
        if (!(inv instanceof INVOKESTATIC) && !(m.isFinal() || xc.isFinal()))
          priority = Priorities.NORMAL_PRIORITY;
        if (xc == null || xc.isAbstract()) {
          try {
            if (!AnalysisContext.currentAnalysisContext()
                .getSubtypes2()
                .hasSubtypes(m.getClassDescriptor())) continue locationLoop;
          } catch (ClassNotFoundException e) {
            AnalysisContext.reportMissingClass(e);
            continue locationLoop;
          }
        }
      }
      BugInstance bug =
          new BugInstance(this, "DMI_UNSUPPORTED_METHOD", priority)
              .addClassAndMethod(classContext.getJavaClass(), method)
              .addCalledMethod(constantPoolGen, inv)
              .addSourceLine(classContext, method, location);
      bugReporter.reportBug(bug);
    }
  }
 private TaintMethodSummary getMethodSummary(InvokeInstruction obj) {
   String methodNameWithSig = obj.getMethodName(cpg) + obj.getSignature(cpg);
   String fullMethodName = getSlashedClassName(obj) + "." + methodNameWithSig;
   TaintMethodSummary methodSummary = methodSummaries.get(fullMethodName);
   if (methodSummary == null && TO_STRING_METHOD.equals(methodNameWithSig)) {
     methodSummary = TaintMethodSummary.getDefaultToStringSummary();
   }
   return methodSummary;
 }
  /**
   * Look up the method referenced by given InvokeInstruction. This method does <em>not</em> look
   * for implementations in super or subclasses according to the virtual dispatch rules.
   *
   * @param inv the InvokeInstruction
   * @param cpg the ConstantPoolGen used by the class the InvokeInstruction belongs to
   * @param chooser JavaClassAndMethodChooser to use to pick the method from among the candidates
   * @return the JavaClassAndMethod, or null if no such method is defined in the class
   */
  public static JavaClassAndMethod findExactMethod(
      InvokeInstruction inv, ConstantPoolGen cpg, JavaClassAndMethodChooser chooser)
      throws ClassNotFoundException {
    String className = inv.getClassName(cpg);
    String methodName = inv.getName(cpg);
    String methodSig = inv.getSignature(cpg);

    JavaClass jclass = Repository.lookupClass(className);
    return findMethod(jclass, methodName, methodSig, chooser);
  }
  /**
   * Determine if given Instruction is a monitor wait.
   *
   * @param ins the Instruction
   * @param cpg the ConstantPoolGen for the Instruction
   * @return true if the instruction is a monitor wait, false if not
   */
  public static boolean isMonitorNotify(Instruction ins, ConstantPoolGen cpg) {
    if (!(ins instanceof InvokeInstruction)) return false;
    if (ins.getOpcode() == Constants.INVOKESTATIC) return false;

    InvokeInstruction inv = (InvokeInstruction) ins;
    String methodName = inv.getMethodName(cpg);
    String methodSig = inv.getSignature(cpg);

    return isMonitorNotify(methodName, methodSig);
  }
Пример #6
0
  /**
   * Get a MethodDescriptor describing the method called by given InvokeInstruction.
   *
   * @param inv the InvokeInstruction
   * @param cpg ConstantPoolGen of class containing instruction
   * @return MethodDescriptor describing the called method
   */
  public static MethodDescriptor getCalledMethodDescriptor(
      InvokeInstruction inv, ConstantPoolGen cpg) {
    String calledClassName = inv.getClassName(cpg).replace('.', '/');
    String calledMethodName = inv.getMethodName(cpg);
    String calledMethodSig = inv.getSignature(cpg);
    boolean isStatic = inv.getOpcode() == Constants.INVOKESTATIC;

    return DescriptorFactory.instance()
        .getMethodDescriptor(calledClassName, calledMethodName, calledMethodSig, isStatic);
  }
Пример #7
0
  public static boolean mightCloseStream(
      BasicBlock basicBlock, InstructionHandle handle, ConstantPoolGen cpg) {

    Instruction ins = handle.getInstruction();

    if ((ins instanceof INVOKEVIRTUAL) || (ins instanceof INVOKEINTERFACE)) {
      // Does this instruction close the stream?
      InvokeInstruction inv = (InvokeInstruction) ins;

      // It's a close if the invoked class is any subtype of the stream
      // base class.
      // (Basically, we may not see the exact original stream class,
      // even though it's the same instance.)

      return inv.getName(cpg).equals("close") && inv.getSignature(cpg).equals("()V");
    }

    return false;
  }
  public static @CheckForNull JavaClassAndMethod findInvocationLeastUpperBound(
      InvokeInstruction inv, ConstantPoolGen cpg, JavaClassAndMethodChooser methodChooser)
      throws ClassNotFoundException {

    if (DEBUG_METHOD_LOOKUP) {
      System.out.println(
          "Find prototype method for " + SignatureConverter.convertMethodSignature(inv, cpg));
    }

    short opcode = inv.getOpcode();

    if (opcode == Constants.INVOKESTATIC) {
      if (methodChooser == INSTANCE_METHOD) return null;
    } else {
      if (methodChooser == STATIC_METHOD) return null;
    }

    // Find the method
    if (opcode == Constants.INVOKESPECIAL) {
      // Non-virtual dispatch
      return findExactMethod(inv, cpg, methodChooser);
    } else {
      String className = inv.getClassName(cpg);
      String methodName = inv.getName(cpg);
      String methodSig = inv.getSignature(cpg);
      if (DEBUG_METHOD_LOOKUP) {
        System.out.println("[Class name is " + className + "]");
        System.out.println("[Method name is " + methodName + "]");
        System.out.println("[Method signature is " + methodSig + "]");
      }

      if (className.startsWith("[")) {
        // Java 1.5 allows array classes to appear as the class name
        className = "java.lang.Object";
      }

      JavaClass jClass = Repository.lookupClass(className);
      return findInvocationLeastUpperBound(
          jClass, methodName, methodSig, methodChooser, opcode == Constants.INVOKEINTERFACE);
    }
  }
Пример #9
0
 private static String getFullMethodName(ConstantPoolGen cpg, InvokeInstruction invoke) {
   String dottedClassName = invoke.getReferenceType(cpg).toString();
   StringBuilder builder = new StringBuilder(ClassName.toSlashedClassName(dottedClassName));
   builder.append(".").append(invoke.getMethodName(cpg)).append(invoke.getSignature(cpg));
   return builder.toString();
 }
  /**
   * Resolve possible instance method call targets.
   *
   * @param receiverType type of the receiver object
   * @param invokeInstruction the InvokeInstruction
   * @param cpg the ConstantPoolGen
   * @param receiverTypeIsExact if true, the receiver type is known exactly, which should allow a
   *     precise result
   * @return Set of methods which might be called
   * @throws ClassNotFoundException
   */
  public static Set<JavaClassAndMethod> resolveMethodCallTargets(
      ReferenceType receiverType,
      InvokeInstruction invokeInstruction,
      ConstantPoolGen cpg,
      boolean receiverTypeIsExact)
      throws ClassNotFoundException {
    HashSet<JavaClassAndMethod> result = new HashSet<JavaClassAndMethod>();

    if (invokeInstruction.getOpcode() == Constants.INVOKESTATIC)
      throw new IllegalArgumentException();

    String methodName = invokeInstruction.getName(cpg);
    String methodSig = invokeInstruction.getSignature(cpg);

    // Array method calls aren't virtual.
    // They should just resolve to Object methods.
    if (receiverType instanceof ArrayType) {
      JavaClass javaLangObject =
          AnalysisContext.currentAnalysisContext().lookupClass("java.lang.Object");
      JavaClassAndMethod classAndMethod =
          findMethod(javaLangObject, methodName, methodSig, INSTANCE_METHOD);
      if (classAndMethod != null) result.add(classAndMethod);
      return result;
    }

    if (receiverType instanceof NullType) {
      return Collections.<JavaClassAndMethod>emptySet();
    }
    AnalysisContext analysisContext = AnalysisContext.currentAnalysisContext();

    // Get the receiver class.
    String receiverClassName = ((ObjectType) receiverType).getClassName();
    JavaClass receiverClass = analysisContext.lookupClass(receiverClassName);
    ClassDescriptor receiverDesc =
        DescriptorFactory.createClassDescriptorFromDottedClassName(receiverClassName);

    // Figure out the upper bound for the method.
    // This is what will be called if this is not a virtual call site.
    JavaClassAndMethod upperBound =
        findMethod(receiverClass, methodName, methodSig, CONCRETE_METHOD);
    if (upperBound == null) {
      upperBound =
          findInvocationLeastUpperBound(
              receiverClass, methodName, methodSig, CONCRETE_METHOD, false);
    }
    if (upperBound != null) {
      if (DEBUG_METHOD_LOOKUP) {
        System.out.println(
            "Adding upper bound: "
                + SignatureConverter.convertMethodSignature(
                    upperBound.getJavaClass(), upperBound.getMethod()));
      }
      result.add(upperBound);
    }

    // Is this a virtual call site?
    boolean virtualCall =
        (invokeInstruction.getOpcode() == Constants.INVOKEVIRTUAL
                || invokeInstruction.getOpcode() == Constants.INVOKEINTERFACE)
            && (upperBound == null
                || !upperBound.getJavaClass().isFinal() && !upperBound.getMethod().isFinal())
            && !receiverTypeIsExact;

    if (virtualCall) {
      if (!receiverClassName.equals("java.lang.Object")) {

        // This is a true virtual call: assume that any concrete
        // subtype method may be called.
        Set<ClassDescriptor> subTypeSet = analysisContext.getSubtypes2().getSubtypes(receiverDesc);
        for (ClassDescriptor subtype : subTypeSet) {
          XMethod concreteSubtypeMethod = findMethod(subtype, methodName, methodSig, false);
          if (concreteSubtypeMethod != null
              && (concreteSubtypeMethod.getAccessFlags() & Constants.ACC_ABSTRACT) == 0) {
            result.add(new JavaClassAndMethod(concreteSubtypeMethod));
          }
        }
        if (false && subTypeSet.size() > 500)
          new RuntimeException(
                  receiverClassName
                      + " has "
                      + subTypeSet.size()
                      + " subclasses, "
                      + result.size()
                      + " of which implement "
                      + methodName
                      + methodSig
                      + " "
                      + invokeInstruction)
              .printStackTrace(System.out);
      }
    }
    return result;
  }
  public static Set<ValueNumber> checkUnconditionalDerefDatabase(
      Location location,
      ValueNumberFrame vnaFrame,
      ConstantPoolGen constantPool,
      @CheckForNull IsNullValueFrame invFrame,
      TypeDataflow typeDataflow)
      throws DataflowAnalysisException {
    if (invFrame != null && !invFrame.isValid()) {
      return Collections.emptySet();
    }

    InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction();

    SignatureParser sigParser = new SignatureParser(inv.getSignature(constantPool));
    int numParams = sigParser.getNumParameters();
    if (numParams == 0 || !sigParser.hasReferenceParameters()) {
      return Collections.emptySet();
    }
    ParameterNullnessPropertyDatabase database =
        AnalysisContext.currentAnalysisContext().getUnconditionalDerefParamDatabase();
    if (database == null) {
      if (DEBUG_CHECK_CALLS) {
        System.out.println("no database!");
      }
      return Collections.emptySet();
    }

    TypeFrame typeFrame = typeDataflow.getFactAtLocation(location);
    if (!typeFrame.isValid()) {
      if (DEBUG_CHECK_CALLS) {
        System.out.println("invalid type frame!");
      }
      return Collections.emptySet();
    }

    try {
      Set<XMethod> targetSet = Hierarchy2.resolveMethodCallTargets(inv, typeFrame, constantPool);

      if (targetSet.isEmpty()) {
        return Collections.emptySet();
      }

      if (DEBUG_CHECK_CALLS) {
        System.out.println("target set size: " + targetSet.size());
      }
      // Compute the intersection of all properties
      ParameterProperty derefParamSet = null;
      for (XMethod target : targetSet) {
        if (target.isStub()) {
          continue;
        }
        if (DEBUG_CHECK_CALLS) {
          System.out.print("Checking: " + target + ": ");
        }

        ParameterProperty targetDerefParamSet = database.getProperty(target.getMethodDescriptor());
        if (targetDerefParamSet == null) {
          // Hmm...no information for this target.
          // assume it doesn't dereference anything
          if (DEBUG_CHECK_CALLS) {
            System.out.println("==> no information, assume no guaranteed dereferences");
          }
          return Collections.emptySet();
        }

        if (DEBUG_CHECK_CALLS) {
          System.out.println("==> " + targetDerefParamSet);
        }
        if (derefParamSet == null) {
          derefParamSet = new ParameterProperty();
          derefParamSet.copyFrom(targetDerefParamSet);
        } else {
          derefParamSet.intersectWith(targetDerefParamSet);
        }
      }

      if (derefParamSet == null || derefParamSet.isEmpty()) {
        if (DEBUG) {
          System.out.println("** Nothing");
        }
        return Collections.emptySet();
      }
      if (DEBUG_CHECK_CALLS) {
        System.out.println(
            "** Summary of call @ " + location.getHandle().getPosition() + ": " + derefParamSet);
      }

      HashSet<ValueNumber> requiredToBeNonnull = new HashSet<ValueNumber>();
      for (int i = 0; i < numParams; i++) {
        if (!derefParamSet.hasProperty(i)) {
          continue;
        }
        int argSlot = vnaFrame.getStackLocation(sigParser.getSlotsFromTopOfStackForParameter(i));
        if (invFrame != null && !reportDereference(invFrame, argSlot)) {
          continue;
        }
        if (DEBUG_CHECK_CALLS) {
          System.out.println(
              "  dereference @ " + location.getHandle().getPosition() + " of parameter " + i);
        }

        requiredToBeNonnull.add(vnaFrame.getValue(argSlot));
      }
      return requiredToBeNonnull;

    } catch (ClassNotFoundException e) {
      AnalysisContext.reportMissingClass(e);
    }
    return Collections.emptySet();
  }
  private void analyzeMethod(ClassContext classContext, Method method)
      throws CFGBuilderException, DataflowAnalysisException {
    if (BCELUtil.isSynthetic(method)
        || (method.getAccessFlags() & Const.ACC_BRIDGE) == Const.ACC_BRIDGE) {
      return;
    }
    CFG cfg = classContext.getCFG(method);

    ConstantPoolGen cpg = classContext.getConstantPoolGen();
    TypeDataflow typeDataflow = classContext.getTypeDataflow(method);

    for (Iterator<BasicBlock> i = cfg.blockIterator(); i.hasNext(); ) {
      BasicBlock basicBlock = i.next();

      // Check if it's a method invocation.
      if (!basicBlock.isExceptionThrower()) {
        continue;
      }
      InstructionHandle thrower = basicBlock.getExceptionThrower();
      Instruction ins = thrower.getInstruction();
      if (!(ins instanceof InvokeInstruction)) {
        continue;
      }

      InvokeInstruction inv = (InvokeInstruction) ins;
      boolean foundThrower = false;
      boolean foundNonThrower = false;

      if (inv instanceof INVOKEINTERFACE) {
        continue;
      }

      String className = inv.getClassName(cpg);

      Location loc = new Location(thrower, basicBlock);
      TypeFrame typeFrame = typeDataflow.getFactAtLocation(loc);
      XMethod primaryXMethod = XFactory.createXMethod(inv, cpg);
      // if (primaryXMethod.isAbstract()) continue;
      Set<XMethod> targetSet = null;
      try {

        if (className.startsWith("[")) {
          continue;
        }
        String methodSig = inv.getSignature(cpg);
        if (!methodSig.endsWith("V")) {
          continue;
        }

        targetSet = Hierarchy2.resolveMethodCallTargets(inv, typeFrame, cpg);

        for (XMethod xMethod : targetSet) {
          if (DEBUG) {
            System.out.println("\tFound " + xMethod);
          }

          boolean isUnconditionalThrower =
              xMethod.isUnconditionalThrower()
                  && !xMethod.isUnsupported()
                  && !xMethod.isSynthetic();
          if (isUnconditionalThrower) {
            foundThrower = true;
            if (DEBUG) {
              System.out.println("Found thrower");
            }
          } else {
            foundNonThrower = true;
            if (DEBUG) {
              System.out.println("Found non thrower");
            }
          }
        }
      } catch (ClassNotFoundException e) {
        analysisContext.getLookupFailureCallback().reportMissingClass(e);
      }
      boolean newResult = foundThrower && !foundNonThrower;
      if (newResult) {
        bugReporter.reportBug(
            new BugInstance(this, "TESTING", Priorities.NORMAL_PRIORITY)
                .addClassAndMethod(classContext.getJavaClass(), method)
                .addString("Call to method that always throws Exception")
                .addMethod(primaryXMethod)
                .describe(MethodAnnotation.METHOD_CALLED)
                .addSourceLine(classContext, method, loc));
      }
    }
  }
  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();
  }