10 #include "../utils/Matchers.h" 11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/Basic/LLVM.h" 15 #include "clang/Basic/SourceLocation.h" 16 #include "clang/Basic/SourceManager.h" 17 #include "clang/Lex/Lexer.h" 18 #include "llvm/ADT/APInt.h" 19 #include "llvm/ADT/APSInt.h" 20 #include "llvm/ADT/FoldingSet.h" 21 #include "llvm/Support/Casting.h" 37 static constexpr llvm::StringLiteral KnownBannedMacroNames[] = {
44 static bool incrementWithoutOverflow(
const APSInt &Value, APSInt &
Result) {
50 static bool areEquivalentNameSpecifier(
const NestedNameSpecifier *Left,
51 const NestedNameSpecifier *Right) {
52 llvm::FoldingSetNodeID LeftID, RightID;
53 Left->Profile(LeftID);
54 Right->Profile(RightID);
55 return LeftID == RightID;
58 static bool areEquivalentExpr(
const Expr *Left,
const Expr *Right) {
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()) {
73 if (!areEquivalentExpr(dyn_cast<Expr>(*LeftIter),
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();
102 case Stmt::CXXOperatorCallExprClass:
103 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
104 cast<CXXOperatorCallExpr>(Right)->getOperator();
105 case Stmt::DependentScopeDeclRefExprClass:
106 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
107 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
109 return areEquivalentNameSpecifier(
110 cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
111 cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
112 case Stmt::DeclRefExprClass:
113 return cast<DeclRefExpr>(Left)->getDecl() ==
114 cast<DeclRefExpr>(Right)->getDecl();
115 case Stmt::MemberExprClass:
116 return cast<MemberExpr>(Left)->getMemberDecl() ==
117 cast<MemberExpr>(Right)->getMemberDecl();
118 case Stmt::CXXFunctionalCastExprClass:
119 case Stmt::CStyleCastExprClass:
120 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
121 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
122 case Stmt::CallExprClass:
123 case Stmt::ImplicitCastExprClass:
124 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();
139 static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
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)) &&
153 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
154 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
159 static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
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 &&
194 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
195 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
203 static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
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 &&
233 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
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)
250 static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
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) &&
285 static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
287 if (Opcode == BO_Sub) {
294 if (Node.isInstantiationDependent())
296 return Node.isIntegerConstantExpr(Finder->getASTContext());
299 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
300 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
303 AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
304 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
308 return Node.getNumArgs() == 2 &&
309 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
312 AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
313 return Node.getOperatorLoc().isMacroID();
316 AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
317 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
320 AST_MATCHER(Expr, isMacro) {
return Node.getExprLoc().isMacroID(); }
322 AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) {
323 const SourceManager &SM = Finder->getASTContext().getSourceManager();
324 const LangOptions &LO = Finder->getASTContext().getLangOpts();
325 SourceLocation
Loc = Node.getExprLoc();
326 while (Loc.isMacroID()) {
327 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
328 if (llvm::is_contained(Names, MacroName))
330 Loc = SM.getImmediateMacroCallerLoc(Loc);
336 static ast_matchers::internal::Matcher<Expr>
337 matchIntegerConstantExpr(StringRef Id) {
338 std::string CstId = (Id +
"-const").str();
339 return expr(isIntegerConstantExpr()).bind(CstId);
345 static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &
Result,
346 StringRef Id, APSInt &Value,
347 const Expr *&ConstExpr) {
348 std::string CstId = (Id +
"-const").str();
349 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
350 return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
354 static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
355 StringRef Id, APSInt &Value) {
356 const Expr *ConstExpr =
nullptr;
357 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
362 static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
363 std::string SymId = (Id +
"-sym").str();
364 return ignoringParenImpCasts(
365 expr(unless(isIntegerConstantExpr())).bind(SymId));
370 static bool retrieveSymbolicExpr(
const MatchFinder::MatchResult &Result,
371 StringRef Id,
const Expr *&SymExpr) {
372 std::string SymId = (Id +
"-sym").str();
373 if (
const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
382 static ast_matchers::internal::Matcher<Expr>
383 matchBinOpIntegerConstantExpr(StringRef Id) {
384 const auto BinOpCstExpr =
386 anyOf(binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|"),
387 hasOperatorName(
"&")),
388 hasEitherOperand(matchSymbolicExpr(Id)),
389 hasEitherOperand(matchIntegerConstantExpr(Id))),
390 binaryOperator(hasOperatorName(
"-"),
391 hasLHS(matchSymbolicExpr(Id)),
392 hasRHS(matchIntegerConstantExpr(Id)))))
394 return ignoringParenImpCasts(BinOpCstExpr);
400 retrieveBinOpIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
401 StringRef Id, BinaryOperatorKind &Opcode,
402 const Expr *&Symbol, APSInt &Value) {
403 if (
const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
404 Opcode = BinExpr->getOpcode();
405 return retrieveSymbolicExpr(Result, Id, Symbol) &&
406 retrieveIntegerConstantExpr(Result, Id, Value);
412 static ast_matchers::internal::Matcher<Expr>
413 matchRelationalIntegerConstantExpr(StringRef Id) {
414 std::string CastId = (Id +
"-cast").str();
415 std::string SwapId = (Id +
"-swap").str();
416 std::string NegateId = (Id +
"-negate").str();
417 std::string OverloadId = (Id +
"-overload").str();
419 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
420 isComparisonOperator(), expr().bind(Id),
421 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
422 hasRHS(matchIntegerConstantExpr(Id))),
423 allOf(hasLHS(matchIntegerConstantExpr(Id)),
424 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
428 const auto CastExpr =
429 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
430 hasSourceExpression(matchSymbolicExpr(Id)))
433 const auto NegateRelationalExpr =
434 unaryOperator(hasOperatorName(
"!"),
435 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
439 const auto NegateNegateRelationalExpr =
440 unaryOperator(hasOperatorName(
"!"),
441 hasUnaryOperand(unaryOperator(
442 hasOperatorName(
"!"),
443 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
445 const auto OverloadedOperatorExpr =
447 anyOf(hasOverloadedOperatorName(
"=="),
448 hasOverloadedOperatorName(
"!="), hasOverloadedOperatorName(
"<"),
449 hasOverloadedOperatorName(
"<="), hasOverloadedOperatorName(
">"),
450 hasOverloadedOperatorName(
">=")),
452 unless(isMacro()), unless(isInTemplateInstantiation()))
455 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
456 NegateNegateRelationalExpr, OverloadedOperatorExpr);
461 static bool isNonConstReferenceType(QualType ParamType) {
462 return ParamType->isReferenceType() &&
463 !ParamType.getNonReferenceType().isConstQualified();
473 canOverloadedOperatorArgsBeModified(
const FunctionDecl *OperatorDecl,
474 bool checkSecondParam) {
475 unsigned ParamCount = OperatorDecl->getNumParams();
480 if (ParamCount == 1 &&
481 !OperatorDecl->getType()->getAs<FunctionType>()->isConst())
484 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
487 return checkSecondParam && ParamCount == 2 &&
488 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
493 static bool retrieveRelationalIntegerConstantExpr(
494 const MatchFinder::MatchResult &Result, StringRef Id,
495 const Expr *&OperandExpr, BinaryOperatorKind &Opcode,
const Expr *&Symbol,
496 APSInt &Value,
const Expr *&ConstExpr) {
497 std::string CastId = (Id +
"-cast").str();
498 std::string SwapId = (Id +
"-swap").str();
499 std::string NegateId = (Id +
"-negate").str();
500 std::string OverloadId = (Id +
"-overload").str();
502 if (
const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
504 Opcode = Bin->getOpcode();
507 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
509 }
else if (
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
513 Value = APSInt(32,
false);
514 }
else if (
const auto *OverloadedOperatorExpr =
515 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
516 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
517 if (!OverloadedFunctionDecl)
520 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
false))
523 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
false))
526 if (
const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
527 if (!Arg->isValueDependent() &&
528 !Arg->isIntegerConstantExpr(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 auto IsIntegerConstantExpr = [AstCtx](
const Expr *E) {
559 return !E->isValueDependent() && E->isIntegerConstantExpr(*AstCtx);
562 if ((IsIntegerConstantExpr(LhsBinOp->getLHS()) ||
563 IsIntegerConstantExpr(LhsBinOp->getRHS())) &&
564 (IsIntegerConstantExpr(RhsBinOp->getLHS()) ||
565 IsIntegerConstantExpr(RhsBinOp->getRHS())))
573 static bool retrieveConstExprFromBothSides(
const BinaryOperator *&BinOp,
574 BinaryOperatorKind &MainOpcode,
575 BinaryOperatorKind &SideOpcode,
576 const Expr *&LhsConst,
577 const Expr *&RhsConst,
578 const ASTContext *AstCtx) {
579 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
580 "Both sides of binary operator must be constant expressions!");
582 MainOpcode = BinOp->getOpcode();
584 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
585 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
587 auto IsIntegerConstantExpr = [AstCtx](
const Expr *E) {
588 return !E->isValueDependent() && E->isIntegerConstantExpr(*AstCtx);
591 LhsConst = IsIntegerConstantExpr(BinOpLhs->getLHS()) ? BinOpLhs->getLHS()
592 : BinOpLhs->getRHS();
593 RhsConst = IsIntegerConstantExpr(BinOpRhs->getLHS()) ? BinOpRhs->getLHS()
594 : BinOpRhs->getRHS();
596 if (!LhsConst || !RhsConst)
599 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
600 "Sides of the binary operator must be equivalent expressions!");
602 SideOpcode = BinOpLhs->getOpcode();
607 static bool areExprsFromDifferentMacros(
const Expr *LhsExpr,
609 const ASTContext *AstCtx) {
610 if (!LhsExpr || !RhsExpr)
613 SourceLocation LhsLoc = LhsExpr->getExprLoc();
614 SourceLocation RhsLoc = RhsExpr->getExprLoc();
616 if (!LhsLoc.isMacroID() || !RhsLoc.isMacroID())
619 const SourceManager &SM = AstCtx->getSourceManager();
620 const LangOptions &LO = AstCtx->getLangOpts();
622 return !(Lexer::getImmediateMacroName(LhsLoc, SM, LO) ==
623 Lexer::getImmediateMacroName(RhsLoc, SM, LO));
626 static bool areExprsMacroAndNonMacro(
const Expr *&LhsExpr,
627 const Expr *&RhsExpr) {
628 if (!LhsExpr || !RhsExpr)
631 SourceLocation LhsLoc = LhsExpr->getExprLoc();
632 SourceLocation RhsLoc = RhsExpr->getExprLoc();
634 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
638 void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
639 const auto AnyLiteralExpr = ignoringParenImpCasts(
640 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
642 const auto BannedIntegerLiteral =
643 integerLiteral(expandedByMacro(KnownBannedMacroNames));
647 binaryOperator(anyOf(hasOperatorName(
"-"), hasOperatorName(
"/"),
648 hasOperatorName(
"%"), hasOperatorName(
"|"),
649 hasOperatorName(
"&"), hasOperatorName(
"^"),
650 matchers::isComparisonOperator(),
651 hasOperatorName(
"&&"), hasOperatorName(
"||"),
652 hasOperatorName(
"=")),
653 operandsAreEquivalent(),
655 unless(isInTemplateInstantiation()),
656 unless(binaryOperatorIsInMacro()),
657 unless(hasType(realFloatingPointType())),
658 unless(hasEitherOperand(hasType(realFloatingPointType()))),
659 unless(hasLHS(AnyLiteralExpr)),
660 unless(hasDescendant(BannedIntegerLiteral)))
665 Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
667 unless(conditionalOperatorIsInMacro()),
668 unless(isInTemplateInstantiation()))
676 hasOverloadedOperatorName(
"-"), hasOverloadedOperatorName(
"/"),
677 hasOverloadedOperatorName(
"%"), hasOverloadedOperatorName(
"|"),
678 hasOverloadedOperatorName(
"&"), hasOverloadedOperatorName(
"^"),
679 hasOverloadedOperatorName(
"=="), hasOverloadedOperatorName(
"!="),
680 hasOverloadedOperatorName(
"<"), hasOverloadedOperatorName(
"<="),
681 hasOverloadedOperatorName(
">"), hasOverloadedOperatorName(
">="),
682 hasOverloadedOperatorName(
"&&"), hasOverloadedOperatorName(
"||"),
683 hasOverloadedOperatorName(
"=")),
684 parametersAreEquivalent(),
686 unless(isMacro()), unless(isInTemplateInstantiation()))
693 hasImplicitDestinationType(isInteger()),
695 hasOperatorName(
"!"),
696 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
697 anyOf(hasOperatorName(
"|"), hasOperatorName(
"&")),
698 hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName(
"|"),
699 hasOperatorName(
"&"))),
701 hasRHS(integerLiteral())))))
702 .bind(
"logical-bitwise-confusion"))),
707 binaryOperator(hasOperatorName(
"&"),
708 hasEitherOperand(ignoringParenImpCasts(binaryOperator(
709 hasOperatorName(
"<<"),
710 hasRHS(ignoringParenImpCasts(
711 integerLiteral().bind(
"shift-const")))))),
712 hasEitherOperand(ignoringParenImpCasts(
713 integerLiteral().bind(
"and-const"))))
714 .bind(
"left-right-shift-confusion"),
723 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr(
"lhs");
724 const auto BinOpCstRight = matchBinOpIntegerConstantExpr(
"rhs");
725 const auto CstRight = matchIntegerConstantExpr(
"rhs");
726 const auto SymRight = matchSymbolicExpr(
"rhs");
729 Finder->addMatcher(binaryOperator(isComparisonOperator(),
730 hasEitherOperand(BinOpCstLeft),
731 hasEitherOperand(CstRight))
732 .bind(
"binop-const-compare-to-const"),
737 binaryOperator(isComparisonOperator(),
738 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
739 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
740 .bind(
"binop-const-compare-to-sym"),
744 Finder->addMatcher(binaryOperator(isComparisonOperator(),
745 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
747 unless(operandsAreEquivalent()))
748 .bind(
"binop-const-compare-to-binop-const"),
756 const auto ComparisonLeft = matchRelationalIntegerConstantExpr(
"lhs");
757 const auto ComparisonRight = matchRelationalIntegerConstantExpr(
"rhs");
759 binaryOperator(anyOf(hasOperatorName(
"||"), hasOperatorName(
"&&")),
760 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
762 unless(operandsAreEquivalent()))
763 .bind(
"comparisons-of-symbol-and-const"),
767 void RedundantExpressionCheck::checkArithmeticExpr(
768 const MatchFinder::MatchResult &Result) {
769 APSInt LhsValue, RhsValue;
770 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
771 BinaryOperatorKind LhsOpcode, RhsOpcode;
773 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
774 "binop-const-compare-to-sym")) {
775 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
776 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
778 !retrieveSymbolicExpr(Result,
"rhs", RhsSymbol) ||
779 !areEquivalentExpr(LhsSymbol, RhsSymbol))
783 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
784 if ((LhsValue != 0 && Opcode == BO_EQ) ||
785 (LhsValue == 0 && Opcode == BO_NE))
786 diag(ComparisonOperator->getOperatorLoc(),
787 "logical expression is always false");
788 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
789 (LhsValue != 0 && Opcode == BO_NE))
790 diag(ComparisonOperator->getOperatorLoc(),
791 "logical expression is always true");
793 }
else if (
const auto *ComparisonOperator =
794 Result.Nodes.getNodeAs<BinaryOperator>(
795 "binop-const-compare-to-binop-const")) {
796 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
798 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
800 !retrieveBinOpIntegerConstantExpr(Result,
"rhs", RhsOpcode, RhsSymbol,
802 !areEquivalentExpr(LhsSymbol, RhsSymbol))
805 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
806 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
809 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
810 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
811 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
812 diag(ComparisonOperator->getOperatorLoc(),
813 "logical expression is always true");
814 }
else if ((Opcode == BO_EQ &&
815 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
817 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
818 diag(ComparisonOperator->getOperatorLoc(),
819 "logical expression is always false");
826 return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
831 return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
835 return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
836 ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
840 void RedundantExpressionCheck::checkBitwiseExpr(
841 const MatchFinder::MatchResult &Result) {
842 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
843 "binop-const-compare-to-const")) {
844 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
846 APSInt LhsValue, RhsValue;
847 const Expr *LhsSymbol =
nullptr;
848 BinaryOperatorKind LhsOpcode;
849 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
851 !retrieveIntegerConstantExpr(Result,
"rhs", RhsValue))
854 uint64_t LhsConstant = LhsValue.getZExtValue();
855 uint64_t RhsConstant = RhsValue.getZExtValue();
856 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
859 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
861 diag(Loc,
"logical expression is always false");
862 else if (Opcode == BO_NE)
863 diag(Loc,
"logical expression is always true");
867 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
869 diag(Loc,
"logical expression is always false");
870 else if (Opcode == BO_NE)
871 diag(Loc,
"logical expression is always true");
873 }
else if (
const auto *IneffectiveOperator =
874 Result.Nodes.getNodeAs<BinaryOperator>(
875 "ineffective-bitwise")) {
877 const Expr *Sym =
nullptr, *ConstExpr =
nullptr;
879 if (!retrieveSymbolicExpr(Result,
"ineffective-bitwise", Sym) ||
880 !retrieveIntegerConstantExpr(Result,
"ineffective-bitwise", Value,
884 if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
887 SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
889 BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
891 diag(Loc,
"expression always evaluates to 0");
893 SourceRange ConstExprRange(ConstExpr->getBeginLoc(),
894 ConstExpr->getEndLoc());
895 StringRef ConstExprText = Lexer::getSourceText(
897 Result.Context->getLangOpts());
899 diag(Loc,
"expression always evaluates to '%0'") << ConstExprText;
902 SourceRange SymExprRange(Sym->getBeginLoc(), Sym->getEndLoc());
904 StringRef ExprText = Lexer::getSourceText(
906 Result.Context->getLangOpts());
908 diag(Loc,
"expression always evaluates to '%0'") << ExprText;
913 void RedundantExpressionCheck::checkRelationalExpr(
914 const MatchFinder::MatchResult &Result) {
915 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
916 "comparisons-of-symbol-and-const")) {
919 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
921 const Expr *LhsExpr =
nullptr, *RhsExpr =
nullptr;
922 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
923 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
924 BinaryOperatorKind LhsOpcode, RhsOpcode;
925 APSInt LhsValue, RhsValue;
927 if (!retrieveRelationalIntegerConstantExpr(
928 Result,
"lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
929 !retrieveRelationalIntegerConstantExpr(
930 Result,
"rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
931 !areEquivalentExpr(LhsSymbol, RhsSymbol))
935 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
936 std::swap(LhsExpr, RhsExpr);
937 std::swap(LhsValue, RhsValue);
938 std::swap(LhsSymbol, RhsSymbol);
939 std::swap(LhsOpcode, RhsOpcode);
943 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
944 areExprsMacroAndNonMacro(LhsConst, RhsConst))
947 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
948 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
949 diag(ComparisonOperator->getOperatorLoc(),
950 "equivalent expression on both sides of logical operator");
954 if (Opcode == BO_LAnd) {
955 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
956 diag(ComparisonOperator->getOperatorLoc(),
957 "logical expression is always false");
958 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
959 diag(LhsExpr->getExprLoc(),
"expression is redundant");
960 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
961 diag(RhsExpr->getExprLoc(),
"expression is redundant");
965 if (Opcode == BO_LOr) {
966 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
967 diag(ComparisonOperator->getOperatorLoc(),
968 "logical expression is always true");
969 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
970 diag(RhsExpr->getExprLoc(),
"expression is redundant");
971 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
972 diag(LhsExpr->getExprLoc(),
"expression is redundant");
978 void RedundantExpressionCheck::check(
const MatchFinder::MatchResult &Result) {
979 if (
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binary")) {
982 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
983 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
984 BinaryOperatorKind MainOpcode, SideOpcode;
986 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
987 LhsConst, RhsConst, Result.Context))
990 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
991 areExprsMacroAndNonMacro(LhsConst, RhsConst))
995 diag(BinOp->getOperatorLoc(),
"both sides of operator are equivalent");
998 if (
const auto *CondOp =
999 Result.Nodes.getNodeAs<ConditionalOperator>(
"cond")) {
1000 const Expr *TrueExpr = CondOp->getTrueExpr();
1001 const Expr *FalseExpr = CondOp->getFalseExpr();
1003 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
1004 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
1006 diag(CondOp->getColonLoc(),
1007 "'true' and 'false' expressions are equivalent");
1010 if (
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"call")) {
1011 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
1012 if (!OverloadedFunctionDecl)
1015 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
true))
1018 diag(Call->getOperatorLoc(),
1019 "both sides of overloaded operator are equivalent");
1022 if (
const auto *NegateOperator =
1023 Result.Nodes.getNodeAs<UnaryOperator>(
"logical-bitwise-confusion")) {
1024 SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1028 "ineffective logical negation operator used; did you mean '~'?");
1029 SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1031 if (!LogicalNotLocation.isMacroID())
1032 Diag << FixItHint::CreateReplacement(
1033 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation),
"~");
1036 if (
const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1037 "left-right-shift-confusion")) {
1038 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>(
"shift-const");
1039 assert(ShiftingConst &&
"Expr* 'ShiftingConst' is nullptr!");
1040 APSInt ShiftingValue;
1042 if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
1045 const auto *AndConst = Result.Nodes.getNodeAs<Expr>(
"and-const");
1046 assert(AndConst &&
"Expr* 'AndCont' is nullptr!");
1048 if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
1054 if (AndValue.getActiveBits() > ShiftingValue)
1057 auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
1058 "ineffective bitwise and operation");
1066 checkArithmeticExpr(Result);
1074 checkBitwiseExpr(Result);
1082 checkRelationalExpr(Result);
SourceLocation Loc
'#' location in the include directive
static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value)
AST_MATCHER(Expr, isMacroID)
static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value)
static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode, APSInt Value)
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl, ast_matchers::internal::Matcher< CXXMethodDecl >, InnerMatcher)