Package com.google.errorprone.bugpatterns

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

/*
* Copyright 2013 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.MATURE;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.kindIs;

import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;

import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree.Kind;
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.JCLiteral;

/**
* @author bill.pugh@gmail.com (Bill Pugh)
* @author eaftan@google.com (Eddie Aftandilian)
*/
@BugPattern(name = "BadShiftAmount",
    summary = "Shift by an amount that is out of range",
    explanation = "For shift operations on int types, only the five lowest-order bits of the "
        + "shift amount are used as the shift distance.  This means that shift amounts that are "
        + "not in the range 0 to 31, inclusive, are silently mapped to values in that range. "
        + "For example, a shift of an int by 32 is equivalent to shifting by 0, i.e., a no-op.\n\n"
        + "See JLS 15.19, \"Shift Operators\", for more details.",
    category = JDK, severity = ERROR, maturity = MATURE)
public class BadShiftAmount extends BugChecker implements BinaryTreeMatcher {

  /**
   * Matches if the left operand is an int, byte, short, or char, and the right operand is a
   * literal that is not in the range 0-31 inclusive.
   *
   * <p>In a shift expression, byte, short, and char undergo unary numeric promotion and are
   * promoted to int.  See JLS 5.6.1.
   */
  private static final Matcher<BinaryTree> BAD_SHIFT_AMOUNT_INT = new Matcher<BinaryTree>() {
    @Override
    public boolean matches(BinaryTree tree, VisitorState state) {
      Type leftType = ((JCTree) tree.getLeftOperand()).type;
      Types types = state.getTypes();
      Symtab symtab = state.getSymtab();
      if (!(types.isSameType(leftType, symtab.intType)) &&
          !(types.isSameType(leftType, symtab.byteType)) &&
          !(types.isSameType(leftType, symtab.shortType)) &&
          !(types.isSameType(leftType, symtab.charType))) {
        return false;
      }

      ExpressionTree rightOperand = tree.getRightOperand();
      if (rightOperand instanceof LiteralTree) {
        Object rightValue = ((LiteralTree) rightOperand).getValue();
        if (rightValue instanceof Number) {
          int intValue = ((Number) rightValue).intValue();
          return intValue < 0 || intValue > 31;
        }
      }

      return false;
    }
  };

  public static final Matcher<BinaryTree> BINARY_TREE_MATCHER = allOf(
      anyOf(
          kindIs(Kind.LEFT_SHIFT),
          kindIs(Kind.RIGHT_SHIFT),
          kindIs(Kind.UNSIGNED_RIGHT_SHIFT)),
      BAD_SHIFT_AMOUNT_INT
  );

  @Override
  public Description matchBinary(BinaryTree tree, VisitorState state) {
    if (!BINARY_TREE_MATCHER.matches(tree, state)) {
      return Description.NO_MATCH;
    }

    /*
     * For shift amounts in [32, 63], cast the left operand to long.  Otherwise change the shift
     * amount to whatever would actually be used.
     */
    int intValue = ((Number) ((LiteralTree) tree.getRightOperand()).getValue()).intValue();

    Fix fix;
    if (intValue >= 32 && intValue <= 63) {
      if (tree.getLeftOperand().getKind() == Kind.INT_LITERAL) {
        fix = SuggestedFix.postfixWith(tree.getLeftOperand(), "L");
      } else {
        fix = SuggestedFix.prefixWith(tree, "(long) ");
      }
    } else {
      JCLiteral jcLiteral = (JCLiteral) tree.getRightOperand();
      // This is the equivalent shift distance according to JLS 15.19.
      String actualShiftDistance = Integer.toString(intValue & 0x1f);
      int actualStart = ASTHelpers.getActualStartPosition(jcLiteral, state.getSourceCode());
      if (actualStart != jcLiteral.getStartPosition()) {
        fix = SuggestedFix.replace(tree.getRightOperand(), actualShiftDistance,
            actualStart - jcLiteral.getStartPosition(), 0);
      } else {
        fix = SuggestedFix.replace(tree.getRightOperand(), actualShiftDistance);
      }
    }
    return describeMatch(tree, fix);
  }
}
TOP

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

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.