/*
 * Copyright 2012 The Error Prone Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.errorprone.bugpatterns;

import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.matchers.Matchers.nextStatement;
import static com.google.errorprone.matchers.Matchers.parentNode;
import static com.sun.source.tree.Tree.Kind.IF;

import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.EmptyStatementTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matchers;
import com.sun.source.tree.EmptyStatementTree;
import com.sun.source.tree.IfTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;

/**
 * This checker finds and fixes empty statements after an if, with no else part. For example: if
 * (foo == 10);
 *
 * <p>It attempts to match javac's -Xlint:empty warning behavior, which can be found in
 * com/sun/tools/javac/comp/Check.java.
 *
 * @author eaftan@google.com (Eddie Aftandilian)
 */
@BugPattern(
    name = "EmptyIf",
    altNames = {"empty"},
    summary = "Empty statement after if",
    severity = ERROR,
    providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
public class EmptyIfStatement extends BugChecker implements EmptyStatementTreeMatcher {

  /**
   * Match empty statement if: - Parent statement is an if - The then part of the parent if is an
   * empty statement, and - The else part of the parent if does not exist
   */
  @Override
  public Description matchEmptyStatement(EmptyStatementTree tree, VisitorState state) {
    boolean matches = false;
    Tree parent = state.getPath().getParentPath().getLeaf();
    if (parent.getKind() == IF) {
      IfTree parentAsIf = (IfTree) parent;
      matches =
          (parentAsIf.getThenStatement() instanceof EmptyStatementTree)
              && (parentAsIf.getElseStatement() == null);
    }
    if (!matches) {
      return Description.NO_MATCH;
    }

    /*
     * We suggest different fixes depending on what follows the parent if statement.
     * If there is no statement following the if, then suggest deleting the whole
     * if statement. If the next statement is a block, then suggest deleting the
     * empty then part of the if.  If the next statement is not a block, then also
     * suggest deleting the empty then part of the if.
     */
    boolean nextStmtIsNull =
        parentNode(nextStatement(Matchers.<StatementTree>isSame(null))).matches(tree, state);

    assert (state.getPath().getParentPath().getLeaf().getKind() == IF);
    IfTree ifParent = (IfTree) state.getPath().getParentPath().getLeaf();
    if (nextStmtIsNull) {
      // No following statements. Delete whole if.
      return describeMatch(parent, SuggestedFix.delete(parent));
    } else {
      // There are more statements. Delete the empty then part of the if.
      return describeMatch(
          ifParent.getThenStatement(), SuggestedFix.delete(ifParent.getThenStatement()));
    }
  }
}

@@ -763,30 +763,28 @@
 ers.
-Matchers.nextStatement
+Description.NO_MATCH
 ;%0Aim
@@ -839,66 +839,30 @@
 ers.
-parentNode;%0Aimport static com.sun.source.tree.Tree.Kind.IF
+isLastStatementInBlock
 ;%0A%0Ai
@@ -1180,56 +1180,8 @@
 on;%0A
-import com.google.errorprone.matchers.Matchers;%0A
 impo
@@ -1285,25 +1285,16 @@
 ce.tree.
-Statement
 Tree;%0Aim
@@ -1313,25 +1313,29 @@
 .source.
-tree
+util
 .Tree
+Path
 ;%0A%0A/**%0A 
@@ -2195,48 +2195,27 @@
     
-boolean matches = false;%0A    
 Tree
+Path
  parent
+Path
  = s
@@ -2236,32 +2236,62 @@
 .getParentPath()
+;%0A    Tree parent = parentPath
 .getLeaf();%0A    
@@ -2297,115 +2297,122 @@
  if 
+(!
 (parent
-.getKind() == IF) %7B%0A      IfTree parentAsIf = (IfTree) parent;%0A      matches =%0A          (parentAsIf
+ instanceof IfTree)) %7B%0A      return NO_MATCH;%0A    %7D%0A    IfTree ifTree = (IfTree) parent;%0A    if (!(ifTree
 .get
@@ -2470,28 +2470,17 @@
     
-      && (parentAsIf
+%7C%7C ifTree
 .get
@@ -2499,41 +2499,16 @@
 t() 
-=
+!
 = null)
-;%0A    %7D%0A    if (!matches)
  %7B%0A 
@@ -2519,28 +2519,16 @@
  return 
-Description.
 NO_MATCH
@@ -2945,251 +2945,69 @@
     
-boolean nextStmtIsNull =%0A        parentNode(nextStatement(Matchers.%3CStatementTree%3EisSame(null))).matches(tree, state);%0A%0A    assert (state.getPath().getParentPath().getLeaf().getKind() == IF);%0A    IfTree ifParent = (IfTree)
+if (isLastStatementInBlock().matches(ifTree,
  state.
-get
+with
 Path(
-).getP
+p
 aren
@@ -3015,44 +3015,10 @@
 Path
-().getLeaf();%0A    if (nextStmtIsNull
+))
 ) %7B%0A
@@ -3260,22 +3260,20 @@
       if
-Parent
+Tree
 .getThen
@@ -3307,22 +3307,20 @@
 elete(if
-Parent
+Tree
 .getThen

Clean up EmptyIfStatement