forked from OSchip/llvm-project
				
			[clang-tidy] Misc redundant expression checker updated for ineffective bitwise operator expressions
Examples: * Always evaluates to 0: ``` int X; if (0 & X) return; ``` * Always evaluates to ~0: ``` int Y; if (Y | ~0) return; ``` * The symbol is unmodified: ``` int Z; Z &= ~0; ``` Patch by: Lilla Barancsuk! Differential Revision: https://reviews.llvm.org/D39285 llvm-svn: 321168
This commit is contained in:
		
							parent
							
								
									bf8519b5c9
								
							
						
					
					
						commit
						91c6671a71
					
				| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "llvm/Support/Casting.h"
 | 
					#include "llvm/Support/Casting.h"
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <cmath>
 | 
				
			||||||
#include <cstdint>
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
| 
						 | 
					@ -198,7 +199,7 @@ static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns whether the ranges covered by the union of both relational
 | 
					// Returns whether the ranges covered by the union of both relational
 | 
				
			||||||
// expressions covers the whole domain (i.e. x < 10  and  x > 0).
 | 
					// expressions cover the whole domain (i.e. x < 10  and  x > 0).
 | 
				
			||||||
static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
 | 
					static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
 | 
				
			||||||
                                   const APSInt &ValueLHS,
 | 
					                                   const APSInt &ValueLHS,
 | 
				
			||||||
                                   BinaryOperatorKind OpcodeRHS,
 | 
					                                   BinaryOperatorKind OpcodeRHS,
 | 
				
			||||||
| 
						 | 
					@ -519,6 +520,9 @@ static bool retrieveRelationalIntegerConstantExpr(
 | 
				
			||||||
    if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
 | 
					    if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
 | 
					    if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
 | 
				
			||||||
            Value, *Result.Context))
 | 
					            Value, *Result.Context))
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
| 
						 | 
					@ -559,7 +563,7 @@ static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const A
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Retrieves integer constant subexpressions from binary operator expressions
 | 
					// Retrieves integer constant subexpressions from binary operator expressions
 | 
				
			||||||
// that have two equivalent sides
 | 
					// that have two equivalent sides.
 | 
				
			||||||
// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
 | 
					// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
 | 
				
			||||||
static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
 | 
					static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
 | 
				
			||||||
                                           BinaryOperatorKind &MainOpcode,
 | 
					                                           BinaryOperatorKind &MainOpcode,
 | 
				
			||||||
