/**
   * Fixes the error by assigning the result of the call to the receiver reference, or deleting the
   * method call.
   */
  public Description describe(MethodInvocationTree methodInvocationTree, VisitorState state) {
    // Find the root of the field access chain, i.e. a.intern().trim() ==> a.
    ExpressionTree identifierExpr = ASTHelpers.getRootAssignable(methodInvocationTree);
    String identifierStr = null;
    Type identifierType = null;
    if (identifierExpr != null) {
      identifierStr = identifierExpr.toString();
      if (identifierExpr instanceof JCIdent) {
        identifierType = ((JCIdent) identifierExpr).sym.type;
      } else if (identifierExpr instanceof JCFieldAccess) {
        identifierType = ((JCFieldAccess) identifierExpr).sym.type;
      } else {
        throw new IllegalStateException("Expected a JCIdent or a JCFieldAccess");
      }
    }

    Type returnType =
        ASTHelpers.getReturnType(((JCMethodInvocation) methodInvocationTree).getMethodSelect());

    Fix fix;
    if (identifierStr != null
        && !"this".equals(identifierStr)
        && returnType != null
        && state.getTypes().isAssignable(returnType, identifierType)) {
      // Fix by assigning the assigning the result of the call to the root receiver reference.
      fix = SuggestedFix.prefixWith(methodInvocationTree, identifierStr + " = ");
    } else {
      // Unclear what the programmer intended.  Delete since we don't know what else to do.
      Tree parent = state.getPath().getParentPath().getLeaf();
      fix = SuggestedFix.delete(parent);
    }
    return describeMatch(methodInvocationTree, fix);
  }
  @Override
  public Description matchMethod(MethodTree methodTree, VisitorState state) {
    // if method is itself annotated with @Inject or it has no ancestor methods, return NO_MATCH;
    if (hasInjectAnnotation().matches(methodTree, state)) {
      return Description.NO_MATCH;
    }

    boolean foundJavaxInject = false;
    for (MethodSymbol superMethod :
        ASTHelpers.findSuperMethods(ASTHelpers.getSymbol(methodTree), state.getTypes())) {

      // With a Guice annotation, Guice will still inject the subclass-overridden method.
      if (ASTHelpers.hasAnnotation(superMethod, GUICE_INJECT_ANNOTATION, state)) {
        return Description.NO_MATCH;
      }

      // is not necessarily a match even if we find javax Inject on an ancestor
      // since a higher up ancestor may have @com.google.inject.Inject
      foundJavaxInject |= ASTHelpers.hasAnnotation(superMethod, JAVAX_INJECT_ANNOTATION, state);
    }

    if (foundJavaxInject) {
      return describeMatch(
          methodTree,
          SuggestedFix.builder()
              .addImport(JAVAX_INJECT_ANNOTATION)
              .prefixWith(methodTree, "@Inject\n")
              .build());
    }
    return Description.NO_MATCH;
  }
 @Override
 public Description matchMethodInvocation(
     MethodInvocationTree methodInvocationTree, VisitorState state) {
   if (methodInvocationTree.getArguments().isEmpty()) {
     return Description.NO_MATCH;
   }
   if (!TRUTH_SUBJECT_CALL.matches(methodInvocationTree, state)) {
     return Description.NO_MATCH;
   }
   ExpressionTree rec = ASTHelpers.getReceiver(methodInvocationTree);
   if (rec == null) {
     return Description.NO_MATCH;
   }
   if (!ASSERT_THAT.matches(rec, state)) {
     return Description.NO_MATCH;
   }
   ExpressionTree expr = getOnlyElement(((MethodInvocationTree) rec).getArguments());
   if (expr == null) {
     return Description.NO_MATCH;
   }
   // check that argument of assertThat is a constant
   if (ASTHelpers.constValue(expr) == null) {
     return Description.NO_MATCH;
   }
   // check that expectation isn't a constant
   ExpressionTree expectation = getOnlyElement(methodInvocationTree.getArguments());
   if (ASTHelpers.constValue(expectation) != null) {
     return Description.NO_MATCH;
   }
   SuggestedFix fix = SuggestedFix.swap(expr, expectation);
   return buildDescription(methodInvocationTree).addFix(fix).build();
 }
  @Override
  public Description matchTry(TryTree tree, VisitorState state) {
    if (tryTreeMatches(tree, state)) {
      List<? extends StatementTree> tryStatements = tree.getBlock().getStatements();
      StatementTree lastTryStatement = tryStatements.get(tryStatements.size() - 1);

      String failCall = String.format("%nfail(\"Expected %s\");", exceptionToString(tree));
      SuggestedFix.Builder fixBuilder =
          SuggestedFix.builder().postfixWith(lastTryStatement, failCall);

      // Make sure that when the fail import is added it doesn't conflict with existing ones.
      fixBuilder.removeStaticImport("junit.framework.Assert.fail");
      fixBuilder.removeStaticImport("junit.framework.TestCase.fail");
      fixBuilder.addStaticImport("org.junit.Assert.fail");

      return describeMatch(lastTryStatement, fixBuilder.build());
    } else {
      return Description.NO_MATCH;
    }
  }
Example #5
0
  /**
   * Suggests replacing with Arrays.equals(a, b). Also adds the necessary import statement for
   * java.util.Arrays.
   */
  @Override
  public Description matchMethodInvocation(MethodInvocationTree t, VisitorState state) {
    String arg1;
    String arg2;
    if (instanceEqualsMatcher.matches(t, state)) {
      arg1 = ((JCFieldAccess) t.getMethodSelect()).getExpression().toString();
      arg2 = t.getArguments().get(0).toString();
    } else if (staticEqualsMatcher.matches(t, state)) {
      arg1 = t.getArguments().get(0).toString();
      arg2 = t.getArguments().get(1).toString();
    } else {
      return NO_MATCH;
    }

    Fix fix =
        SuggestedFix.builder()
            .replace(t, "Arrays.equals(" + arg1 + ", " + arg2 + ")")
            .addImport("java.util.Arrays")
            .build();
    return describeMatch(t, fix);
  }