/* (non-Javadoc)
   * @see edu.umd.cs.findbugs.ba.INullnessAnnotationDatabase#getResolvedAnnotation(java.lang.Object, boolean)
   */
  public NullnessAnnotation getResolvedAnnotation(Object o, boolean getMinimal) {
    Profiler profiler = Global.getAnalysisCache().getProfiler();
    profiler.start(this.getClass());
    try {

      if (DEBUG) {
        System.out.println("getResolvedAnnotation: o=" + o + "...");
      }

      TypeQualifierAnnotation tqa = null;

      if (o instanceof XMethodParameter) {
        XMethodParameter param = (XMethodParameter) o;

        tqa =
            TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(
                param.getMethod(), param.getParameterNumber(), nonnullTypeQualifierValue);
      } else if (o instanceof XMethod || o instanceof XField) {
        tqa =
            TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(
                (AnnotatedObject) o, nonnullTypeQualifierValue);
      }

      NullnessAnnotation result = toNullnessAnnotation(tqa);
      if (DEBUG) {
        System.out.println("   ==> " + (result != null ? result.toString() : "not found"));
      }
      return result;
    } finally {
      profiler.end(this.getClass());
    }
  }
  /* (non-Javadoc)
   * @see edu.umd.cs.findbugs.ba.INullnessAnnotationDatabase#parameterMustBeNonNull(edu.umd.cs.findbugs.ba.XMethod, int)
   */
  public boolean parameterMustBeNonNull(XMethod m, int param) {
    if (DEBUG) {
      System.out.print("Checking " + m + " param " + param + " for @Nonnull...");
    }
    TypeQualifierAnnotation tqa =
        TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(
            m, param, nonnullTypeQualifierValue);

    if (tqa == null && param == 0) {
      String name = m.getName();
      String signature = m.getSignature();
      if (name.equals("main")
          && signature.equals("([Ljava/lang/String;)V")
          && m.isStatic()
          && m.isPublic()) return true;
      else if (NullnessAnnotationDatabase.assertsFirstParameterIsNonnull(m)) return true;
      else if (name.equals("compareTo")
          && signature.substring(signature.indexOf(";") + 1).equals(")Z")
          && !m.isStatic()) return true;
    }
    boolean answer = (tqa != null) && tqa.when == When.ALWAYS;

    if (DEBUG) {
      System.out.println(answer ? "yes" : "no");
    }

    return answer;
  }
  public void visitClassContext(ClassContext classContext) {

    JavaClass jclass = classContext.getJavaClass();

    for (Method method : jclass.getMethods()) {
      XMethod xmethod = XFactory.createXMethod(classContext.getJavaClass(), method);
      ParameterProperty nonnullParameters =
          AnalysisContext.currentAnalysisContext()
              .getUnconditionalDerefParamDatabase()
              .getProperty(xmethod.getMethodDescriptor());
      if (nonnullParameters != null) {
        for (int p : nonnullParameters.iterable()) {
          TypeQualifierAnnotation directTypeQualifierAnnotation =
              TypeQualifierApplications.getDirectTypeQualifierAnnotation(
                  xmethod, p, nonnullTypeQualifierValue);
          if (directTypeQualifierAnnotation != null
              && directTypeQualifierAnnotation.when == When.UNKNOWN) {
            //
            // The LocalVariableAnnotation is constructed using the local variable
            // number of the parameter, not the parameter number.
            //
            int paramLocal = xmethod.isStatic() ? p : p + 1;

            reporter.reportBug(
                new BugInstance(
                        this,
                        "NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE",
                        NORMAL_PRIORITY)
                    .addClassAndMethod(jclass, method)
                    .add(
                        LocalVariableAnnotation.getParameterLocalVariableAnnotation(
                            method, paramLocal)));
          }
        }
      }
    }
  }