11 #include "../utils/Matchers.h"
12 #include "../utils/OptionsUtils.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Basic/LLVM.h"
16 #include "clang/Basic/SourceLocation.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/Lex/Lexer.h"
19 #include "llvm/ADT/APInt.h"
20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/ADT/FoldingSet.h"
22 #include "llvm/Support/Casting.h"
30 using namespace clang::ast_matchers;
31 using namespace clang::tidy::matchers;
42 "EAGAIN;EWOULDBLOCK;SIGCLD;SIGCHLD;";
47 return Value < Result;
51 const NestedNameSpecifier *Right) {
52 llvm::FoldingSetNodeID LeftID, RightID;
53 Left->Profile(LeftID);
54 Right->Profile(RightID);
55 return LeftID == RightID;
60 return !Left && !Right;
62 Left = Left->IgnoreParens();
63 Right = Right->IgnoreParens();
66 if (Left->getStmtClass() != Right->getStmtClass())
70 Expr::const_child_iterator LeftIter = Left->child_begin();
71 Expr::const_child_iterator RightIter = Right->child_begin();
72 while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
74 dyn_cast<Expr>(*RightIter)))
79 if (LeftIter != Left->child_end() || RightIter != Right->child_end())
83 switch (Left->getStmtClass()) {
87 case Stmt::CharacterLiteralClass:
88 return cast<CharacterLiteral>(Left)->getValue() ==
89 cast<CharacterLiteral>(Right)->getValue();
90 case Stmt::IntegerLiteralClass: {
91 llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
92 llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
93 return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
96 case Stmt::FloatingLiteralClass:
97 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
98 cast<FloatingLiteral>(Right)->getValue());
99 case Stmt::StringLiteralClass:
100 return cast<StringLiteral>(Left)->getBytes() ==
101 cast<StringLiteral>(Right)->getBytes();
103 case Stmt::DependentScopeDeclRefExprClass:
104 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
105 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
108 cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
109 cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
110 case Stmt::DeclRefExprClass:
111 return cast<DeclRefExpr>(Left)->getDecl() ==
112 cast<DeclRefExpr>(Right)->getDecl();
113 case Stmt::MemberExprClass:
114 return cast<MemberExpr>(Left)->getMemberDecl() ==
115 cast<MemberExpr>(Right)->getMemberDecl();
117 case Stmt::CStyleCastExprClass:
118 return cast<CStyleCastExpr>(Left)->getTypeAsWritten() ==
119 cast<CStyleCastExpr>(Right)->getTypeAsWritten();
121 case Stmt::CallExprClass:
122 case Stmt::ImplicitCastExprClass:
123 case Stmt::ArraySubscriptExprClass:
126 case Stmt::UnaryOperatorClass:
127 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
129 return cast<UnaryOperator>(Left)->getOpcode() ==
130 cast<UnaryOperator>(Right)->getOpcode();
131 case Stmt::BinaryOperatorClass:
132 return cast<BinaryOperator>(Left)->getOpcode() ==
133 cast<BinaryOperator>(Right)->getOpcode();
140 const APSInt &ValueLHS,
141 BinaryOperatorKind OpcodeRHS,
142 const APSInt &ValueRHS) {
143 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
144 "Values must be ordered");
146 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
147 return OpcodeLHS == OpcodeRHS;
150 APSInt ValueLHS_plus1;
151 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
152 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
154 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
160 const APSInt &ValueLHS,
161 BinaryOperatorKind OpcodeRHS,
162 const APSInt &ValueRHS) {
163 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
164 "Values must be ordered");
167 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
170 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
172 return OpcodeRHS == BO_EQ;
174 return OpcodeRHS == BO_GT;
176 return OpcodeRHS == BO_LT;
178 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
180 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
187 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
188 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
192 APSInt ValueLHS_plus1;
193 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
195 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
204 const APSInt &ValueLHS,
205 BinaryOperatorKind OpcodeRHS,
206 const APSInt &ValueRHS) {
207 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
208 "Values must be ordered");
211 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
214 return OpcodeRHS == BO_NE;
216 return OpcodeRHS == BO_EQ;
218 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
220 return OpcodeRHS == BO_GE;
222 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
224 return OpcodeRHS == BO_LE;
231 APSInt ValueLHS_plus1;
232 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
234 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
238 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
239 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
244 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
251 const APSInt &ValueLHS,
252 BinaryOperatorKind OpcodeRHS,
253 const APSInt &ValueRHS) {
254 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
257 return OpcodeRHS == BO_EQ && Comparison == 0;
259 return (OpcodeRHS == BO_NE && Comparison == 0) ||
260 (OpcodeRHS == BO_EQ && Comparison != 0) ||
261 (OpcodeRHS == BO_LT && Comparison >= 0) ||
262 (OpcodeRHS == BO_LE && Comparison > 0) ||
263 (OpcodeRHS == BO_GT && Comparison <= 0) ||
264 (OpcodeRHS == BO_GE && Comparison < 0);
267 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
268 (OpcodeRHS == BO_LE && Comparison > 0) ||
269 (OpcodeRHS == BO_EQ && Comparison > 0));
271 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
272 (OpcodeRHS == BO_GE && Comparison < 0) ||
273 (OpcodeRHS == BO_EQ && Comparison < 0));
275 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
278 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
286 if (Opcode == BO_Sub) {
293 if (Node.isInstantiationDependent())
295 return Node.isIntegerConstantExpr(
Finder->getASTContext());
299 static ast_matchers::internal::Matcher<Expr>
301 std::string CstId = (Id +
"-const").str();
302 return expr(isIntegerConstantExpr()).bind(CstId);
308 StringRef Id, APSInt &Value) {
309 std::string CstId = (Id +
"-const").str();
310 const auto *CstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
311 return CstExpr && CstExpr->isIntegerConstantExpr(Value, *Result.Context);
317 std::string SymId = (Id +
"-sym").str();
318 return ignoringParenImpCasts(
319 expr(unless(isIntegerConstantExpr())).bind(SymId));
325 StringRef Id,
const Expr *&SymExpr) {
326 std::string SymId = (Id +
"-sym").str();
327 if (
const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
336 static ast_matchers::internal::Matcher<Expr>
338 const auto BinOpCstExpr =
340 anyOf(binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|"),
341 hasOperatorName(
"&")),
344 binaryOperator(hasOperatorName(
"-"),
348 return ignoringParenImpCasts(BinOpCstExpr);
355 StringRef Id, BinaryOperatorKind &Opcode,
356 const Expr *&Symbol, APSInt &Value) {
357 if (
const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
358 Opcode = BinExpr->getOpcode();
366 static ast_matchers::internal::Matcher<Expr>
368 std::string CastId = (Id +
"-cast").str();
369 std::string SwapId = (Id +
"-swap").str();
370 std::string NegateId = (Id +
"-negate").str();
372 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
373 isComparisonOperator(), expr().bind(Id),
381 const auto CastExpr =
382 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
386 const auto NegateRelationalExpr =
387 unaryOperator(hasOperatorName(
"!"),
388 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
391 const auto NegateNegateRelationalExpr =
392 unaryOperator(hasOperatorName(
"!"),
393 hasUnaryOperand(unaryOperator(
394 hasOperatorName(
"!"),
395 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
397 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
398 NegateNegateRelationalExpr);
405 StringRef Id,
const Expr *&OperandExpr,
406 BinaryOperatorKind &Opcode,
407 const Expr *&Symbol, APSInt &Value) {
408 std::string CastId = (Id +
"-cast").str();
409 std::string SwapId = (Id +
"-swap").str();
410 std::string NegateId = (Id +
"-negate").str();
412 if (
const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
414 Opcode = Bin->getOpcode();
418 }
else if (
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
422 Value = APSInt(32,
false);
430 if (Result.Nodes.getNodeAs<Expr>(SwapId))
431 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
432 if (Result.Nodes.getNodeAs<Expr>(NegateId))
433 Opcode = BinaryOperator::negateComparisonOp(Opcode);
447 return Node.getNumArgs() == 2 &&
452 return Node.getOperatorLoc().isMacroID();
456 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
459 AST_MATCHER(Expr, isMacro) {
return Node.getExprLoc().isMacroID(); }
462 const SourceManager &
SM =
Finder->getASTContext().getSourceManager();
463 const LangOptions &LO =
Finder->getASTContext().getLangOpts();
464 SourceLocation
Loc = Node.getExprLoc();
465 while (Loc.isMacroID()) {
466 std::string MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
467 if (Names.find(MacroName) != Names.end())
469 Loc = SM.getImmediateMacroCallerLoc(Loc);
474 void RedundantExpressionCheck::registerMatchers(MatchFinder *
Finder) {
475 const auto AnyLiteralExpr = ignoringParenImpCasts(
476 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
478 std::vector<std::string> MacroNames =
480 std::set<std::string> Names(MacroNames.begin(), MacroNames.end());
482 const auto BannedIntegerLiteral = integerLiteral(expandedByMacro(Names));
485 binaryOperator(anyOf(hasOperatorName(
"-"), hasOperatorName(
"/"),
486 hasOperatorName(
"%"), hasOperatorName(
"|"),
487 hasOperatorName(
"&"), hasOperatorName(
"^"),
488 matchers::isComparisonOperator(),
489 hasOperatorName(
"&&"), hasOperatorName(
"||"),
490 hasOperatorName(
"=")),
491 operandsAreEquivalent(),
493 unless(isInTemplateInstantiation()),
494 unless(binaryOperatorIsInMacro()),
495 unless(hasType(realFloatingPointType())),
496 unless(hasEitherOperand(hasType(realFloatingPointType()))),
497 unless(hasLHS(AnyLiteralExpr)),
498 unless(hasDescendant(BannedIntegerLiteral)))
503 conditionalOperator(expressionsAreEquivalent(),
505 unless(conditionalOperatorIsInMacro()),
506 unless(hasTrueExpression(AnyLiteralExpr)),
507 unless(isInTemplateInstantiation()))
514 hasOverloadedOperatorName(
"-"), hasOverloadedOperatorName(
"/"),
515 hasOverloadedOperatorName(
"%"), hasOverloadedOperatorName(
"|"),
516 hasOverloadedOperatorName(
"&"), hasOverloadedOperatorName(
"^"),
517 hasOverloadedOperatorName(
"=="), hasOverloadedOperatorName(
"!="),
518 hasOverloadedOperatorName(
"<"), hasOverloadedOperatorName(
"<="),
519 hasOverloadedOperatorName(
">"), hasOverloadedOperatorName(
">="),
520 hasOverloadedOperatorName(
"&&"), hasOverloadedOperatorName(
"||"),
521 hasOverloadedOperatorName(
"=")),
522 parametersAreEquivalent(),
524 unless(isMacro()), unless(isInTemplateInstantiation()))
540 Finder->addMatcher(binaryOperator(isComparisonOperator(),
541 hasEitherOperand(BinOpCstLeft),
542 hasEitherOperand(CstRight))
543 .bind(
"binop-const-compare-to-const"),
548 binaryOperator(isComparisonOperator(),
549 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
550 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
551 .bind(
"binop-const-compare-to-sym"),
555 Finder->addMatcher(binaryOperator(isComparisonOperator(),
556 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
558 unless(operandsAreEquivalent()))
559 .bind(
"binop-const-compare-to-binop-const"),
570 binaryOperator(anyOf(hasOperatorName(
"||"), hasOperatorName(
"&&")),
571 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
573 unless(operandsAreEquivalent()))
574 .bind(
"comparisons-of-symbol-and-const"),
578 void RedundantExpressionCheck::checkArithmeticExpr(
579 const MatchFinder::MatchResult &Result) {
580 APSInt LhsValue, RhsValue;
581 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
582 BinaryOperatorKind LhsOpcode, RhsOpcode;
584 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
585 "binop-const-compare-to-sym")) {
586 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
594 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
595 if ((LhsValue != 0 && Opcode == BO_EQ) ||
596 (LhsValue == 0 && Opcode == BO_NE))
597 diag(ComparisonOperator->getOperatorLoc(),
598 "logical expression is always false");
599 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
600 (LhsValue != 0 && Opcode == BO_NE))
601 diag(ComparisonOperator->getOperatorLoc(),
602 "logical expression is always true");
604 }
else if (
const auto *ComparisonOperator =
605 Result.Nodes.getNodeAs<BinaryOperator>(
606 "binop-const-compare-to-binop-const")) {
607 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
620 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
621 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
622 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
623 diag(ComparisonOperator->getOperatorLoc(),
624 "logical expression is always true");
625 }
else if ((Opcode == BO_EQ &&
626 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
628 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
629 diag(ComparisonOperator->getOperatorLoc(),
630 "logical expression is always false");
636 void RedundantExpressionCheck::checkBitwiseExpr(
637 const MatchFinder::MatchResult &Result) {
638 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
639 "binop-const-compare-to-const")) {
640 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
642 APSInt LhsValue, RhsValue;
643 const Expr *LhsSymbol =
nullptr;
644 BinaryOperatorKind LhsOpcode;
650 uint64_t LhsConstant = LhsValue.getZExtValue();
651 uint64_t RhsConstant = RhsValue.getZExtValue();
652 SourceLocation
Loc = ComparisonOperator->getOperatorLoc();
655 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
657 diag(Loc,
"logical expression is always false");
658 else if (Opcode == BO_NE)
659 diag(Loc,
"logical expression is always true");
663 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
665 diag(Loc,
"logical expression is always false");
666 else if (Opcode == BO_NE)
667 diag(Loc,
"logical expression is always true");
672 void RedundantExpressionCheck::checkRelationalExpr(
673 const MatchFinder::MatchResult &Result) {
674 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
675 "comparisons-of-symbol-and-const")) {
677 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
679 const Expr *LhsExpr =
nullptr, *RhsExpr =
nullptr;
680 APSInt LhsValue, RhsValue;
681 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
682 BinaryOperatorKind LhsOpcode, RhsOpcode;
684 Result,
"lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue) ||
686 Result,
"rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue) ||
691 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
692 std::swap(LhsExpr, RhsExpr);
693 std::swap(LhsValue, RhsValue);
694 std::swap(LhsSymbol, RhsSymbol);
695 std::swap(LhsOpcode, RhsOpcode);
698 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
700 diag(ComparisonOperator->getOperatorLoc(),
701 "equivalent expression on both side of logical operator");
705 if (Opcode == BO_LAnd) {
707 diag(ComparisonOperator->getOperatorLoc(),
708 "logical expression is always false");
710 diag(LhsExpr->getExprLoc(),
"expression is redundant");
712 diag(RhsExpr->getExprLoc(),
"expression is redundant");
716 if (Opcode == BO_LOr) {
718 diag(ComparisonOperator->getOperatorLoc(),
719 "logical expression is always true");
721 diag(RhsExpr->getExprLoc(),
"expression is redundant");
723 diag(LhsExpr->getExprLoc(),
"expression is redundant");
729 void RedundantExpressionCheck::check(
const MatchFinder::MatchResult &Result) {
730 if (
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binary"))
731 diag(BinOp->getOperatorLoc(),
"both side of operator are equivalent");
732 if (
const auto *CondOp = Result.Nodes.getNodeAs<ConditionalOperator>(
"cond"))
733 diag(CondOp->getColonLoc(),
"'true' and 'false' expression are equivalent");
734 if (
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"call"))
735 diag(Call->getOperatorLoc(),
736 "both side of overloaded operator are equivalent");
738 checkArithmeticExpr(Result);
739 checkBitwiseExpr(Result);
740 checkRelationalExpr(Result);
SourceLocation Loc
'#' location in the include directive
static ast_matchers::internal::Matcher< Expr > matchRelationalIntegerConstantExpr(StringRef Id)
static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
std::unique_ptr< ast_matchers::MatchFinder > Finder
static const char KnownBannedMacroNames[]
static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, APSInt &Value)
static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left, const NestedNameSpecifier *Right)
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
static bool retrieveRelationalIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value)
static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result)
static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static ast_matchers::internal::Matcher< Expr > matchSymbolicExpr(StringRef Id)
static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&SymExpr)
static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool areEquivalentExpr(const Expr *Left, const Expr *Right)
static bool retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value)
static ast_matchers::internal::Matcher< Expr > matchBinOpIntegerConstantExpr(StringRef Id)
static ast_matchers::internal::Matcher< Expr > matchIntegerConstantExpr(StringRef Id)
static void canonicalNegateExpr(BinaryOperatorKind &Opcode, APSInt &Value)
AST_MATCHER(VarDecl, isAsm)
AST_MATCHER_P(Expr, expandedByMacro, std::set< std::string >, Names)