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;
    }
  }
Beispiel #7
0
  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;
  }
Beispiel #9
0
 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);
  }
Beispiel #11
0
 /**
  * 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);
 }
Beispiel #17
0
 /**
  * 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());
 }