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" 38 static constexpr llvm::StringLiteral KnownBannedMacroNames[] = {
45 static bool incrementWithoutOverflow(
const APSInt &Value, APSInt &
Result) {
51 static bool areEquivalentNameSpecifier(
const NestedNameSpecifier *Left,
52 const NestedNameSpecifier *Right) {
53 llvm::FoldingSetNodeID LeftID, RightID;
54 Left->Profile(LeftID);
55 Right->Profile(RightID);
56 return LeftID == RightID;
59 static bool areEquivalentExpr(
const Expr *Left,
const Expr *Right) {
61 return !Left && !Right;
63 Left = Left->IgnoreParens();
64 Right = Right->IgnoreParens();
67 if (Left->getStmtClass() != Right->getStmtClass())
71 Expr::const_child_iterator LeftIter = Left->child_begin();
72 Expr::const_child_iterator RightIter = Right->child_begin();
73 while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
74 if (!areEquivalentExpr(dyn_cast<Expr>(*LeftIter),
75 dyn_cast<Expr>(*RightIter)))
80 if (LeftIter != Left->child_end() || RightIter != Right->child_end())
84 switch (Left->getStmtClass()) {
88 case Stmt::CharacterLiteralClass:
89 return cast<CharacterLiteral>(Left)->getValue() ==
90 cast<CharacterLiteral>(Right)->getValue();
91 case Stmt::IntegerLiteralClass: {
92 llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
93 llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
94 return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
97 case Stmt::FloatingLiteralClass:
98 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
99 cast<FloatingLiteral>(Right)->getValue());
100 case Stmt::StringLiteralClass:
101 return cast<StringLiteral>(Left)->getBytes() ==
102 cast<StringLiteral>(Right)->getBytes();
103 case Stmt::CXXOperatorCallExprClass:
104 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
105 cast<CXXOperatorCallExpr>(Right)->getOperator();
106 case Stmt::DependentScopeDeclRefExprClass:
107 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
108 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
110 return areEquivalentNameSpecifier(
111 cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
112 cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
113 case Stmt::DeclRefExprClass:
114 return cast<DeclRefExpr>(Left)->getDecl() ==
115 cast<DeclRefExpr>(Right)->getDecl();
116 case Stmt::MemberExprClass:
117 return cast<MemberExpr>(Left)->getMemberDecl() ==
118 cast<MemberExpr>(Right)->getMemberDecl();
119 case Stmt::CXXFunctionalCastExprClass:
120 case Stmt::CStyleCastExprClass:
121 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
122 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
123 case Stmt::CallExprClass:
124 case Stmt::ImplicitCastExprClass:
125 case Stmt::ArraySubscriptExprClass:
127 case Stmt::UnaryOperatorClass:
128 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
130 return cast<UnaryOperator>(Left)->getOpcode() ==
131 cast<UnaryOperator>(Right)->getOpcode();
132 case Stmt::BinaryOperatorClass:
133 return cast<BinaryOperator>(Left)->getOpcode() ==
134 cast<BinaryOperator>(Right)->getOpcode();
140 static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
141 const APSInt &ValueLHS,
142 BinaryOperatorKind OpcodeRHS,
143 const APSInt &ValueRHS) {
144 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
145 "Values must be ordered");
147 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
148 return OpcodeLHS == OpcodeRHS;
151 APSInt ValueLHS_plus1;
152 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
153 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
154 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
155 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
160 static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
161 const APSInt &ValueLHS,
162 BinaryOperatorKind OpcodeRHS,
163 const APSInt &ValueRHS) {
164 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
165 "Values must be ordered");
168 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
171 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
173 return OpcodeRHS == BO_EQ;
175 return OpcodeRHS == BO_GT;
177 return OpcodeRHS == BO_LT;
179 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
181 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
188 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
189 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
193 APSInt ValueLHS_plus1;
194 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
195 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
196 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
204 static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
205 const APSInt &ValueLHS,
206 BinaryOperatorKind OpcodeRHS,
207 const APSInt &ValueRHS) {
208 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
209 "Values must be ordered");
212 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
215 return OpcodeRHS == BO_NE;
217 return OpcodeRHS == BO_EQ;
219 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
221 return OpcodeRHS == BO_GE;
223 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
225 return OpcodeRHS == BO_LE;
232 APSInt ValueLHS_plus1;
233 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
234 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
235 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
239 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
240 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
245 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
251 static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
252 const APSInt &ValueLHS,
253 BinaryOperatorKind OpcodeRHS,
254 const APSInt &ValueRHS) {
255 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
258 return OpcodeRHS == BO_EQ && Comparison == 0;
260 return (OpcodeRHS == BO_NE && Comparison == 0) ||
261 (OpcodeRHS == BO_EQ && Comparison != 0) ||
262 (OpcodeRHS == BO_LT && Comparison >= 0) ||
263 (OpcodeRHS == BO_LE && Comparison > 0) ||
264 (OpcodeRHS == BO_GT && Comparison <= 0) ||
265 (OpcodeRHS == BO_GE && Comparison < 0);
268 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
269 (OpcodeRHS == BO_LE && Comparison > 0) ||
270 (OpcodeRHS == BO_EQ && Comparison > 0));
272 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
273 (OpcodeRHS == BO_GE && Comparison < 0) ||
274 (OpcodeRHS == BO_EQ && Comparison < 0));
276 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
279 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
286 static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
288 if (Opcode == BO_Sub) {
295 if (Node.isInstantiationDependent())
297 return Node.isIntegerConstantExpr(Finder->getASTContext());
300 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
301 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
304 AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
305 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
309 return Node.getNumArgs() == 2 &&
310 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
313 AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
314 return Node.getOperatorLoc().isMacroID();
317 AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
318 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
321 AST_MATCHER(Expr, isMacro) {
return Node.getExprLoc().isMacroID(); }
323 AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) {
324 const SourceManager &SM = Finder->getASTContext().getSourceManager();
325 const LangOptions &LO = Finder->getASTContext().getLangOpts();
326 SourceLocation
Loc = Node.getExprLoc();
327 while (Loc.isMacroID()) {
328 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
329 if (llvm::is_contained(Names, MacroName))
331 Loc = SM.getImmediateMacroCallerLoc(Loc);
337 static ast_matchers::internal::Matcher<Expr>
338 matchIntegerConstantExpr(StringRef Id) {
339 std::string CstId = (Id +
"-const").str();
340 return expr(isIntegerConstantExpr()).bind(CstId);
346 static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &
Result,
347 StringRef Id, APSInt &Value,
348 const Expr *&ConstExpr) {
349 std::string CstId = (Id +
"-const").str();
350 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
351 return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
355 static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
356 StringRef Id, APSInt &Value) {
357 const Expr *ConstExpr =
nullptr;
358 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
363 static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
364 std::string SymId = (Id +
"-sym").str();
365 return ignoringParenImpCasts(
366 expr(unless(isIntegerConstantExpr())).bind(SymId));
371 static bool retrieveSymbolicExpr(
const MatchFinder::MatchResult &Result,
372 StringRef Id,
const Expr *&SymExpr) {
373 std::string SymId = (Id +
"-sym").str();
374 if (
const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
383 static ast_matchers::internal::Matcher<Expr>
384 matchBinOpIntegerConstantExpr(StringRef Id) {
385 const auto BinOpCstExpr =
387 anyOf(binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|"),
388 hasOperatorName(
"&")),
389 hasEitherOperand(matchSymbolicExpr(Id)),
390 hasEitherOperand(matchIntegerConstantExpr(Id))),
391 binaryOperator(hasOperatorName(
"-"),
392 hasLHS(matchSymbolicExpr(Id)),
393 hasRHS(matchIntegerConstantExpr(Id)))))
395 return ignoringParenImpCasts(BinOpCstExpr);
401 retrieveBinOpIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
402 StringRef Id, BinaryOperatorKind &Opcode,
403 const Expr *&Symbol, APSInt &Value) {
404 if (
const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
405 Opcode = BinExpr->getOpcode();
406 return retrieveSymbolicExpr(Result, Id, Symbol) &&
407 retrieveIntegerConstantExpr(Result, Id, Value);
413 static ast_matchers::internal::Matcher<Expr>
414 matchRelationalIntegerConstantExpr(StringRef Id) {
415 std::string CastId = (Id +
"-cast").str();
416 std::string SwapId = (Id +
"-swap").str();
417 std::string NegateId = (Id +
"-negate").str();
418 std::string OverloadId = (Id +
"-overload").str();
420 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
421 isComparisonOperator(), expr().bind(Id),
422 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
423 hasRHS(matchIntegerConstantExpr(Id))),
424 allOf(hasLHS(matchIntegerConstantExpr(Id)),
425 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
429 const auto CastExpr =
430 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
431 hasSourceExpression(matchSymbolicExpr(Id)))
434 const auto NegateRelationalExpr =
435 unaryOperator(hasOperatorName(
"!"),
436 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
440 const auto NegateNegateRelationalExpr =
441 unaryOperator(hasOperatorName(
"!"),
442 hasUnaryOperand(unaryOperator(
443 hasOperatorName(
"!"),
444 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
446 const auto OverloadedOperatorExpr =
448 anyOf(hasOverloadedOperatorName(
"=="),
449 hasOverloadedOperatorName(
"!="), hasOverloadedOperatorName(
"<"),
450 hasOverloadedOperatorName(
"<="), hasOverloadedOperatorName(
">"),
451 hasOverloadedOperatorName(
">=")),
453 unless(isMacro()), unless(isInTemplateInstantiation()))
456 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
457 NegateNegateRelationalExpr, OverloadedOperatorExpr);
462 static bool isNonConstReferenceType(QualType ParamType) {
463 return ParamType->isReferenceType() &&
464 !ParamType.getNonReferenceType().isConstQualified();
474 canOverloadedOperatorArgsBeModified(
const FunctionDecl *OperatorDecl,
475 bool checkSecondParam) {
476 unsigned ParamCount = OperatorDecl->getNumParams();
481 if (ParamCount == 1 &&
482 !OperatorDecl->getType()->getAs<FunctionType>()->isConst())
485 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
488 return checkSecondParam && ParamCount == 2 &&
489 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
494 static bool retrieveRelationalIntegerConstantExpr(
495 const MatchFinder::MatchResult &Result, StringRef Id,
496 const Expr *&OperandExpr, BinaryOperatorKind &Opcode,
const Expr *&Symbol,
497 APSInt &Value,
const Expr *&ConstExpr) {
498 std::string CastId = (Id +
"-cast").str();
499 std::string SwapId = (Id +
"-swap").str();
500 std::string NegateId = (Id +
"-negate").str();
501 std::string OverloadId = (Id +
"-overload").str();
503 if (
const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
505 Opcode = Bin->getOpcode();
508 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
510 }
else if (
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
514 Value = APSInt(32,
false);
515 }
else if (
const auto *OverloadedOperatorExpr =
516 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
517 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
518 if (!OverloadedFunctionDecl)
521 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
false))
524 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
false))
527 if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
528 Value, *Result.Context))
531 Symbol = OverloadedOperatorExpr->getArg(0);
532 OperandExpr = OverloadedOperatorExpr;
533 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
535 return BinaryOperator::isComparisonOp(Opcode);
540 if (!retrieveSymbolicExpr(Result, Id, Symbol))
543 if (Result.Nodes.getNodeAs<Expr>(SwapId))
544 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
545 if (Result.Nodes.getNodeAs<Expr>(NegateId))
546 Opcode = BinaryOperator::negateComparisonOp(Opcode);
551 static bool areSidesBinaryConstExpressions(
const BinaryOperator *&BinOp,
const ASTContext *AstCtx) {
552 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
553 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
555 if (!LhsBinOp || !RhsBinOp)
558 if ((LhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
559 LhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)) &&
560 (RhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
561 RhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)))
569 static bool retrieveConstExprFromBothSides(
const BinaryOperator *&BinOp,
570 BinaryOperatorKind &MainOpcode,
571 BinaryOperatorKind &SideOpcode,
572 const Expr *&LhsConst,
573 const Expr *&RhsConst,
574 const ASTContext *AstCtx) {
575 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
576 "Both sides of binary operator must be constant expressions!");
578 MainOpcode = BinOp->getOpcode();
580 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
581 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
583 LhsConst = BinOpLhs->getLHS()->isIntegerConstantExpr(*AstCtx)
585 : BinOpLhs->getRHS();
586 RhsConst = BinOpRhs->getLHS()->isIntegerConstantExpr(*AstCtx)
588 : BinOpRhs->getRHS();
590 if (!LhsConst || !RhsConst)
593 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
594 "Sides of the binary operator must be equivalent expressions!");
596 SideOpcode = BinOpLhs->getOpcode();
601 static bool areExprsFromDifferentMacros(
const Expr *LhsExpr,
603 const ASTContext *AstCtx) {
604 if (!LhsExpr || !RhsExpr)
607 SourceLocation LhsLoc = LhsExpr->getExprLoc();
608 SourceLocation RhsLoc = RhsExpr->getExprLoc();
610 if (!LhsLoc.isMacroID() || !RhsLoc.isMacroID())
613 const SourceManager &SM = AstCtx->getSourceManager();
614 const LangOptions &LO = AstCtx->getLangOpts();
616 return !(Lexer::getImmediateMacroName(LhsLoc, SM, LO) ==
617 Lexer::getImmediateMacroName(RhsLoc, SM, LO));
620 static bool areExprsMacroAndNonMacro(
const Expr *&LhsExpr,
621 const Expr *&RhsExpr) {
622 if (!LhsExpr || !RhsExpr)
625 SourceLocation LhsLoc = LhsExpr->getExprLoc();
626 SourceLocation RhsLoc = RhsExpr->getExprLoc();
628 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
632 void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
633 const auto AnyLiteralExpr = ignoringParenImpCasts(
634 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
636 const auto BannedIntegerLiteral =
637 integerLiteral(expandedByMacro(KnownBannedMacroNames));
641 binaryOperator(anyOf(hasOperatorName(
"-"), hasOperatorName(
"/"),
642 hasOperatorName(
"%"), hasOperatorName(
"|"),
643 hasOperatorName(
"&"), hasOperatorName(
"^"),
644 matchers::isComparisonOperator(),
645 hasOperatorName(
"&&"), hasOperatorName(
"||"),
646 hasOperatorName(
"=")),
647 operandsAreEquivalent(),
649 unless(isInTemplateInstantiation()),
650 unless(binaryOperatorIsInMacro()),
651 unless(hasType(realFloatingPointType())),
652 unless(hasEitherOperand(hasType(realFloatingPointType()))),
653 unless(hasLHS(AnyLiteralExpr)),
654 unless(hasDescendant(BannedIntegerLiteral)))
659 Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
661 unless(conditionalOperatorIsInMacro()),
662 unless(isInTemplateInstantiation()))
670 hasOverloadedOperatorName(
"-"), hasOverloadedOperatorName(
"/"),
671 hasOverloadedOperatorName(
"%"), hasOverloadedOperatorName(
"|"),
672 hasOverloadedOperatorName(
"&"), hasOverloadedOperatorName(
"^"),
673 hasOverloadedOperatorName(
"=="), hasOverloadedOperatorName(
"!="),
674 hasOverloadedOperatorName(
"<"), hasOverloadedOperatorName(
"<="),
675 hasOverloadedOperatorName(
">"), hasOverloadedOperatorName(
">="),
676 hasOverloadedOperatorName(
"&&"), hasOverloadedOperatorName(
"||"),
677 hasOverloadedOperatorName(
"=")),
678 parametersAreEquivalent(),
680 unless(isMacro()), unless(isInTemplateInstantiation()))
687 hasImplicitDestinationType(isInteger()),
689 hasOperatorName(
"!"),
690 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
691 anyOf(hasOperatorName(
"|"), hasOperatorName(
"&")),
692 hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName(
"|"),
693 hasOperatorName(
"&"))),
695 hasRHS(integerLiteral())))))
696 .bind(
"logical-bitwise-confusion"))),
701 binaryOperator(hasOperatorName(
"&"),
702 hasEitherOperand(ignoringParenImpCasts(binaryOperator(
703 hasOperatorName(
"<<"),
704 hasRHS(ignoringParenImpCasts(
705 integerLiteral().bind(
"shift-const")))))),
706 hasEitherOperand(ignoringParenImpCasts(
707 integerLiteral().bind(
"and-const"))))
708 .bind(
"left-right-shift-confusion"),
717 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr(
"lhs");
718 const auto BinOpCstRight = matchBinOpIntegerConstantExpr(
"rhs");
719 const auto CstRight = matchIntegerConstantExpr(
"rhs");
720 const auto SymRight = matchSymbolicExpr(
"rhs");
723 Finder->addMatcher(binaryOperator(isComparisonOperator(),
724 hasEitherOperand(BinOpCstLeft),
725 hasEitherOperand(CstRight))
726 .bind(
"binop-const-compare-to-const"),
731 binaryOperator(isComparisonOperator(),
732 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
733 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
734 .bind(
"binop-const-compare-to-sym"),
738 Finder->addMatcher(binaryOperator(isComparisonOperator(),
739 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
741 unless(operandsAreEquivalent()))
742 .bind(
"binop-const-compare-to-binop-const"),
750 const auto ComparisonLeft = matchRelationalIntegerConstantExpr(
"lhs");
751 const auto ComparisonRight = matchRelationalIntegerConstantExpr(
"rhs");
753 binaryOperator(anyOf(hasOperatorName(
"||"), hasOperatorName(
"&&")),
754 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
756 unless(operandsAreEquivalent()))
757 .bind(
"comparisons-of-symbol-and-const"),
761 void RedundantExpressionCheck::checkArithmeticExpr(
762 const MatchFinder::MatchResult &Result) {
763 APSInt LhsValue, RhsValue;
764 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
765 BinaryOperatorKind LhsOpcode, RhsOpcode;
767 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
768 "binop-const-compare-to-sym")) {
769 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
770 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
772 !retrieveSymbolicExpr(Result,
"rhs", RhsSymbol) ||
773 !areEquivalentExpr(LhsSymbol, RhsSymbol))
777 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
778 if ((LhsValue != 0 && Opcode == BO_EQ) ||
779 (LhsValue == 0 && Opcode == BO_NE))
780 diag(ComparisonOperator->getOperatorLoc(),
781 "logical expression is always false");
782 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
783 (LhsValue != 0 && Opcode == BO_NE))
784 diag(ComparisonOperator->getOperatorLoc(),
785 "logical expression is always true");
787 }
else if (
const auto *ComparisonOperator =
788 Result.Nodes.getNodeAs<BinaryOperator>(
789 "binop-const-compare-to-binop-const")) {
790 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
792 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
794 !retrieveBinOpIntegerConstantExpr(Result,
"rhs", RhsOpcode, RhsSymbol,
796 !areEquivalentExpr(LhsSymbol, RhsSymbol))
799 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
800 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
803 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
804 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
805 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
806 diag(ComparisonOperator->getOperatorLoc(),
807 "logical expression is always true");
808 }
else if ((Opcode == BO_EQ &&
809 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
811 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
812 diag(ComparisonOperator->getOperatorLoc(),
813 "logical expression is always false");
820 return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
825 return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
829 return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
830 ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
834 void RedundantExpressionCheck::checkBitwiseExpr(
835 const MatchFinder::MatchResult &Result) {
836 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
837 "binop-const-compare-to-const")) {
838 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
840 APSInt LhsValue, RhsValue;
841 const Expr *LhsSymbol =
nullptr;
842 BinaryOperatorKind LhsOpcode;
843 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
845 !retrieveIntegerConstantExpr(Result,
"rhs", RhsValue))
848 uint64_t LhsConstant = LhsValue.getZExtValue();
849 uint64_t RhsConstant = RhsValue.getZExtValue();
850 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
853 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
855 diag(Loc,
"logical expression is always false");
856 else if (Opcode == BO_NE)
857 diag(Loc,
"logical expression is always true");
861 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
863 diag(Loc,
"logical expression is always false");
864 else if (Opcode == BO_NE)
865 diag(Loc,
"logical expression is always true");
867 }
else if (
const auto *IneffectiveOperator =
868 Result.Nodes.getNodeAs<BinaryOperator>(
869 "ineffective-bitwise")) {
871 const Expr *Sym =
nullptr, *ConstExpr =
nullptr;
873 if (!retrieveSymbolicExpr(Result,
"ineffective-bitwise", Sym) ||
874 !retrieveIntegerConstantExpr(Result,
"ineffective-bitwise", Value,
878 if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
881 SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
883 BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
885 diag(Loc,
"expression always evaluates to 0");
887 SourceRange ConstExprRange(ConstExpr->getBeginLoc(),
888 ConstExpr->getEndLoc());
889 StringRef ConstExprText = Lexer::getSourceText(
890 CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
891 Result.Context->getLangOpts());
893 diag(Loc,
"expression always evaluates to '%0'") << ConstExprText;
896 SourceRange SymExprRange(Sym->getBeginLoc(), Sym->getEndLoc());
898 StringRef ExprText = Lexer::getSourceText(
899 CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
900 Result.Context->getLangOpts());
902 diag(Loc,
"expression always evaluates to '%0'") << ExprText;
907 void RedundantExpressionCheck::checkRelationalExpr(
908 const MatchFinder::MatchResult &Result) {
909 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
910 "comparisons-of-symbol-and-const")) {
913 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
915 const Expr *LhsExpr =
nullptr, *RhsExpr =
nullptr;
916 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
917 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
918 BinaryOperatorKind LhsOpcode, RhsOpcode;
919 APSInt LhsValue, RhsValue;
921 if (!retrieveRelationalIntegerConstantExpr(
922 Result,
"lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
923 !retrieveRelationalIntegerConstantExpr(
924 Result,
"rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
925 !areEquivalentExpr(LhsSymbol, RhsSymbol))
929 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
930 std::swap(LhsExpr, RhsExpr);
931 std::swap(LhsValue, RhsValue);
932 std::swap(LhsSymbol, RhsSymbol);
933 std::swap(LhsOpcode, RhsOpcode);
937 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
938 areExprsMacroAndNonMacro(LhsConst, RhsConst))
941 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
942 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
943 diag(ComparisonOperator->getOperatorLoc(),
944 "equivalent expression on both sides of logical operator");
948 if (Opcode == BO_LAnd) {
949 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
950 diag(ComparisonOperator->getOperatorLoc(),
951 "logical expression is always false");
952 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
953 diag(LhsExpr->getExprLoc(),
"expression is redundant");
954 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
955 diag(RhsExpr->getExprLoc(),
"expression is redundant");
959 if (Opcode == BO_LOr) {
960 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
961 diag(ComparisonOperator->getOperatorLoc(),
962 "logical expression is always true");
963 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
964 diag(RhsExpr->getExprLoc(),
"expression is redundant");
965 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
966 diag(LhsExpr->getExprLoc(),
"expression is redundant");
972 void RedundantExpressionCheck::check(
const MatchFinder::MatchResult &Result) {
973 if (
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binary")) {
976 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
977 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
978 BinaryOperatorKind MainOpcode, SideOpcode;
980 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
981 LhsConst, RhsConst, Result.Context))
984 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
985 areExprsMacroAndNonMacro(LhsConst, RhsConst))
989 diag(BinOp->getOperatorLoc(),
"both sides of operator are equivalent");
992 if (
const auto *CondOp =
993 Result.Nodes.getNodeAs<ConditionalOperator>(
"cond")) {
994 const Expr *TrueExpr = CondOp->getTrueExpr();
995 const Expr *FalseExpr = CondOp->getFalseExpr();
997 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
998 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
1000 diag(CondOp->getColonLoc(),
1001 "'true' and 'false' expressions are equivalent");
1004 if (
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"call")) {
1005 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
1006 if (!OverloadedFunctionDecl)
1009 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
true))
1012 diag(Call->getOperatorLoc(),
1013 "both sides of overloaded operator are equivalent");
1016 if (
const auto *NegateOperator =
1017 Result.Nodes.getNodeAs<UnaryOperator>(
"logical-bitwise-confusion")) {
1018 SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1022 "ineffective logical negation operator used; did you mean '~'?");
1023 SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1025 if (!LogicalNotLocation.isMacroID())
1026 Diag << FixItHint::CreateReplacement(
1027 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation),
"~");
1030 if (
const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1031 "left-right-shift-confusion")) {
1032 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>(
"shift-const");
1033 assert(ShiftingConst &&
"Expr* 'ShiftingConst' is nullptr!");
1034 APSInt ShiftingValue;
1036 if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
1039 const auto *AndConst = Result.Nodes.getNodeAs<Expr>(
"and-const");
1040 assert(AndConst &&
"Expr* 'AndCont' is nullptr!");
1042 if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
1048 if (AndValue.getActiveBits() > ShiftingValue)
1051 auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
1052 "ineffective bitwise and operation");
1060 checkArithmeticExpr(Result);
1068 checkBitwiseExpr(Result);
1076 checkRelationalExpr(Result);
SourceLocation Loc
'#' location in the include directive
static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value)
AST_MATCHER(BinaryOperator, isAssignmentOperator)
static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value)
static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode, APSInt Value)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
AST_MATCHER_P(FunctionDecl, throws, internal::Matcher< Type >, InnerMatcher)