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) {
47 return Value < 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();
134 case Stmt::UnaryExprOrTypeTraitExprClass:
135 const auto *LeftUnaryExpr =
136 cast<UnaryExprOrTypeTraitExpr>(Left);
137 const auto *RightUnaryExpr =
138 cast<UnaryExprOrTypeTraitExpr>(Right);
139 if (LeftUnaryExpr->isArgumentType() && RightUnaryExpr->isArgumentType())
140 return LeftUnaryExpr->getArgumentType() ==
141 RightUnaryExpr->getArgumentType();
142 else if (!LeftUnaryExpr->isArgumentType() &&
143 !RightUnaryExpr->isArgumentType())
144 return areEquivalentExpr(LeftUnaryExpr->getArgumentExpr(),
145 RightUnaryExpr->getArgumentExpr());
153 static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
154 const APSInt &ValueLHS,
155 BinaryOperatorKind OpcodeRHS,
156 const APSInt &ValueRHS) {
157 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
158 "Values must be ordered");
160 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
161 return OpcodeLHS == OpcodeRHS;
164 APSInt ValueLHS_plus1;
165 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
166 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
167 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
168 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
173 static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
174 const APSInt &ValueLHS,
175 BinaryOperatorKind OpcodeRHS,
176 const APSInt &ValueRHS) {
177 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
178 "Values must be ordered");
181 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
184 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
186 return OpcodeRHS == BO_EQ;
188 return OpcodeRHS == BO_GT;
190 return OpcodeRHS == BO_LT;
192 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
194 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
201 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
202 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
206 APSInt ValueLHS_plus1;
207 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
208 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
209 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
217 static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
218 const APSInt &ValueLHS,
219 BinaryOperatorKind OpcodeRHS,
220 const APSInt &ValueRHS) {
221 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
222 "Values must be ordered");
225 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
228 return OpcodeRHS == BO_NE;
230 return OpcodeRHS == BO_EQ;
232 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
234 return OpcodeRHS == BO_GE;
236 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
238 return OpcodeRHS == BO_LE;
245 APSInt ValueLHS_plus1;
246 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
247 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
248 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
252 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
253 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
258 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
264 static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
265 const APSInt &ValueLHS,
266 BinaryOperatorKind OpcodeRHS,
267 const APSInt &ValueRHS) {
268 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
271 return OpcodeRHS == BO_EQ && Comparison == 0;
273 return (OpcodeRHS == BO_NE && Comparison == 0) ||
274 (OpcodeRHS == BO_EQ && Comparison != 0) ||
275 (OpcodeRHS == BO_LT && Comparison >= 0) ||
276 (OpcodeRHS == BO_LE && Comparison > 0) ||
277 (OpcodeRHS == BO_GT && Comparison <= 0) ||
278 (OpcodeRHS == BO_GE && Comparison < 0);
281 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
282 (OpcodeRHS == BO_LE && Comparison > 0) ||
283 (OpcodeRHS == BO_EQ && Comparison > 0));
285 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
286 (OpcodeRHS == BO_GE && Comparison < 0) ||
287 (OpcodeRHS == BO_EQ && Comparison < 0));
289 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
292 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
299 static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
301 if (Opcode == BO_Sub) {
308 if (Node.isInstantiationDependent())
310 return Node.isIntegerConstantExpr(Finder->getASTContext());
313 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
314 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
317 AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
318 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
322 return Node.getNumArgs() == 2 &&
323 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
326 AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
327 return Node.getOperatorLoc().isMacroID();
330 AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
331 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
334 AST_MATCHER(Expr, isMacro) {
return Node.getExprLoc().isMacroID(); }
336 AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) {
337 const SourceManager &SM = Finder->getASTContext().getSourceManager();
338 const LangOptions &LO = Finder->getASTContext().getLangOpts();
339 SourceLocation
Loc = Node.getExprLoc();
340 while (Loc.isMacroID()) {
341 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
342 if (llvm::is_contained(Names, MacroName))
344 Loc = SM.getImmediateMacroCallerLoc(Loc);
350 static ast_matchers::internal::Matcher<Expr>
351 matchIntegerConstantExpr(StringRef Id) {
352 std::string CstId = (Id +
"-const").str();
353 return expr(isIntegerConstantExpr()).bind(CstId);
359 static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
360 StringRef Id, APSInt &Value,
361 const Expr *&ConstExpr) {
362 std::string CstId = (Id +
"-const").str();
363 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
364 return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
368 static bool retrieveIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
369 StringRef Id, APSInt &Value) {
370 const Expr *ConstExpr =
nullptr;
371 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
376 static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
377 std::string SymId = (Id +
"-sym").str();
378 return ignoringParenImpCasts(
379 expr(unless(isIntegerConstantExpr())).bind(SymId));
384 static bool retrieveSymbolicExpr(
const MatchFinder::MatchResult &Result,
385 StringRef Id,
const Expr *&SymExpr) {
386 std::string SymId = (Id +
"-sym").str();
387 if (
const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
396 static ast_matchers::internal::Matcher<Expr>
397 matchBinOpIntegerConstantExpr(StringRef Id) {
398 const auto BinOpCstExpr =
400 anyOf(binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|"),
401 hasOperatorName(
"&")),
402 hasEitherOperand(matchSymbolicExpr(Id)),
403 hasEitherOperand(matchIntegerConstantExpr(Id))),
404 binaryOperator(hasOperatorName(
"-"),
405 hasLHS(matchSymbolicExpr(Id)),
406 hasRHS(matchIntegerConstantExpr(Id)))))
408 return ignoringParenImpCasts(BinOpCstExpr);
414 retrieveBinOpIntegerConstantExpr(
const MatchFinder::MatchResult &Result,
415 StringRef Id, BinaryOperatorKind &Opcode,
416 const Expr *&Symbol, APSInt &Value) {
417 if (
const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
418 Opcode = BinExpr->getOpcode();
419 return retrieveSymbolicExpr(Result, Id, Symbol) &&
420 retrieveIntegerConstantExpr(Result, Id, Value);
426 static ast_matchers::internal::Matcher<Expr>
427 matchRelationalIntegerConstantExpr(StringRef Id) {
428 std::string CastId = (Id +
"-cast").str();
429 std::string SwapId = (Id +
"-swap").str();
430 std::string NegateId = (Id +
"-negate").str();
431 std::string OverloadId = (Id +
"-overload").str();
433 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
434 isComparisonOperator(), expr().bind(Id),
435 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
436 hasRHS(matchIntegerConstantExpr(Id))),
437 allOf(hasLHS(matchIntegerConstantExpr(Id)),
438 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
442 const auto CastExpr =
443 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
444 hasSourceExpression(matchSymbolicExpr(Id)))
447 const auto NegateRelationalExpr =
448 unaryOperator(hasOperatorName(
"!"),
449 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
453 const auto NegateNegateRelationalExpr =
454 unaryOperator(hasOperatorName(
"!"),
455 hasUnaryOperand(unaryOperator(
456 hasOperatorName(
"!"),
457 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
459 const auto OverloadedOperatorExpr =
461 anyOf(hasOverloadedOperatorName(
"=="),
462 hasOverloadedOperatorName(
"!="), hasOverloadedOperatorName(
"<"),
463 hasOverloadedOperatorName(
"<="), hasOverloadedOperatorName(
">"),
464 hasOverloadedOperatorName(
">=")),
466 unless(isMacro()), unless(isInTemplateInstantiation()))
469 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
470 NegateNegateRelationalExpr, OverloadedOperatorExpr);
475 static bool isNonConstReferenceType(QualType ParamType) {
476 return ParamType->isReferenceType() &&
477 !ParamType.getNonReferenceType().isConstQualified();
487 canOverloadedOperatorArgsBeModified(
const FunctionDecl *OperatorDecl,
488 bool checkSecondParam) {
489 unsigned ParamCount = OperatorDecl->getNumParams();
494 if (ParamCount == 1 &&
495 !OperatorDecl->getType()->castAs<FunctionType>()->isConst())
498 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
501 return checkSecondParam && ParamCount == 2 &&
502 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
507 static bool retrieveRelationalIntegerConstantExpr(
508 const MatchFinder::MatchResult &Result, StringRef Id,
509 const Expr *&OperandExpr, BinaryOperatorKind &Opcode,
const Expr *&Symbol,
510 APSInt &Value,
const Expr *&ConstExpr) {
511 std::string CastId = (Id +
"-cast").str();
512 std::string SwapId = (Id +
"-swap").str();
513 std::string NegateId = (Id +
"-negate").str();
514 std::string OverloadId = (Id +
"-overload").str();
516 if (
const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
518 Opcode = Bin->getOpcode();
521 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
523 }
else if (
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
527 Value = APSInt(32,
false);
528 }
else if (
const auto *OverloadedOperatorExpr =
529 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
530 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
531 if (!OverloadedFunctionDecl)
534 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
false))
537 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
false))
540 if (
const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
541 if (!Arg->isValueDependent() &&
542 !Arg->isIntegerConstantExpr(Value, *Result.Context))
545 Symbol = OverloadedOperatorExpr->getArg(0);
546 OperandExpr = OverloadedOperatorExpr;
547 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
549 return BinaryOperator::isComparisonOp(Opcode);
554 if (!retrieveSymbolicExpr(Result, Id, Symbol))
557 if (Result.Nodes.getNodeAs<Expr>(SwapId))
558 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
559 if (Result.Nodes.getNodeAs<Expr>(NegateId))
560 Opcode = BinaryOperator::negateComparisonOp(Opcode);
565 static bool areSidesBinaryConstExpressions(
const BinaryOperator *&BinOp,
const ASTContext *AstCtx) {
566 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
567 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
569 if (!LhsBinOp || !RhsBinOp)
572 auto IsIntegerConstantExpr = [AstCtx](
const Expr *
E) {
573 return !
E->isValueDependent() &&
E->isIntegerConstantExpr(*AstCtx);
576 if ((IsIntegerConstantExpr(LhsBinOp->getLHS()) ||
577 IsIntegerConstantExpr(LhsBinOp->getRHS())) &&
578 (IsIntegerConstantExpr(RhsBinOp->getLHS()) ||
579 IsIntegerConstantExpr(RhsBinOp->getRHS())))
587 static bool retrieveConstExprFromBothSides(
const BinaryOperator *&BinOp,
588 BinaryOperatorKind &MainOpcode,
589 BinaryOperatorKind &SideOpcode,
590 const Expr *&LhsConst,
591 const Expr *&RhsConst,
592 const ASTContext *AstCtx) {
593 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
594 "Both sides of binary operator must be constant expressions!");
596 MainOpcode = BinOp->getOpcode();
598 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
599 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
601 auto IsIntegerConstantExpr = [AstCtx](
const Expr *
E) {
602 return !
E->isValueDependent() &&
E->isIntegerConstantExpr(*AstCtx);
605 LhsConst = IsIntegerConstantExpr(BinOpLhs->getLHS()) ? BinOpLhs->getLHS()
606 : BinOpLhs->getRHS();
607 RhsConst = IsIntegerConstantExpr(BinOpRhs->getLHS()) ? BinOpRhs->getLHS()
608 : BinOpRhs->getRHS();
610 if (!LhsConst || !RhsConst)
613 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
614 "Sides of the binary operator must be equivalent expressions!");
616 SideOpcode = BinOpLhs->getOpcode();
621 static bool isSameRawIdentifierToken(
const Token &T1,
const Token &T2,
622 const SourceManager &SM) {
623 if (T1.getKind() != T2.getKind())
625 if (T1.isNot(tok::raw_identifier))
627 if (T1.getLength() != T2.getLength())
629 return StringRef(SM.getCharacterData(T1.getLocation()), T1.getLength()) ==
630 StringRef(SM.getCharacterData(T2.getLocation()), T2.getLength());
633 bool isTokAtEndOfExpr(SourceRange ExprSR, Token T,
const SourceManager &SM) {
634 return SM.getExpansionLoc(ExprSR.getEnd()) == T.getLocation();
640 static bool areExprsFromDifferentMacros(
const Expr *LhsExpr,
642 const ASTContext *AstCtx) {
643 if (!LhsExpr || !RhsExpr)
645 SourceRange Lsr = LhsExpr->getSourceRange();
646 SourceRange Rsr = RhsExpr->getSourceRange();
647 if (!Lsr.getBegin().isMacroID() || !Rsr.getBegin().isMacroID())
650 const SourceManager &SM = AstCtx->getSourceManager();
651 const LangOptions &LO = AstCtx->getLangOpts();
653 std::pair<FileID, unsigned> LsrLocInfo =
654 SM.getDecomposedLoc(SM.getExpansionLoc(Lsr.getBegin()));
655 std::pair<FileID, unsigned> RsrLocInfo =
656 SM.getDecomposedLoc(SM.getExpansionLoc(Rsr.getBegin()));
657 const llvm::MemoryBuffer *MB = SM.getBuffer(LsrLocInfo.first);
659 const char *LTokenPos = MB->getBufferStart() + LsrLocInfo.second;
660 const char *RTokenPos = MB->getBufferStart() + RsrLocInfo.second;
661 Lexer LRawLex(SM.getLocForStartOfFile(LsrLocInfo.first), LO,
662 MB->getBufferStart(), LTokenPos, MB->getBufferEnd());
663 Lexer RRawLex(SM.getLocForStartOfFile(RsrLocInfo.first), LO,
664 MB->getBufferStart(), RTokenPos, MB->getBufferEnd());
668 LRawLex.LexFromRawLexer(LTok);
669 RRawLex.LexFromRawLexer(RTok);
670 }
while (!LTok.is(tok::eof) && !RTok.is(tok::eof) &&
671 isSameRawIdentifierToken(LTok, RTok, SM) &&
672 !isTokAtEndOfExpr(Lsr, LTok, SM) &&
673 !isTokAtEndOfExpr(Rsr, RTok, SM));
674 return (!isTokAtEndOfExpr(Lsr, LTok, SM) ||
675 !isTokAtEndOfExpr(Rsr, RTok, SM)) ||
676 !isSameRawIdentifierToken(LTok, RTok, SM);
679 static bool areExprsMacroAndNonMacro(
const Expr *&LhsExpr,
680 const Expr *&RhsExpr) {
681 if (!LhsExpr || !RhsExpr)
684 SourceLocation LhsLoc = LhsExpr->getExprLoc();
685 SourceLocation RhsLoc = RhsExpr->getExprLoc();
687 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
691 void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
692 const auto AnyLiteralExpr = ignoringParenImpCasts(
693 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
695 const auto BannedIntegerLiteral =
696 integerLiteral(expandedByMacro(KnownBannedMacroNames));
700 binaryOperator(anyOf(hasOperatorName(
"-"), hasOperatorName(
"/"),
701 hasOperatorName(
"%"), hasOperatorName(
"|"),
702 hasOperatorName(
"&"), hasOperatorName(
"^"),
703 matchers::isComparisonOperator(),
704 hasOperatorName(
"&&"), hasOperatorName(
"||"),
705 hasOperatorName(
"=")),
706 operandsAreEquivalent(),
708 unless(isInTemplateInstantiation()),
709 unless(binaryOperatorIsInMacro()),
710 unless(hasType(realFloatingPointType())),
711 unless(hasEitherOperand(hasType(realFloatingPointType()))),
712 unless(hasLHS(AnyLiteralExpr)),
713 unless(hasDescendant(BannedIntegerLiteral)))
718 Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
720 unless(conditionalOperatorIsInMacro()),
721 unless(isInTemplateInstantiation()))
729 hasOverloadedOperatorName(
"-"), hasOverloadedOperatorName(
"/"),
730 hasOverloadedOperatorName(
"%"), hasOverloadedOperatorName(
"|"),
731 hasOverloadedOperatorName(
"&"), hasOverloadedOperatorName(
"^"),
732 hasOverloadedOperatorName(
"=="), hasOverloadedOperatorName(
"!="),
733 hasOverloadedOperatorName(
"<"), hasOverloadedOperatorName(
"<="),
734 hasOverloadedOperatorName(
">"), hasOverloadedOperatorName(
">="),
735 hasOverloadedOperatorName(
"&&"), hasOverloadedOperatorName(
"||"),
736 hasOverloadedOperatorName(
"=")),
737 parametersAreEquivalent(),
739 unless(isMacro()), unless(isInTemplateInstantiation()))
746 hasImplicitDestinationType(isInteger()),
748 hasOperatorName(
"!"),
749 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
750 anyOf(hasOperatorName(
"|"), hasOperatorName(
"&")),
751 hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName(
"|"),
752 hasOperatorName(
"&"))),
754 hasRHS(integerLiteral())))))
755 .bind(
"logical-bitwise-confusion"))),
760 binaryOperator(hasOperatorName(
"&"),
761 hasEitherOperand(ignoringParenImpCasts(binaryOperator(
762 hasOperatorName(
"<<"),
763 hasRHS(ignoringParenImpCasts(
764 integerLiteral().bind(
"shift-const")))))),
765 hasEitherOperand(ignoringParenImpCasts(
766 integerLiteral().bind(
"and-const"))))
767 .bind(
"left-right-shift-confusion"),
776 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr(
"lhs");
777 const auto BinOpCstRight = matchBinOpIntegerConstantExpr(
"rhs");
778 const auto CstRight = matchIntegerConstantExpr(
"rhs");
779 const auto SymRight = matchSymbolicExpr(
"rhs");
782 Finder->addMatcher(binaryOperator(isComparisonOperator(),
783 hasEitherOperand(BinOpCstLeft),
784 hasEitherOperand(CstRight))
785 .bind(
"binop-const-compare-to-const"),
790 binaryOperator(isComparisonOperator(),
791 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
792 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
793 .bind(
"binop-const-compare-to-sym"),
797 Finder->addMatcher(binaryOperator(isComparisonOperator(),
798 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
800 unless(operandsAreEquivalent()))
801 .bind(
"binop-const-compare-to-binop-const"),
809 const auto ComparisonLeft = matchRelationalIntegerConstantExpr(
"lhs");
810 const auto ComparisonRight = matchRelationalIntegerConstantExpr(
"rhs");
812 binaryOperator(anyOf(hasOperatorName(
"||"), hasOperatorName(
"&&")),
813 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
815 unless(operandsAreEquivalent()))
816 .bind(
"comparisons-of-symbol-and-const"),
820 void RedundantExpressionCheck::checkArithmeticExpr(
821 const MatchFinder::MatchResult &Result) {
822 APSInt LhsValue, RhsValue;
823 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
824 BinaryOperatorKind LhsOpcode, RhsOpcode;
826 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
827 "binop-const-compare-to-sym")) {
828 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
829 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
831 !retrieveSymbolicExpr(Result,
"rhs", RhsSymbol) ||
832 !areEquivalentExpr(LhsSymbol, RhsSymbol))
836 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
837 if ((LhsValue != 0 && Opcode == BO_EQ) ||
838 (LhsValue == 0 && Opcode == BO_NE))
839 diag(ComparisonOperator->getOperatorLoc(),
840 "logical expression is always false");
841 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
842 (LhsValue != 0 && Opcode == BO_NE))
843 diag(ComparisonOperator->getOperatorLoc(),
844 "logical expression is always true");
846 }
else if (
const auto *ComparisonOperator =
847 Result.Nodes.getNodeAs<BinaryOperator>(
848 "binop-const-compare-to-binop-const")) {
849 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
851 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
853 !retrieveBinOpIntegerConstantExpr(Result,
"rhs", RhsOpcode, RhsSymbol,
855 !areEquivalentExpr(LhsSymbol, RhsSymbol))
858 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
859 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
862 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
863 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
864 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
865 diag(ComparisonOperator->getOperatorLoc(),
866 "logical expression is always true");
867 }
else if ((Opcode == BO_EQ &&
868 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
870 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
871 diag(ComparisonOperator->getOperatorLoc(),
872 "logical expression is always false");
879 return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
884 return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
888 return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
889 ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
893 void RedundantExpressionCheck::checkBitwiseExpr(
894 const MatchFinder::MatchResult &Result) {
895 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
896 "binop-const-compare-to-const")) {
897 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
899 APSInt LhsValue, RhsValue;
900 const Expr *LhsSymbol =
nullptr;
901 BinaryOperatorKind LhsOpcode;
902 if (!retrieveBinOpIntegerConstantExpr(Result,
"lhs", LhsOpcode, LhsSymbol,
904 !retrieveIntegerConstantExpr(Result,
"rhs", RhsValue))
907 uint64_t LhsConstant = LhsValue.getZExtValue();
908 uint64_t RhsConstant = RhsValue.getZExtValue();
909 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
912 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
914 diag(Loc,
"logical expression is always false");
915 else if (Opcode == BO_NE)
916 diag(Loc,
"logical expression is always true");
920 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
922 diag(Loc,
"logical expression is always false");
923 else if (Opcode == BO_NE)
924 diag(Loc,
"logical expression is always true");
926 }
else if (
const auto *IneffectiveOperator =
927 Result.Nodes.getNodeAs<BinaryOperator>(
928 "ineffective-bitwise")) {
930 const Expr *Sym =
nullptr, *ConstExpr =
nullptr;
932 if (!retrieveSymbolicExpr(Result,
"ineffective-bitwise", Sym) ||
933 !retrieveIntegerConstantExpr(Result,
"ineffective-bitwise", Value,
937 if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
940 SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
942 BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
944 diag(Loc,
"expression always evaluates to 0");
946 SourceRange ConstExprRange(ConstExpr->getBeginLoc(),
947 ConstExpr->getEndLoc());
948 StringRef ConstExprText = Lexer::getSourceText(
950 Result.Context->getLangOpts());
952 diag(Loc,
"expression always evaluates to '%0'") << ConstExprText;
955 SourceRange SymExprRange(Sym->getBeginLoc(), Sym->getEndLoc());
957 StringRef ExprText = Lexer::getSourceText(
959 Result.Context->getLangOpts());
961 diag(Loc,
"expression always evaluates to '%0'") << ExprText;
966 void RedundantExpressionCheck::checkRelationalExpr(
967 const MatchFinder::MatchResult &Result) {
968 if (
const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
969 "comparisons-of-symbol-and-const")) {
972 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
974 const Expr *LhsExpr =
nullptr, *RhsExpr =
nullptr;
975 const Expr *LhsSymbol =
nullptr, *RhsSymbol =
nullptr;
976 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
977 BinaryOperatorKind LhsOpcode, RhsOpcode;
978 APSInt LhsValue, RhsValue;
980 if (!retrieveRelationalIntegerConstantExpr(
981 Result,
"lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
982 !retrieveRelationalIntegerConstantExpr(
983 Result,
"rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
984 !areEquivalentExpr(LhsSymbol, RhsSymbol))
988 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
989 std::swap(LhsExpr, RhsExpr);
990 std::swap(LhsValue, RhsValue);
991 std::swap(LhsSymbol, RhsSymbol);
992 std::swap(LhsOpcode, RhsOpcode);
996 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
997 areExprsMacroAndNonMacro(LhsConst, RhsConst))
1000 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
1001 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1002 diag(ComparisonOperator->getOperatorLoc(),
1003 "equivalent expression on both sides of logical operator");
1007 if (Opcode == BO_LAnd) {
1008 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1009 diag(ComparisonOperator->getOperatorLoc(),
1010 "logical expression is always false");
1011 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1012 diag(LhsExpr->getExprLoc(),
"expression is redundant");
1013 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
1014 diag(RhsExpr->getExprLoc(),
"expression is redundant");
1018 if (Opcode == BO_LOr) {
1019 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1020 diag(ComparisonOperator->getOperatorLoc(),
1021 "logical expression is always true");
1022 }
else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1023 diag(RhsExpr->getExprLoc(),
"expression is redundant");
1024 }
else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
1025 diag(LhsExpr->getExprLoc(),
"expression is redundant");
1031 void RedundantExpressionCheck::check(
const MatchFinder::MatchResult &Result) {
1032 if (
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(
"binary")) {
1035 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
1036 const Expr *LhsConst =
nullptr, *RhsConst =
nullptr;
1037 BinaryOperatorKind MainOpcode, SideOpcode;
1039 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
1040 LhsConst, RhsConst, Result.Context))
1043 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1044 areExprsMacroAndNonMacro(LhsConst, RhsConst))
1048 diag(BinOp->getOperatorLoc(),
"both sides of operator are equivalent");
1051 if (
const auto *CondOp =
1052 Result.Nodes.getNodeAs<ConditionalOperator>(
"cond")) {
1053 const Expr *TrueExpr = CondOp->getTrueExpr();
1054 const Expr *FalseExpr = CondOp->getFalseExpr();
1056 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
1057 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
1059 diag(CondOp->getColonLoc(),
1060 "'true' and 'false' expressions are equivalent");
1063 if (
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"call")) {
1064 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
1065 if (!OverloadedFunctionDecl)
1068 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl,
true))
1071 diag(Call->getOperatorLoc(),
1072 "both sides of overloaded operator are equivalent");
1075 if (
const auto *NegateOperator =
1076 Result.Nodes.getNodeAs<UnaryOperator>(
"logical-bitwise-confusion")) {
1077 SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1081 "ineffective logical negation operator used; did you mean '~'?");
1082 SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1084 if (!LogicalNotLocation.isMacroID())
1085 Diag << FixItHint::CreateReplacement(
1086 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation),
"~");
1089 if (
const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1090 "left-right-shift-confusion")) {
1091 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>(
"shift-const");
1092 assert(ShiftingConst &&
"Expr* 'ShiftingConst' is nullptr!");
1093 APSInt ShiftingValue;
1095 if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
1098 const auto *AndConst = Result.Nodes.getNodeAs<Expr>(
"and-const");
1099 assert(AndConst &&
"Expr* 'AndCont' is nullptr!");
1101 if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
1107 if (AndValue.getActiveBits() > ShiftingValue)
1110 auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
1111 "ineffective bitwise and operation");
1119 checkArithmeticExpr(Result);
1127 checkBitwiseExpr(Result);
1135 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++ -*-===//
AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl, ast_matchers::internal::Matcher< CXXMethodDecl >, InnerMatcher)