11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Basic/LLVM.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/Lex/Lexer.h"
17#include "llvm/ADT/APInt.h"
18#include "llvm/ADT/APSInt.h"
19#include "llvm/ADT/FoldingSet.h"
20#include "llvm/ADT/SmallBitVector.h"
21#include "llvm/Support/FormatVariadic.h"
35static constexpr llvm::StringLiteral KnownBannedMacroNames[] = {
42static bool incrementWithoutOverflow(
const APSInt &
Value, APSInt &Result) {
45 return Value < Result;
48static bool areEquivalentExpr(
const Expr *Left,
const Expr *Right) {
56 if (
Left->getStmtClass() !=
Right->getStmtClass())
60 Expr::const_child_iterator LeftIter =
Left->child_begin();
61 Expr::const_child_iterator RightIter =
Right->child_begin();
62 while (LeftIter !=
Left->child_end() && RightIter !=
Right->child_end()) {
63 if (!areEquivalentExpr(dyn_cast_or_null<Expr>(*LeftIter),
64 dyn_cast_or_null<Expr>(*RightIter)))
69 if (LeftIter !=
Left->child_end() || RightIter !=
Right->child_end())
73 switch (
Left->getStmtClass()) {
77 case Stmt::CharacterLiteralClass:
78 return cast<CharacterLiteral>(Left)->getValue() ==
79 cast<CharacterLiteral>(Right)->getValue();
80 case Stmt::IntegerLiteralClass: {
81 llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
82 llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
83 return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
86 case Stmt::FloatingLiteralClass:
87 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
88 cast<FloatingLiteral>(Right)->getValue());
89 case Stmt::StringLiteralClass:
90 return cast<StringLiteral>(Left)->getBytes() ==
91 cast<StringLiteral>(Right)->getBytes();
92 case Stmt::CXXOperatorCallExprClass:
93 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
94 cast<CXXOperatorCallExpr>(Right)->getOperator();
95 case Stmt::DependentScopeDeclRefExprClass:
96 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
97 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
99 return cast<DependentScopeDeclRefExpr>(Left)->getQualifier() ==
100 cast<DependentScopeDeclRefExpr>(Right)->getQualifier();
101 case Stmt::DeclRefExprClass:
102 return cast<DeclRefExpr>(Left)->getDecl() ==
103 cast<DeclRefExpr>(Right)->getDecl();
104 case Stmt::MemberExprClass:
105 return cast<MemberExpr>(Left)->getMemberDecl() ==
106 cast<MemberExpr>(Right)->getMemberDecl();
107 case Stmt::CXXFoldExprClass:
108 return cast<CXXFoldExpr>(Left)->getOperator() ==
109 cast<CXXFoldExpr>(Right)->getOperator();
110 case Stmt::CXXFunctionalCastExprClass:
111 case Stmt::CStyleCastExprClass:
112 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
113 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
114 case Stmt::CallExprClass:
115 case Stmt::ImplicitCastExprClass:
116 case Stmt::ArraySubscriptExprClass:
118 case Stmt::UnaryOperatorClass:
119 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
121 return cast<UnaryOperator>(Left)->getOpcode() ==
122 cast<UnaryOperator>(Right)->getOpcode();
123 case Stmt::BinaryOperatorClass:
124 if (cast<BinaryOperator>(Left)->isAssignmentOp())
126 return cast<BinaryOperator>(Left)->getOpcode() ==
127 cast<BinaryOperator>(Right)->getOpcode();
128 case Stmt::UnaryExprOrTypeTraitExprClass:
129 const auto *LeftUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Left);
130 const auto *RightUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Right);
131 if (LeftUnaryExpr->isArgumentType() && RightUnaryExpr->isArgumentType())
132 return LeftUnaryExpr->getKind() == RightUnaryExpr->getKind() &&
133 LeftUnaryExpr->getArgumentType() ==
134 RightUnaryExpr->getArgumentType();
135 if (!LeftUnaryExpr->isArgumentType() && !RightUnaryExpr->isArgumentType())
136 return areEquivalentExpr(LeftUnaryExpr->getArgumentExpr(),
137 RightUnaryExpr->getArgumentExpr());
145static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
146 const APSInt &ValueLHS,
147 BinaryOperatorKind OpcodeRHS,
148 const APSInt &ValueRHS) {
149 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
150 "Values must be ordered");
152 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
153 return OpcodeLHS == OpcodeRHS;
156 APSInt ValueLhsPlus1;
157 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
158 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
159 incrementWithoutOverflow(ValueLHS, ValueLhsPlus1) &&
160 APSInt::compareValues(ValueLhsPlus1, ValueRHS) == 0;
165static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
166 const APSInt &ValueLHS,
167 BinaryOperatorKind OpcodeRHS,
168 const APSInt &ValueRHS) {
169 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
170 "Values must be ordered");
173 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
176 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
178 return OpcodeRHS == BO_EQ;
180 return OpcodeRHS == BO_GT;
182 return OpcodeRHS == BO_LT;
184 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
186 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
193 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
194 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
198 APSInt ValueLhsPlus1;
199 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
200 incrementWithoutOverflow(ValueLHS, ValueLhsPlus1) &&
201 APSInt::compareValues(ValueLhsPlus1, ValueRHS) == 0)
209static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
210 const APSInt &ValueLHS,
211 BinaryOperatorKind OpcodeRHS,
212 const APSInt &ValueRHS) {
213 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
214 "Values must be ordered");
217 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
220 return OpcodeRHS == BO_NE;
222 return OpcodeRHS == BO_EQ;
224 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
226 return OpcodeRHS == BO_GE;
228 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
230 return OpcodeRHS == BO_LE;
237 APSInt ValueLhsPlus1;
238 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
239 incrementWithoutOverflow(ValueLHS, ValueLhsPlus1) &&
240 APSInt::compareValues(ValueLhsPlus1, ValueRHS) == 0)
244 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
245 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
250 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
256static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
257 const APSInt &ValueLHS,
258 BinaryOperatorKind OpcodeRHS,
259 const APSInt &ValueRHS) {
260 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
263 return OpcodeRHS == BO_EQ && Comparison == 0;
265 return (OpcodeRHS == BO_NE && Comparison == 0) ||
266 (OpcodeRHS == BO_EQ && Comparison != 0) ||
267 (OpcodeRHS == BO_LT && Comparison >= 0) ||
268 (OpcodeRHS == BO_LE && Comparison > 0) ||
269 (OpcodeRHS == BO_GT && Comparison <= 0) ||
270 (OpcodeRHS == BO_GE && Comparison < 0);
273 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
274 (OpcodeRHS == BO_LE && Comparison > 0) ||
275 (OpcodeRHS == BO_EQ && Comparison > 0));
277 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
278 (OpcodeRHS == BO_GE && Comparison < 0) ||
279 (OpcodeRHS == BO_EQ && Comparison < 0));
281 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
284 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
291static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
293 if (Opcode == BO_Sub) {
300static OverloadedOperatorKind getOp(
const BinaryOperator *Op) {
301 return BinaryOperator::getOverloadedOperator(Op->getOpcode());
304static OverloadedOperatorKind getOp(
const CXXOperatorCallExpr *Op) {
305 if (Op->getNumArgs() != 2)
307 return Op->getOperator();
310static std::pair<const Expr *, const Expr *>
311getOperands(
const BinaryOperator *Op) {
312 return {Op->getLHS()->IgnoreParenImpCasts(),
313 Op->getRHS()->IgnoreParenImpCasts()};
316static std::pair<const Expr *, const Expr *>
317getOperands(
const CXXOperatorCallExpr *Op) {
318 return {Op->getArg(0)->IgnoreParenImpCasts(),
319 Op->getArg(1)->IgnoreParenImpCasts()};
322template <
typename TExpr>
323static const TExpr *checkOpKind(
const Expr *TheExpr,
324 OverloadedOperatorKind OpKind) {
325 const auto *AsTExpr = dyn_cast_or_null<TExpr>(TheExpr);
326 if (AsTExpr && getOp(AsTExpr) == OpKind)
334template <
typename TExpr,
unsigned N>
335static bool collectOperands(
const Expr *Part,
336 SmallVector<const Expr *, N> &AllOperands,
337 OverloadedOperatorKind OpKind) {
338 if (
const auto *BinOp = checkOpKind<TExpr>(Part, OpKind)) {
339 const std::pair<const Expr *, const Expr *> Operands = getOperands(BinOp);
340 if (areEquivalentExpr(Operands.first, Operands.second))
342 return collectOperands<TExpr>(Operands.first, AllOperands, OpKind) ||
343 collectOperands<TExpr>(Operands.second, AllOperands, OpKind);
346 AllOperands.push_back(Part);
350template <
typename TExpr>
351static bool hasSameOperatorParent(
const Expr *TheExpr,
352 OverloadedOperatorKind OpKind,
353 ASTContext &Context) {
355 const DynTypedNodeList
Parents = Context.getParents(*TheExpr);
356 for (DynTypedNode DynParent : Parents) {
357 if (
const auto *Parent = DynParent.get<Expr>()) {
358 bool Skip = isa<ParenExpr>(Parent) || isa<ImplicitCastExpr>(Parent) ||
359 isa<FullExpr>(Parent) ||
360 isa<MaterializeTemporaryExpr>(Parent);
361 if (Skip && hasSameOperatorParent<TExpr>(Parent, OpKind, Context))
363 if (checkOpKind<TExpr>(Parent, OpKind))
371template <
typename TExpr>
373markDuplicateOperands(
const TExpr *TheExpr,
374 ast_matchers::internal::BoundNodesTreeBuilder *Builder,
375 ASTContext &Context) {
376 const OverloadedOperatorKind OpKind = getOp(TheExpr);
377 if (OpKind == OO_None)
381 const std::pair<const Expr *, const Expr *> Operands = getOperands(TheExpr);
382 if (!(checkOpKind<TExpr>(Operands.first, OpKind) ||
383 checkOpKind<TExpr>(Operands.second, OpKind)))
388 if (hasSameOperatorParent<TExpr>(TheExpr, OpKind, Context))
391 SmallVector<const Expr *, 4> AllOperands;
392 if (collectOperands<TExpr>(Operands.first, AllOperands, OpKind))
394 if (collectOperands<TExpr>(Operands.second, AllOperands, OpKind))
396 size_t NumOperands = AllOperands.size();
397 llvm::SmallBitVector Duplicates(NumOperands);
398 for (
size_t I = 0; I < NumOperands; I++) {
401 bool FoundDuplicates =
false;
403 for (
size_t J = I + 1; J < NumOperands; J++) {
404 if (AllOperands[J]->HasSideEffects(Context))
407 if (areEquivalentExpr(AllOperands[I], AllOperands[J])) {
408 FoundDuplicates =
true;
410 Builder->setBinding(SmallString<11>(llvm::formatv(
"duplicate{0}", J)),
411 DynTypedNode::create(*AllOperands[J]));
416 Builder->setBinding(SmallString<11>(llvm::formatv(
"duplicate{0}", I)),
417 DynTypedNode::create(*AllOperands[I]));
420 return Duplicates.any();
424 if (Node.isInstantiationDependent())
426 return Node.isIntegerConstantExpr(Finder->getASTContext());
429AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
430 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
433AST_MATCHER(BinaryOperator, nestedOperandsAreEquivalent) {
434 return markDuplicateOperands(&Node, Builder, Finder->getASTContext());
437AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
438 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
442 return Node.getNumArgs() == 2 &&
443 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
446AST_MATCHER(CXXOperatorCallExpr, nestedParametersAreEquivalent) {
447 return markDuplicateOperands(&Node, Builder, Finder->getASTContext());
450AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
451 return Node.getOperatorLoc().isMacroID();
454AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
455 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
458AST_MATCHER(Expr, isMacro) {
return Node.getExprLoc().isMacroID(); }
460AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) {
461 const SourceManager &SM = Finder->getASTContext().getSourceManager();
462 const LangOptions &LO = Finder->getASTContext().getLangOpts();
463 SourceLocation Loc = Node.getExprLoc();
464 while (Loc.isMacroID()) {
465 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
466 if (llvm::is_contained(Names, MacroName))
468 Loc = SM.getImmediateMacroCallerLoc(Loc);
474static ast_matchers::internal::Matcher<Expr>
475matchIntegerConstantExpr(StringRef Id) {
476 std::string CstId = (Id +
"-const").str();
477 return expr(isIntegerConstantExpr()).bind(CstId);
483static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
484 StringRef Id, APSInt &
Value,
485 const Expr *&ConstExpr) {
486 std::string CstId = (Id +
"-const").str();
487 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
490 std::optional<llvm::APSInt> R =
491 ConstExpr->getIntegerConstantExpr(*Result.Context);
499static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
500 StringRef Id, APSInt &
Value) {
501 const Expr *ConstExpr =
nullptr;
502 return retrieveIntegerConstantExpr(Result, Id,
Value, ConstExpr);
507static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
508 std::string SymId = (Id +
"-sym").str();
509 return ignoringParenImpCasts(
510 expr(unless(isIntegerConstantExpr())).bind(SymId));
515static bool retrieveSymbolicExpr(
const MatchFinder::MatchResult &Result,
516 StringRef Id,
const Expr *&SymExpr) {
517 std::string SymId = (Id +
"-sym").str();
518 if (
const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
527static ast_matchers::internal::Matcher<Expr>
528matchBinOpIntegerConstantExpr(StringRef Id) {
529 const auto BinOpCstExpr =
530 expr(anyOf(binaryOperator(hasAnyOperatorName(
"+",
"|",
"&"),
531 hasOperands(matchSymbolicExpr(Id),
532 matchIntegerConstantExpr(Id))),
533 binaryOperator(hasOperatorName(
"-"),
534 hasLHS(matchSymbolicExpr(Id)),
535 hasRHS(matchIntegerConstantExpr(Id)))))
537 return ignoringParenImpCasts(BinOpCstExpr);
543retrieveBinOpIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
544 StringRef Id, BinaryOperatorKind &Opcode,
545 const Expr *&Symbol, APSInt &
Value) {
546 if (
const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
547 Opcode = BinExpr->getOpcode();
548 return retrieveSymbolicExpr(Result, Id, Symbol) &&
549 retrieveIntegerConstantExpr(Result, Id,
Value);
555static ast_matchers::internal::Matcher<Expr>
556matchRelationalIntegerConstantExpr(StringRef Id) {
557 std::string CastId = (Id +
"-cast").str();
558 std::string SwapId = (Id +
"-swap").str();
559 std::string NegateId = (Id +
"-negate").str();
560 std::string OverloadId = (Id +
"-overload").str();
561 std::string ConstId = (Id +
"-const").str();
563 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
564 isComparisonOperator(), expr().bind(Id),
565 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
566 hasRHS(matchIntegerConstantExpr(Id))),
567 allOf(hasLHS(matchIntegerConstantExpr(Id)),
568 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
572 const auto CastExpr =
573 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
574 hasSourceExpression(matchSymbolicExpr(Id)))
577 const auto NegateRelationalExpr =
578 unaryOperator(hasOperatorName(
"!"),
579 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
583 const auto NegateNegateRelationalExpr =
584 unaryOperator(hasOperatorName(
"!"),
585 hasUnaryOperand(unaryOperator(
586 hasOperatorName(
"!"),
587 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
589 const auto OverloadedOperatorExpr =
591 hasAnyOverloadedOperatorName(
"==",
"!=",
"<",
"<=",
">",
">="),
593 unless(isMacro()), unless(isInTemplateInstantiation()),
594 anyOf(hasLHS(ignoringParenImpCasts(integerLiteral().bind(ConstId))),
595 hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId)))))
598 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
599 NegateNegateRelationalExpr, OverloadedOperatorExpr);
604static bool isNonConstReferenceType(QualType ParamType) {
605 return ParamType->isReferenceType() &&
606 !ParamType.getNonReferenceType().isConstQualified();
616canOverloadedOperatorArgsBeModified(
const CXXOperatorCallExpr *OperatorCall,
617 bool CheckSecondParam) {
618 const auto *OperatorDecl =
619 dyn_cast_or_null<FunctionDecl>(OperatorCall->getCalleeDecl());
625 unsigned ParamCount = OperatorDecl->getNumParams();
630 if (ParamCount == 1 &&
631 !OperatorDecl->getType()->castAs<FunctionType>()->isConst())
634 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
637 return CheckSecondParam && ParamCount == 2 &&
638 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
643static bool retrieveRelationalIntegerConstantExpr(
644 const MatchFinder::MatchResult &Result, StringRef Id,
645 const Expr *&OperandExpr, BinaryOperatorKind &Opcode,
const Expr *&Symbol,
646 APSInt &
Value,
const Expr *&ConstExpr) {
647 std::string CastId = (Id +
"-cast").str();
648 std::string SwapId = (Id +
"-swap").str();
649 std::string NegateId = (Id +
"-negate").str();
650 std::string OverloadId = (Id +
"-overload").str();
652 if (
const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
654 Opcode = Bin->getOpcode();
657 if (!retrieveIntegerConstantExpr(Result, Id,
Value, ConstExpr))
659 }
else if (
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
663 Value = APSInt(32,
false);
664 }
else if (
const auto *OverloadedOperatorExpr =
665 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
666 if (canOverloadedOperatorArgsBeModified(OverloadedOperatorExpr,
false))
669 bool IntegerConstantIsFirstArg =
false;
671 if (
const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
672 if (!Arg->isValueDependent() &&
673 !Arg->isIntegerConstantExpr(*Result.Context)) {
674 IntegerConstantIsFirstArg =
true;
675 if (
const auto *Arg = OverloadedOperatorExpr->getArg(0)) {
676 if (!Arg->isValueDependent() &&
677 !Arg->isIntegerConstantExpr(*Result.Context))
685 Symbol = OverloadedOperatorExpr->getArg(IntegerConstantIsFirstArg ? 1 : 0);
686 OperandExpr = OverloadedOperatorExpr;
687 Opcode = BinaryOperator::getOverloadedOpcode(
688 OverloadedOperatorExpr->getOperator());
690 if (!retrieveIntegerConstantExpr(Result, Id,
Value, ConstExpr))
693 if (!BinaryOperator::isComparisonOp(Opcode))
698 if (IntegerConstantIsFirstArg)
699 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
706 if (!retrieveSymbolicExpr(Result, Id, Symbol))
709 if (Result.Nodes.getNodeAs<Expr>(SwapId))
710 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
711 if (Result.Nodes.getNodeAs<Expr>(NegateId))
712 Opcode = BinaryOperator::negateComparisonOp(Opcode);
717static bool areSidesBinaryConstExpressions(
const BinaryOperator *&BinOp,
718 const ASTContext *AstCtx) {
719 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
720 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
722 if (!LhsBinOp || !RhsBinOp)
725 auto IsIntegerConstantExpr = [AstCtx](
const Expr *E) {
726 return !E->isValueDependent() && E->isIntegerConstantExpr(*AstCtx);
729 if ((IsIntegerConstantExpr(LhsBinOp->getLHS()) ||
730 IsIntegerConstantExpr(LhsBinOp->getRHS())) &&
731 (IsIntegerConstantExpr(RhsBinOp->getLHS()) ||
732 IsIntegerConstantExpr(RhsBinOp->getRHS())))
737static bool areSidesBinaryConstExpressionsOrDefinesOrIntegerConstant(
738 const BinaryOperator *&BinOp,
const ASTContext *AstCtx) {
739 if (areSidesBinaryConstExpressions(BinOp, AstCtx))
742 const Expr *Lhs = BinOp->getLHS();
743 const Expr *Rhs = BinOp->getRHS();
748 auto IsDefineExpr = [AstCtx](
const Expr *E) {
749 const SourceRange Lsr = E->getSourceRange();
750 if (!Lsr.getBegin().isMacroID() || E->isValueDependent() ||
751 !E->isIntegerConstantExpr(*AstCtx))
756 return IsDefineExpr(Lhs) || IsDefineExpr(Rhs);
762static bool retrieveConstExprFromBothSides(
const BinaryOperator *&BinOp,
763 BinaryOperatorKind &MainOpcode,
764 BinaryOperatorKind &SideOpcode,
765 const Expr *&LhsConst,
766 const Expr *&RhsConst,
767 const ASTContext *AstCtx) {
768 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
769 "Both sides of binary operator must be constant expressions!");
771 MainOpcode = BinOp->getOpcode();
773 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
774 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
776 auto IsIntegerConstantExpr = [AstCtx](
const Expr *E) {
777 return !E->isValueDependent() && E->isIntegerConstantExpr(*AstCtx);
780 LhsConst = IsIntegerConstantExpr(BinOpLhs->getLHS()) ? BinOpLhs->getLHS()
781 : BinOpLhs->getRHS();
782 RhsConst = IsIntegerConstantExpr(BinOpRhs->getLHS()) ? BinOpRhs->getLHS()
783 : BinOpRhs->getRHS();
785 if (!LhsConst || !RhsConst)
788 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
789 "Sides of the binary operator must be equivalent expressions!");
791 SideOpcode = BinOpLhs->getOpcode();
796static bool isSameRawIdentifierToken(
const Token &T1,
const Token &T2,
797 const SourceManager &SM) {
798 if (T1.getKind() != T2.getKind())
800 if (T1.isNot(tok::raw_identifier))
802 if (T1.getLength() != T2.getLength())
804 return StringRef(SM.getCharacterData(T1.getLocation()), T1.getLength()) ==
805 StringRef(SM.getCharacterData(T2.getLocation()), T2.getLength());
808bool isTokAtEndOfExpr(SourceRange ExprSR, Token T,
const SourceManager &SM) {
809 return SM.getExpansionLoc(ExprSR.getEnd()) ==
T.getLocation();
815static bool areExprsFromDifferentMacros(
const Expr *LhsExpr,
817 const ASTContext *AstCtx) {
818 if (!LhsExpr || !RhsExpr)
820 const SourceRange Lsr = LhsExpr->getSourceRange();
821 const SourceRange Rsr = RhsExpr->getSourceRange();
822 if (!Lsr.getBegin().isMacroID() || !Rsr.getBegin().isMacroID())
825 const SourceManager &SM = AstCtx->getSourceManager();
826 const LangOptions &LO = AstCtx->getLangOpts();
828 std::pair<FileID, unsigned> LsrLocInfo =
829 SM.getDecomposedLoc(SM.getExpansionLoc(Lsr.getBegin()));
830 std::pair<FileID, unsigned> RsrLocInfo =
831 SM.getDecomposedLoc(SM.getExpansionLoc(Rsr.getBegin()));
832 llvm::MemoryBufferRef MB = SM.getBufferOrFake(LsrLocInfo.first);
834 const char *LTokenPos = MB.getBufferStart() + LsrLocInfo.second;
835 const char *RTokenPos = MB.getBufferStart() + RsrLocInfo.second;
836 Lexer LRawLex(SM.getLocForStartOfFile(LsrLocInfo.first), LO,
837 MB.getBufferStart(), LTokenPos, MB.getBufferEnd());
838 Lexer RRawLex(SM.getLocForStartOfFile(RsrLocInfo.first), LO,
839 MB.getBufferStart(), RTokenPos, MB.getBufferEnd());
843 LRawLex.LexFromRawLexer(LTok);
844 RRawLex.LexFromRawLexer(RTok);
845 }
while (!LTok.is(tok::eof) && !RTok.is(tok::eof) &&
846 isSameRawIdentifierToken(LTok, RTok, SM) &&
847 !isTokAtEndOfExpr(Lsr, LTok, SM) &&
848 !isTokAtEndOfExpr(Rsr, RTok, SM));
849 return (!isTokAtEndOfExpr(Lsr, LTok, SM) ||
850 !isTokAtEndOfExpr(Rsr, RTok, SM)) ||
851 !isSameRawIdentifierToken(LTok, RTok, SM);
854static bool areExprsMacroAndNonMacro(
const Expr *&LhsExpr,
855 const Expr *&RhsExpr) {
856 if (!LhsExpr || !RhsExpr)
859 const SourceLocation LhsLoc = LhsExpr->getExprLoc();
860 const SourceLocation RhsLoc = RhsExpr->getExprLoc();
862 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
865static bool areStringsSameIgnoreSpaces(
const llvm::StringRef Left,
866 const llvm::StringRef Right) {
871 llvm::StringRef L =
Left.trim();
872 llvm::StringRef R =
Right.trim();
873 while (!L.empty() && !R.empty()) {
876 if (L.empty() && R.empty())
879 if (L.front() != R.front())
884 return L.empty() && R.empty();
887static bool areExprsSameMacroOrLiteral(
const BinaryOperator *BinOp,
888 const ASTContext *Context) {
893 const Expr *Lhs = BinOp->getLHS();
894 const Expr *Rhs = BinOp->getRHS();
895 const SourceManager &SM = Context->getSourceManager();
897 const SourceRange Lsr = Lhs->getSourceRange();
898 const SourceRange Rsr = Rhs->getSourceRange();
899 if (Lsr.getBegin().isMacroID()) {
901 if (Rsr.getBegin().isMacroID()) {
903 const llvm::StringRef L = Lexer::getSourceText(
904 CharSourceRange::getTokenRange(Lsr), SM, Context->getLangOpts());
905 const llvm::StringRef R = Lexer::getSourceText(
906 CharSourceRange::getTokenRange(Rsr), SM, Context->getLangOpts());
907 return areStringsSameIgnoreSpaces(L, R);
912 const auto *Lil = dyn_cast<IntegerLiteral>(Lhs);
913 const auto *Ril = dyn_cast<IntegerLiteral>(Rhs);
915 return Lil->getValue() == Ril->getValue();
917 const auto *Lbl = dyn_cast<CXXBoolLiteralExpr>(Lhs);
918 const auto *Rbl = dyn_cast<CXXBoolLiteralExpr>(Rhs);
920 return Lbl->getValue() == Rbl->getValue();
927 const auto BannedIntegerLiteral =
928 integerLiteral(expandedByMacro(KnownBannedMacroNames));
929 const auto IsInUnevaluatedContext = expr(anyOf(
930 hasAncestor(expr(hasUnevaluatedContext())), hasAncestor(typeLoc())));
935 binaryOperator(anyOf(isComparisonOperator(),
936 hasAnyOperatorName(
"-",
"/",
"%",
"|",
"&",
937 "^",
"&&",
"||",
"=")),
938 operandsAreEquivalent(),
940 unless(isInTemplateInstantiation()),
941 unless(binaryOperatorIsInMacro()),
942 unless(hasAncestor(arraySubscriptExpr())),
943 unless(hasDescendant(BannedIntegerLiteral)),
944 unless(IsInUnevaluatedContext))
951 binaryOperator(hasAnyOperatorName(
"|",
"&",
"||",
"&&",
"^"),
952 nestedOperandsAreEquivalent(),
954 unless(isInTemplateInstantiation()),
955 unless(binaryOperatorIsInMacro()),
957 unless(hasDescendant(BannedIntegerLiteral)),
958 unless(IsInUnevaluatedContext))
959 .bind(
"nested-duplicates"),
965 conditionalOperator(expressionsAreEquivalent(),
967 unless(conditionalOperatorIsInMacro()),
968 unless(isInTemplateInstantiation()),
969 unless(IsInUnevaluatedContext))
977 hasAnyOverloadedOperatorName(
"-",
"/",
"%",
"|",
"&",
"^",
978 "==",
"!=",
"<",
"<=",
">",
979 ">=",
"&&",
"||",
"="),
980 parametersAreEquivalent(),
982 unless(isMacro()), unless(isInTemplateInstantiation()),
983 unless(IsInUnevaluatedContext))
990 hasAnyOverloadedOperatorName(
"|",
"&",
"||",
"&&",
"^"),
991 nestedParametersAreEquivalent(), argumentCountIs(2),
993 unless(isMacro()), unless(isInTemplateInstantiation()),
994 unless(IsInUnevaluatedContext))
995 .bind(
"nested-duplicates"),
1002 hasImplicitDestinationType(isInteger()),
1004 hasOperatorName(
"!"),
1005 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
1006 hasAnyOperatorName(
"|",
"&"),
1008 binaryOperator(hasAnyOperatorName(
"|",
"&")),
1010 hasRHS(integerLiteral())))))
1011 .bind(
"logical-bitwise-confusion")),
1012 unless(IsInUnevaluatedContext))),
1019 hasOperatorName(
"&"),
1020 hasOperands(ignoringParenImpCasts(binaryOperator(
1021 hasOperatorName(
"<<"),
1022 hasRHS(ignoringParenImpCasts(
1023 integerLiteral().bind(
"shift-const"))))),
1024 ignoringParenImpCasts(
1025 integerLiteral().bind(
"and-const"))),
1026 unless(IsInUnevaluatedContext))
1027 .bind(
"left-right-shift-confusion")),
1036 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr(
"lhs");
1037 const auto BinOpCstRight = matchBinOpIntegerConstantExpr(
"rhs");
1038 const auto CstRight = matchIntegerConstantExpr(
"rhs");
1039 const auto SymRight = matchSymbolicExpr(
"rhs");
1043 traverse(TK_AsIs, binaryOperator(isComparisonOperator(),
1044 hasOperands(BinOpCstLeft, CstRight),
1045 unless(IsInUnevaluatedContext))
1046 .bind(
"binop-const-compare-to-const")),
1053 binaryOperator(isComparisonOperator(),
1054 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
1055 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))),
1056 unless(IsInUnevaluatedContext))
1057 .bind(
"binop-const-compare-to-sym")),
1063 binaryOperator(isComparisonOperator(), hasLHS(BinOpCstLeft),
1064 hasRHS(BinOpCstRight),
1066 unless(operandsAreEquivalent()),
1067 unless(IsInUnevaluatedContext))
1068 .bind(
"binop-const-compare-to-binop-const")),
1076 const auto ComparisonLeft = matchRelationalIntegerConstantExpr(
"lhs");
1077 const auto ComparisonRight = matchRelationalIntegerConstantExpr(
"rhs");
1080 binaryOperator(hasAnyOperatorName(
"||",
"&&"),
1081 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
1083 unless(operandsAreEquivalent()),
1084 unless(IsInUnevaluatedContext))
1085 .bind(
"comparisons-of-symbol-and-const")),
1089void RedundantExpressionCheck::checkArithmeticExpr(
1090 const MatchFinder::MatchResult &Result) {
1091 APSInt LhsValue, RhsValue;
1092 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
1093 BinaryOperatorKind LhsOpcode{}, RhsOpcode{};
1095 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
1096 "binop-const-compare-to-sym")) {
1097 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1098 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
1100 !retrieveSymbolicExpr(Result,
"rhs", RhsSymbol) ||
1101 !areEquivalentExpr(LhsSymbol, RhsSymbol))
1105 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
1106 if ((LhsValue != 0 && Opcode == BO_EQ) ||
1107 (LhsValue == 0 && Opcode == BO_NE))
1108 diag(ComparisonOperator->getOperatorLoc(),
1109 "logical expression is always false");
1110 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
1111 (LhsValue != 0 && Opcode == BO_NE))
1112 diag(ComparisonOperator->getOperatorLoc(),
1113 "logical expression is always true");
1115 }
else if (
const auto *ComparisonOperator =
1116 Result.Nodes.getNodeAs<BinaryOperator>(
1117 "binop-const-compare-to-binop-const")) {
1118 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1120 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
1122 !retrieveBinOpIntegerConstantExpr(Result,
"rhs", RhsOpcode, RhsSymbol,
1124 !areEquivalentExpr(LhsSymbol, RhsSymbol))
1127 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
1128 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
1131 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
1132 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
1133 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
1134 diag(ComparisonOperator->getOperatorLoc(),
1135 "logical expression is always true");
1136 }
else if ((Opcode == BO_EQ &&
1137 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
1139 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
1140 diag(ComparisonOperator->getOperatorLoc(),
1141 "logical expression is always false");
1148 return (Opcode == BO_And || Opcode == BO_AndAssign) &&
Value == 0;
1153 return (Opcode == BO_Or || Opcode == BO_OrAssign) &&
~Value == 0;
1157 return ((Opcode == BO_Or || Opcode == BO_OrAssign) &&
Value == 0) ||
1158 ((Opcode == BO_And || Opcode == BO_AndAssign) &&
~Value == 0);
1161void RedundantExpressionCheck::checkBitwiseExpr(
1162 const MatchFinder::MatchResult &Result) {
1163 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
1164 "binop-const-compare-to-const")) {
1165 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1167 APSInt LhsValue, RhsValue;
1168 const Expr *LhsSymbol =
nullptr;
1169 BinaryOperatorKind LhsOpcode{};
1170 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
1172 !retrieveIntegerConstantExpr(Result,
"rhs", RhsValue))
1175 uint64_t LhsConstant = LhsValue.getZExtValue();
1176 uint64_t RhsConstant = RhsValue.getZExtValue();
1177 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
1180 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
1181 if (Opcode == BO_EQ)
1182 diag(Loc,
"logical expression is always false");
1183 else if (Opcode == BO_NE)
1184 diag(Loc,
"logical expression is always true");
1188 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
1189 if (Opcode == BO_EQ)
1190 diag(Loc,
"logical expression is always false");
1191 else if (Opcode == BO_NE)
1192 diag(Loc,
"logical expression is always true");
1194 }
else if (
const auto *IneffectiveOperator =
1195 Result.Nodes.getNodeAs<BinaryOperator>(
1196 "ineffective-bitwise")) {
1198 const Expr *Sym =
nullptr, *ConstExpr =
nullptr;
1200 if (!retrieveSymbolicExpr(Result,
"ineffective-bitwise", Sym) ||
1201 !retrieveIntegerConstantExpr(Result,
"ineffective-bitwise",
Value,
1205 if ((
Value != 0 && ~
Value != 0) || Sym->getExprLoc().isMacroID())
1208 SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
1210 BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
1212 diag(Loc,
"expression always evaluates to 0");
1214 SourceRange ConstExprRange(ConstExpr->getBeginLoc(),
1215 ConstExpr->getEndLoc());
1216 StringRef ConstExprText = Lexer::getSourceText(
1217 CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
1218 Result.Context->getLangOpts());
1220 diag(Loc,
"expression always evaluates to '%0'") << ConstExprText;
1223 SourceRange SymExprRange(Sym->getBeginLoc(), Sym->getEndLoc());
1225 StringRef ExprText = Lexer::getSourceText(
1226 CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
1227 Result.Context->getLangOpts());
1229 diag(Loc,
"expression always evaluates to '%0'") << ExprText;
1234void RedundantExpressionCheck::checkRelationalExpr(
1235 const MatchFinder::MatchResult &Result) {
1236 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
1237 "comparisons-of-symbol-and-const")) {
1240 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1242 const Expr *LhsExpr =
nullptr, *RhsExpr =
nullptr;
1243 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
1244 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
1245 BinaryOperatorKind LhsOpcode{}, RhsOpcode{};
1246 APSInt LhsValue, RhsValue;
1248 if (!retrieveRelationalIntegerConstantExpr(
1249 Result,
"lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
1250 !retrieveRelationalIntegerConstantExpr(
1251 Result,
"rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
1252 !areEquivalentExpr(LhsSymbol, RhsSymbol))
1256 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
1257 std::swap(LhsExpr, RhsExpr);
1258 std::swap(LhsValue, RhsValue);
1259 std::swap(LhsSymbol, RhsSymbol);
1260 std::swap(LhsOpcode, RhsOpcode);
1264 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1265 areExprsMacroAndNonMacro(LhsConst, RhsConst))
1268 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
1269 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1270 diag(ComparisonOperator->getOperatorLoc(),
1271 "equivalent expression on both sides of logical operator");
1275 if (Opcode == BO_LAnd) {
1276 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1277 diag(ComparisonOperator->getOperatorLoc(),
1278 "logical expression is always false");
1279 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1280 diag(LhsExpr->getExprLoc(),
"expression is redundant");
1281 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
1282 diag(RhsExpr->getExprLoc(),
"expression is redundant");
1286 if (Opcode == BO_LOr) {
1287 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1288 diag(ComparisonOperator->getOperatorLoc(),
1289 "logical expression is always true");
1290 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1291 diag(RhsExpr->getExprLoc(),
"expression is redundant");
1292 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
1293 diag(LhsExpr->getExprLoc(),
"expression is redundant");
1300 if (
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binary")) {
1324 const Expr *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
1325 const Expr *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
1326 const BinaryOperator::Opcode Op = BinOp->getOpcode();
1327 const bool OpEqualEQorNE = ((Op == BO_EQ) || (Op == BO_NE));
1329 const auto *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
1330 const auto *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
1331 const auto *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
1332 const auto *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
1334 if (DeclRef1 && DeclRef2 &&
1335 DeclRef1->getType()->hasFloatingRepresentation() &&
1336 DeclRef2->getType()->hasFloatingRepresentation() &&
1337 (DeclRef1->getDecl() == DeclRef2->getDecl()) && OpEqualEQorNE) {
1341 if (FloatLit1 && FloatLit2 &&
1342 FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()) &&
1347 if (areSidesBinaryConstExpressionsOrDefinesOrIntegerConstant(
1348 BinOp, Result.Context)) {
1349 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
1350 BinaryOperatorKind MainOpcode{}, SideOpcode{};
1351 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
1352 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
1353 LhsConst, RhsConst, Result.Context))
1356 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1357 areExprsMacroAndNonMacro(LhsConst, RhsConst))
1360 if (!areExprsSameMacroOrLiteral(BinOp, Result.Context))
1364 diag(BinOp->getOperatorLoc(),
"both sides of operator are equivalent");
1367 if (
const auto *CondOp =
1368 Result.Nodes.getNodeAs<ConditionalOperator>(
"cond")) {
1369 const Expr *TrueExpr = CondOp->getTrueExpr();
1370 const Expr *FalseExpr = CondOp->getFalseExpr();
1372 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
1373 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
1375 diag(CondOp->getColonLoc(),
1376 "'true' and 'false' expressions are equivalent");
1379 if (
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"call")) {
1380 if (canOverloadedOperatorArgsBeModified(Call,
true))
1383 diag(Call->getOperatorLoc(),
1384 "both sides of overloaded operator are equivalent");
1387 if (
const auto *Op = Result.Nodes.getNodeAs<Expr>(
"nested-duplicates")) {
1388 const auto *Call = dyn_cast<CXXOperatorCallExpr>(Op);
1389 if (Call && canOverloadedOperatorArgsBeModified(Call,
true))
1393 Call ?
"overloaded operator has equivalent nested operands"
1394 :
"operator has equivalent nested operands";
1396 const auto Diag = diag(Op->getExprLoc(),
Message);
1397 for (
const auto &KeyValue : Result.Nodes.getMap()) {
1398 if (StringRef(KeyValue.first).starts_with(
"duplicate"))
1399 Diag << KeyValue.second.getSourceRange();
1403 if (
const auto *NegateOperator =
1404 Result.Nodes.getNodeAs<UnaryOperator>(
"logical-bitwise-confusion")) {
1405 SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1409 "ineffective logical negation operator used; did you mean '~'?");
1410 SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1412 if (!LogicalNotLocation.isMacroID())
1413 Diag << FixItHint::CreateReplacement(
1414 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation),
"~");
1417 if (
const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1418 "left-right-shift-confusion")) {
1419 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>(
"shift-const");
1420 assert(ShiftingConst &&
"Expr* 'ShiftingConst' is nullptr!");
1421 std::optional<llvm::APSInt> ShiftingValue =
1422 ShiftingConst->getIntegerConstantExpr(*Result.Context);
1427 const auto *AndConst = Result.Nodes.getNodeAs<Expr>(
"and-const");
1428 assert(AndConst &&
"Expr* 'AndCont' is nullptr!");
1429 std::optional<llvm::APSInt> AndValue =
1430 AndConst->getIntegerConstantExpr(*Result.Context);
1437 if (AndValue->getActiveBits() > *ShiftingValue)
1440 auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
1441 "ineffective bitwise and operation");
1449 checkArithmeticExpr(Result);
1457 checkBitwiseExpr(Result);
1465 checkRelationalExpr(Result);
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)
static constexpr StringRef Message
static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value)
static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode, APSInt Value)
static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value)