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;";
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))
246 const APSInt &ValueLHS,
247 BinaryOperatorKind OpcodeRHS,
248 const APSInt &ValueRHS) {
249 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
252 return OpcodeRHS == BO_EQ && Comparison == 0;
254 return (OpcodeRHS == BO_NE && Comparison == 0) ||
255 (OpcodeRHS == BO_EQ && Comparison != 0) ||
256 (OpcodeRHS == BO_LT && Comparison >= 0) ||
257 (OpcodeRHS == BO_LE && Comparison > 0) ||
258 (OpcodeRHS == BO_GT && Comparison <= 0) ||
259 (OpcodeRHS == BO_GE && Comparison < 0);
262 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
263 (OpcodeRHS == BO_LE && Comparison > 0) ||
264 (OpcodeRHS == BO_EQ && Comparison > 0));
266 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
267 (OpcodeRHS == BO_GE && Comparison < 0) ||
268 (OpcodeRHS == BO_EQ && Comparison < 0));
270 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
273 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
281 if (Opcode == BO_Sub) {
288 if (Node.isInstantiationDependent())
290 return Node.isIntegerConstantExpr(
Finder->getASTContext());
294 static ast_matchers::internal::Matcher<Expr>
296 std::string CstId = (Id +
"-const").str();
297 return expr(isIntegerConstantExpr()).bind(CstId);
303 StringRef Id, APSInt &Value) {
304 std::string CstId = (Id +
"-const").str();
305 const auto *CstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
306 return CstExpr && CstExpr->isIntegerConstantExpr(Value, *Result.Context);
312 std::string SymId = (Id +
"-sym").str();
313 return ignoringParenImpCasts(
314 expr(unless(isIntegerConstantExpr())).bind(SymId));
320 StringRef Id,
const Expr *&SymExpr) {
321 std::string SymId = (Id +
"-sym").str();
322 if (
const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
331 static ast_matchers::internal::Matcher<Expr>
333 const auto BinOpCstExpr =
335 anyOf(binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|"),
336 hasOperatorName(
"&")),
339 binaryOperator(hasOperatorName(
"-"),
343 return ignoringParenImpCasts(BinOpCstExpr);
350 StringRef Id, BinaryOperatorKind &Opcode,
351 const Expr *&Symbol, APSInt &Value) {
352 if (
const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
353 Opcode = BinExpr->getOpcode();
361 static ast_matchers::internal::Matcher<Expr>
363 std::string CastId = (Id +
"-cast").str();
364 std::string SwapId = (Id +
"-swap").str();
365 std::string NegateId = (Id +
"-negate").str();
367 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
368 isComparisonOperator(), expr().bind(Id),
376 const auto CastExpr =
377 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
381 const auto NegateRelationalExpr =
382 unaryOperator(hasOperatorName(
"!"),
383 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
386 const auto NegateNegateRelationalExpr =
387 unaryOperator(hasOperatorName(
"!"),
388 hasUnaryOperand(unaryOperator(
389 hasOperatorName(
"!"),
390 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
392 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
393 NegateNegateRelationalExpr);
400 StringRef Id,
const Expr *&OperandExpr,
401 BinaryOperatorKind &Opcode,
402 const Expr *&Symbol, APSInt &Value) {
403 std::string CastId = (Id +
"-cast").str();
404 std::string SwapId = (Id +
"-swap").str();
405 std::string NegateId = (Id +
"-negate").str();
407 if (
const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
409 Opcode = Bin->getOpcode();
413 }
else if (
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
417 Value = APSInt(32,
false);
425 if (Result.Nodes.getNodeAs<Expr>(SwapId))
426 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
427 if (Result.Nodes.getNodeAs<Expr>(NegateId))
428 Opcode = BinaryOperator::negateComparisonOp(Opcode);
442 return Node.getNumArgs() == 2 &&
447 return Node.getOperatorLoc().isMacroID();
451 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
454 AST_MATCHER(Expr, isMacro) {
return Node.getExprLoc().isMacroID(); }
457 const SourceManager &
SM =
Finder->getASTContext().getSourceManager();
458 const LangOptions &LO =
Finder->getASTContext().getLangOpts();
459 SourceLocation
Loc = Node.getExprLoc();
460 while (Loc.isMacroID()) {
461 std::string MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
462 if (Names.find(MacroName) != Names.end())
464 Loc = SM.getImmediateMacroCallerLoc(Loc);
469 void RedundantExpressionCheck::registerMatchers(MatchFinder *
Finder) {
470 const auto AnyLiteralExpr = ignoringParenImpCasts(
471 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
473 std::vector<std::string> MacroNames =
475 std::set<std::string> Names(MacroNames.begin(), MacroNames.end());
477 const auto BannedIntegerLiteral = integerLiteral(expandedByMacro(Names));
480 binaryOperator(anyOf(hasOperatorName(
"-"), hasOperatorName(
"/"),
481 hasOperatorName(
"%"), hasOperatorName(
"|"),
482 hasOperatorName(
"&"), hasOperatorName(
"^"),
483 matchers::isComparisonOperator(),
484 hasOperatorName(
"&&"), hasOperatorName(
"||"),
485 hasOperatorName(
"=")),
486 operandsAreEquivalent(),
488 unless(isInTemplateInstantiation()),
489 unless(binaryOperatorIsInMacro()),
490 unless(hasType(realFloatingPointType())),
491 unless(hasEitherOperand(hasType(realFloatingPointType()))),
492 unless(hasLHS(AnyLiteralExpr)),
493 unless(hasDescendant(BannedIntegerLiteral)))
498 conditionalOperator(expressionsAreEquivalent(),
500 unless(conditionalOperatorIsInMacro()),
501 unless(hasTrueExpression(AnyLiteralExpr)),
502 unless(isInTemplateInstantiation()))
509 hasOverloadedOperatorName(
"-"), hasOverloadedOperatorName(
"/"),
510 hasOverloadedOperatorName(
"%"), hasOverloadedOperatorName(
"|"),
511 hasOverloadedOperatorName(
"&"), hasOverloadedOperatorName(
"^"),
512 hasOverloadedOperatorName(
"=="), hasOverloadedOperatorName(
"!="),
513 hasOverloadedOperatorName(
"<"), hasOverloadedOperatorName(
"<="),
514 hasOverloadedOperatorName(
">"), hasOverloadedOperatorName(
">="),
515 hasOverloadedOperatorName(
"&&"), hasOverloadedOperatorName(
"||"),
516 hasOverloadedOperatorName(
"=")),
517 parametersAreEquivalent(),
519 unless(isMacro()), unless(isInTemplateInstantiation()))
535 Finder->addMatcher(binaryOperator(isComparisonOperator(),
536 hasEitherOperand(BinOpCstLeft),
537 hasEitherOperand(CstRight))
538 .bind(
"binop-const-compare-to-const"),
543 binaryOperator(isComparisonOperator(),
544 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
545 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
546 .bind(
"binop-const-compare-to-sym"),
550 Finder->addMatcher(binaryOperator(isComparisonOperator(),
551 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
553 unless(operandsAreEquivalent()))
554 .bind(
"binop-const-compare-to-binop-const"),
565 binaryOperator(anyOf(hasOperatorName(
"||"), hasOperatorName(
"&&")),
566 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
568 unless(operandsAreEquivalent()))
569 .bind(
"comparisons-of-symbol-and-const"),
573 void RedundantExpressionCheck::checkArithmeticExpr(
574 const MatchFinder::MatchResult &
Result) {
575 APSInt LhsValue, RhsValue;
576 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
577 BinaryOperatorKind LhsOpcode, RhsOpcode;
579 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
580 "binop-const-compare-to-sym")) {
581 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
589 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
590 if ((LhsValue != 0 && Opcode == BO_EQ) ||
591 (LhsValue == 0 && Opcode == BO_NE))
592 diag(ComparisonOperator->getOperatorLoc(),
593 "logical expression is always false");
594 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
595 (LhsValue != 0 && Opcode == BO_NE))
596 diag(ComparisonOperator->getOperatorLoc(),
597 "logical expression is always true");
599 }
else if (
const auto *ComparisonOperator =
600 Result.Nodes.getNodeAs<BinaryOperator>(
601 "binop-const-compare-to-binop-const")) {
602 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
615 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
616 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
617 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
618 diag(ComparisonOperator->getOperatorLoc(),
619 "logical expression is always true");
620 }
else if ((Opcode == BO_EQ &&
621 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
623 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
624 diag(ComparisonOperator->getOperatorLoc(),
625 "logical expression is always false");
631 void RedundantExpressionCheck::checkBitwiseExpr(
632 const MatchFinder::MatchResult &Result) {
633 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
634 "binop-const-compare-to-const")) {
635 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
637 APSInt LhsValue, RhsValue;
638 const Expr *LhsSymbol =
nullptr;
639 BinaryOperatorKind LhsOpcode;
645 uint64_t LhsConstant = LhsValue.getZExtValue();
646 uint64_t RhsConstant = RhsValue.getZExtValue();
647 SourceLocation
Loc = ComparisonOperator->getOperatorLoc();
650 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
652 diag(Loc,
"logical expression is always false");
653 else if (Opcode == BO_NE)
654 diag(Loc,
"logical expression is always true");
658 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
660 diag(Loc,
"logical expression is always false");
661 else if (Opcode == BO_NE)
662 diag(Loc,
"logical expression is always true");
667 void RedundantExpressionCheck::checkRelationalExpr(
668 const MatchFinder::MatchResult &Result) {
669 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
670 "comparisons-of-symbol-and-const")) {
672 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
674 const Expr *LhsExpr =
nullptr, *RhsExpr =
nullptr;
675 APSInt LhsValue, RhsValue;
676 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
677 BinaryOperatorKind LhsOpcode, RhsOpcode;
679 Result,
"lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue) ||
681 Result,
"rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue) ||
686 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
687 std::swap(LhsExpr, RhsExpr);
688 std::swap(LhsValue, RhsValue);
689 std::swap(LhsSymbol, RhsSymbol);
690 std::swap(LhsOpcode, RhsOpcode);
693 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
695 diag(ComparisonOperator->getOperatorLoc(),
696 "equivalent expression on both side of logical operator");
700 if (Opcode == BO_LAnd) {
702 diag(ComparisonOperator->getOperatorLoc(),
703 "logical expression is always false");
705 diag(LhsExpr->getExprLoc(),
"expression is redundant");
707 diag(RhsExpr->getExprLoc(),
"expression is redundant");
711 if (Opcode == BO_LOr) {
713 diag(ComparisonOperator->getOperatorLoc(),
714 "logical expression is always true");
716 diag(RhsExpr->getExprLoc(),
"expression is redundant");
718 diag(LhsExpr->getExprLoc(),
"expression is redundant");
724 void RedundantExpressionCheck::check(
const MatchFinder::MatchResult &Result) {
725 if (
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binary"))
726 diag(BinOp->getOperatorLoc(),
"both side of operator are equivalent");
727 if (
const auto *CondOp = Result.Nodes.getNodeAs<ConditionalOperator>(
"cond"))
728 diag(CondOp->getColonLoc(),
"'true' and 'false' expression are equivalent");
729 if (
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"call"))
730 diag(Call->getOperatorLoc(),
731 "both side of overloaded operator are equivalent");
733 checkArithmeticExpr(Result);
734 checkBitwiseExpr(Result);
735 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)
AST_MATCHER(Expr, isMacro)
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_P(Expr, expandedByMacro, std::set< std::string >, Names)