Package com.google.errorprone.bugpatterns

Source Code of com.google.errorprone.bugpatterns.SelfEquality

/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* 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.Category.JDK;
import static com.google.errorprone.BugPattern.MaturityLevel.EXPERIMENTAL;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.kindIs;
import static com.sun.source.tree.Tree.Kind.EQUAL_TO;
import static com.sun.source.tree.Tree.Kind.NOT_EQUAL_TO;

import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;

import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;

import java.util.List;

/**
* @author scottjohnson@google.com (Scott Johnson)
*/
@BugPattern(name = "SelfEquality",
    summary = "Variable compared to itself",
    explanation = "There is no good reason to test a primitive value or reference for equality " +
          "with itself.",
    category = JDK, severity = ERROR, maturity = EXPERIMENTAL)
public class SelfEquality extends BugChecker implements BinaryTreeMatcher {

  @Override
  public Description matchBinary(BinaryTree tree, VisitorState state) {
    if (!(anyOf(kindIs(EQUAL_TO), kindIs(NOT_EQUAL_TO)).matches(tree, state)
        && ASTHelpers.sameVariable(tree.getLeftOperand(), tree.getRightOperand()))) {
      return Description.NO_MATCH;
    }

    StringBuilder fixedExpression = new StringBuilder();
    Fix fix = null;

    ExpressionTree leftOperand = tree.getLeftOperand();
    ExpressionTree rightOperand = tree.getRightOperand();
    Type leftType = ((JCTree) leftOperand).type;
    Types types = state.getTypes();
    Symtab symtab = state.getSymtab();

    /**
     * Try to figure out what they were trying to do.
     * Cases:
     * 1) (foo == foo) ==> (foo == other.foo)
     * 2) (foo == this.foo) ==> (other.foo == this.foo)
     * 3) (this.foo == foo) ==> (this.foo == other.foo)
     * 4) (this.foo == this.foo) ==> (this.foo == other.foo)
     */

    // Choose argument to replace.
    ExpressionTree toReplace;
    if (rightOperand.getKind() == Kind.IDENTIFIER) {
      toReplace = rightOperand;
    } else if (leftOperand.getKind() == Kind.IDENTIFIER) {
      toReplace = leftOperand;
    } else {
      // If we don't have a good reason to replace one or the other, replace the second.
      toReplace = rightOperand;
    }

    // Find containing block
    TreePath path = state.getPath();
    while (path.getLeaf() != null && path.getLeaf().getKind() != Kind.CLASS
        && path.getLeaf().getKind() != Kind.BLOCK) {
      path = path.getParentPath();
    }
    if (path.getLeaf() != null) {
      List<? extends JCTree> members;
      // Must be block or class
      if (path.getLeaf().getKind() == Kind.CLASS) {
        members = ((JCClassDecl) path.getLeaf()).getMembers();
      } else {
        members = ((JCBlock) path.getLeaf()).getStatements();
      }
      for (JCTree jcTree : members) {
        if (jcTree.getKind() == Kind.VARIABLE) {
          JCVariableDecl declaration = (JCVariableDecl) jcTree;
          TypeSymbol variableTypeSymbol = declaration.getType().type.tsym;

          if (ASTHelpers.getSymbol(toReplace).isMemberOf(variableTypeSymbol, state.getTypes())) {
            if (toReplace.getKind() == Kind.IDENTIFIER) {
              fix = SuggestedFix.prefixWith(toReplace, declaration.getName() + ".");
            } else {
              fix = SuggestedFix.replace(
                  ((JCFieldAccess) toReplace).getExpression(), declaration.getName().toString());
            }
          }
        }
      }
    }

    if (fix == null) {
      // No good replacement, let's try something else!

      // For floats or doubles, y!=y -> isNaN(y)
      if (tree.getKind() == Tree.Kind.EQUAL_TO) {
        fixedExpression.append("!");
      }
      if (types.isSameType(leftType, symtab.floatType)) {
        fixedExpression.append("Float.isNaN(" + leftOperand + ")");
        fix = SuggestedFix.replace(tree, fixedExpression.toString());
      } else if (types.isSameType(leftType, symtab.doubleType)) {
        fixedExpression.append("Double.isNaN(" + leftOperand + ")");
        fix = SuggestedFix.replace(tree, fixedExpression.toString());
      } else {

        // last resort, just replace with true or false
        if (tree.getKind() == Tree.Kind.EQUAL_TO) {
          fix = SuggestedFix.replace(tree, "true");
        } else {
          fix = SuggestedFix.replace(tree, "false");
        }
      }
    }

    return (fix == null) ? describeMatch(tree) : describeMatch(tree, fix);
  }
}
TOP

Related Classes of com.google.errorprone.bugpatterns.SelfEquality

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.