| 
						 | 
					@ -675,6 +679,33 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
 | 
				
			||||||
          .bind("call"),
 | 
					          .bind("call"),
 | 
				
			||||||
      this);
 | 
					      this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Match expressions like: !(1 | 2 | 3)
 | 
				
			||||||
 | 
					  Finder->addMatcher(
 | 
				
			||||||
 | 
					      implicitCastExpr(
 | 
				
			||||||
 | 
					          hasImplicitDestinationType(isInteger()),
 | 
				
			||||||
 | 
					          has(unaryOperator(
 | 
				
			||||||
 | 
					                  hasOperatorName("!"),
 | 
				
			||||||
 | 
					                  hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
 | 
				
			||||||
 | 
					                      anyOf(hasOperatorName("|"), hasOperatorName("&")),
 | 
				
			||||||
 | 
					                      hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName("|"),
 | 
				
			||||||
 | 
					                                                        hasOperatorName("&"))),
 | 
				
			||||||
 | 
					                                   integerLiteral())),
 | 
				
			||||||
 | 
					                      hasRHS(integerLiteral())))))
 | 
				
			||||||
 | 
					                  .bind("logical-bitwise-confusion"))),
 | 
				
			||||||
 | 
					      this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Match expressions like: (X << 8) & 0xFF
 | 
				
			||||||
 | 
					  Finder->addMatcher(
 | 
				
			||||||
 | 
					      binaryOperator(hasOperatorName("&"),
 | 
				
			||||||
 | 
					                     hasEitherOperand(ignoringParenImpCasts(binaryOperator(
 | 
				
			||||||
 | 
					                         hasOperatorName("<<"),
 | 
				
			||||||
 | 
					                         hasRHS(ignoringParenImpCasts(
 | 
				
			||||||
 | 
					                             integerLiteral().bind("shift-const")))))),
 | 
				
			||||||
 | 
					                     hasEitherOperand(ignoringParenImpCasts(
 | 
				
			||||||
 | 
					                         integerLiteral().bind("and-const"))))
 | 
				
			||||||
 | 
					          .bind("left-right-shift-confusion"),
 | 
				
			||||||
 | 
					      this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Match common expressions and apply more checks to find redundant
 | 
					  // Match common expressions and apply more checks to find redundant
 | 
				
			||||||
  // sub-expressions.
 | 
					  // sub-expressions.
 | 
				
			||||||
  //   a) Expr <op> K1 == K2
 | 
					  //   a) Expr <op> K1 == K2
 | 
				
			||||||
| 
						 | 
					@ -783,6 +814,21 @@ void RedundantExpressionCheck::checkArithmeticExpr(
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value) {
 | 
				
			||||||
 | 
					  return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode,
 | 
				
			||||||
 | 
					                                              APSInt Value) {
 | 
				
			||||||
 | 
					  return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value) {
 | 
				
			||||||
 | 
					  return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
 | 
				
			||||||
 | 
					         ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RedundantExpressionCheck::checkBitwiseExpr(
 | 
					void RedundantExpressionCheck::checkBitwiseExpr(
 | 
				
			||||||
    const MatchFinder::MatchResult &Result) {
 | 
					    const MatchFinder::MatchResult &Result) {
 | 
				
			||||||
  if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
 | 
					  if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
 | 
				
			||||||
| 
						 | 
					@ -816,6 +862,43 @@ void RedundantExpressionCheck::checkBitwiseExpr(
 | 
				
			||||||
      else if (Opcode == BO_NE)
 | 
					      else if (Opcode == BO_NE)
 | 
				
			||||||
        diag(Loc, "logical expression is always true");
 | 
					        diag(Loc, "logical expression is always true");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  } else if (const auto *IneffectiveOperator =
 | 
				
			||||||
 | 
					                 Result.Nodes.getNodeAs<BinaryOperator>(
 | 
				
			||||||
 | 
					                     "ineffective-bitwise")) {
 | 
				
			||||||
 | 
					    APSInt Value;
 | 
				
			||||||
 | 
					    const Expr *Sym = nullptr, *ConstExpr = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!retrieveSymbolicExpr(Result, "ineffective-bitwise", Sym) ||
 | 
				
			||||||
 | 
					        !retrieveIntegerConstantExpr(Result, "ineffective-bitwise", Value,
 | 
				
			||||||
 | 
					                                     ConstExpr))
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
 | 
				
			||||||
 | 
					    if (exprEvaluatesToZero(Opcode, Value)) {
 | 
				
			||||||
 | 
					      diag(Loc, "expression always evaluates to 0");
 | 
				
			||||||
 | 
					    } else if (exprEvaluatesToBitwiseNegatedZero(Opcode, Value)) {
 | 
				
			||||||
 | 
					      SourceRange ConstExprRange(ConstExpr->getLocStart(),
 | 
				
			||||||
 | 
					                                 ConstExpr->getLocEnd());
 | 
				
			||||||
 | 
					      StringRef ConstExprText = Lexer::getSourceText(
 | 
				
			||||||
 | 
					          CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
 | 
				
			||||||
 | 
					          Result.Context->getLangOpts());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      diag(Loc, "expression always evaluates to '%0'") << ConstExprText;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else if (exprEvaluatesToSymbolic(Opcode, Value)) {
 | 
				
			||||||
 | 
					      SourceRange SymExprRange(Sym->getLocStart(), Sym->getLocEnd());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      StringRef ExprText = Lexer::getSourceText(
 | 
				
			||||||
 | 
					          CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
 | 
				
			||||||
 | 
					          Result.Context->getLangOpts());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      diag(Loc, "expression always evaluates to '%0'") << ExprText;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -928,6 +1011,45 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
 | 
				
			||||||
         "both sides of overloaded operator are equivalent");
 | 
					         "both sides of overloaded operator are equivalent");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (const auto *NegateOperator =
 | 
				
			||||||
 | 
					          Result.Nodes.getNodeAs<UnaryOperator>("logical-bitwise-confusion")) {
 | 
				
			||||||
 | 
					    SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto Diag =
 | 
				
			||||||
 | 
					        diag(OperatorLoc,
 | 
				
			||||||
 | 
					             "ineffective logical negation operator used; did you mean '~'?");
 | 
				
			||||||
 | 
					    SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!LogicalNotLocation.isMacroID())
 | 
				
			||||||
 | 
					      Diag << FixItHint::CreateReplacement(
 | 
				
			||||||
 | 
					          CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation), "~");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
 | 
				
			||||||
 | 
					          "left-right-shift-confusion")) {
 | 
				
			||||||
 | 
					    const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>("shift-const");
 | 
				
			||||||
 | 
					    assert(ShiftingConst && "Expr* 'ShiftingConst' is nullptr!");
 | 
				
			||||||
 | 
					    APSInt ShiftingValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto *AndConst = Result.Nodes.getNodeAs<Expr>("and-const");
 | 
				
			||||||
 | 
					    assert(AndConst && "Expr* 'AndCont' is nullptr!");
 | 
				
			||||||
 | 
					    APSInt AndValue;
 | 
				
			||||||
 | 
					    if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If ShiftingConst is shifted left with more bits than the position of the
 | 
				
			||||||
 | 
					    // leftmost 1 in the bit representation of AndValue, AndConstant is
 | 
				
			||||||
 | 
					    // ineffective.
 | 
				
			||||||
 | 
					    if (floor(log2(AndValue.getExtValue())) >= ShiftingValue)
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
 | 
				
			||||||
 | 
					                     "ineffective bitwise and operation.");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Check for the following bound expressions:
 | 
					  // Check for the following bound expressions:
 | 
				
			||||||
  // - "binop-const-compare-to-sym",
 | 
					  // - "binop-const-compare-to-sym",
 | 
				
			||||||
  // - "binop-const-compare-to-binop-const",
 | 
					  // - "binop-const-compare-to-binop-const",
 | 
				
			||||||
| 
						 | 
					@ -937,8 +1059,10 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Check for the following bound expression:
 | 
					  // Check for the following bound expression:
 | 
				
			||||||
  // - "binop-const-compare-to-const",
 | 
					  // - "binop-const-compare-to-const",
 | 
				
			||||||
 | 
					  // - "ineffective-bitwise"
 | 
				
			||||||
  // Produced message:
 | 
					  // Produced message:
 | 
				
			||||||
  // -> "logical expression is always false/true"
 | 
					  // -> "logical expression is always false/true"
 | 
				
			||||||
 | 
					  // -> "expression always evaluates to ..."
 | 
				
			||||||
  checkBitwiseExpr(Result);
 | 
					  checkBitwiseExpr(Result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Check for te following bound expression:
 | 
					  // Check for te following bound expression:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -268,6 +268,15 @@ Improvements to clang-tidy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Added the ability to suppress specific checks (or all checks) in a ``NOLINT`` or ``NOLINTNEXTLINE`` comment.
 | 
					- Added the ability to suppress specific checks (or all checks) in a ``NOLINT`` or ``NOLINTNEXTLINE`` comment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Added new functionality to `misc-redundant-expression
 | 
				
			||||||
 | 
					  http://clang.llvm.org/extra/clang-tidy/checks/misc-redundant-expression.html`_ check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Finds redundant binary operator expressions where the operators are overloaded,
 | 
				
			||||||
 | 
					  and ones that contain the same macros twice.
 | 
				
			||||||
 | 
					  Also checks for assignment expressions that do not change the value of the
 | 
				
			||||||
 | 
					  assigned variable, and expressions that always evaluate to the same value
 | 
				
			||||||
 | 
					  because of possible operator confusion.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Improvements to include-fixer
 | 
					Improvements to include-fixer
 | 
				
			||||||
-----------------------------
 | 
					-----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,6 +154,8 @@ bool TestOverloadedOperator(MyStruct& S) {
 | 
				
			||||||
  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
 | 
				
			||||||
  if (S >= S) return true;
 | 
					  if (S >= S) return true;
 | 
				
			||||||
  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LT(x, y) (void)((x) < (y))
 | 
					#define LT(x, y) (void)((x) < (y))
 | 
				
			||||||
| 
						 | 
					@ -662,3 +664,59 @@ int TestWithMinMaxInt(int X) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FLAG1 1
 | 
				
			||||||
 | 
					#define FLAG2 2
 | 
				
			||||||
 | 
					#define FLAG3 4
 | 
				
			||||||
 | 
					#define FLAGS (FLAG1 | FLAG2 | FLAG3)
 | 
				
			||||||
 | 
					#define NOTFLAGS !(FLAG1 | FLAG2 | FLAG3)
 | 
				
			||||||
 | 
					int operatorConfusion(int X, int Y, long Z)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  // Ineffective & expressions.
 | 
				
			||||||
 | 
					  Y = (Y << 8) & 0xff;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation.
 | 
				
			||||||
 | 
					  Y = (Y << 12) & 0xfff;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					  Y = (Y << 12) & 0xff;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					  Y = (Y << 8) & 0x77;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					  Y = (Y << 5) & 0x11;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Tests for unmatched types
 | 
				
			||||||
 | 
					  Z = (Z << 8) & 0xff;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation.
 | 
				
			||||||
 | 
					  Y = (Y << 12) & 0xfffL;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					  Z = (Y << 12) & 0xffLL;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					  Y = (Z << 8L) & 0x77L;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Effective expressions. Do not check.
 | 
				
			||||||
 | 
					  Y = (Y << 4) & 0x15;
 | 
				
			||||||
 | 
					  Y = (Y << 3) & 0x250;
 | 
				
			||||||
 | 
					  Y = (Y << 9) & 0xF33;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int K = !(1 | 2 | 4);
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: ineffective logical negation operator used; did you mean '~'?
 | 
				
			||||||
 | 
					  // CHECK-FIXES: {{^}}  int K = ~(1 | 2 | 4);{{$}}
 | 
				
			||||||
 | 
					  K = !(FLAG1 & FLAG2 & FLAG3);
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: ineffective logical negation operator
 | 
				
			||||||
 | 
					  // CHECK-FIXES: {{^}}  K = ~(FLAG1 & FLAG2 & FLAG3);{{$}}
 | 
				
			||||||
 | 
					  K = !(3 | 4);
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: ineffective logical negation operator
 | 
				
			||||||
 | 
					  // CHECK-FIXES: {{^}}  K = ~(3 | 4);{{$}}
 | 
				
			||||||
 | 
					  int NotFlags = !FLAGS;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: ineffective logical negation operator
 | 
				
			||||||
 | 
					  // CHECK-FIXES: {{^}}  int NotFlags = ~FLAGS;{{$}}
 | 
				
			||||||
 | 
					  NotFlags = NOTFLAGS;
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: ineffective logical negation operator
 | 
				
			||||||
 | 
					  return !(1 | 2 | 4);
 | 
				
			||||||
 | 
					  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: ineffective logical negation operator
 | 
				
			||||||
 | 
					  // CHECK-FIXES: {{^}}  return ~(1 | 2 | 4);{{$}}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#undef FLAG1
 | 
				
			||||||
 | 
					#undef FLAG2
 | 
				
			||||||
 | 
					#undef FLAG3
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue