18 const auto Literal0 = integerLiteral(equals(0));
19 const auto Literal1 = integerLiteral(equals(1));
21 const auto ClassWithContains = cxxRecordDecl(
22 hasMethod(cxxMethodDecl(isConst(), parameterCountIs(1), isPublic(),
23 unless(isDeleted()), returns(booleanType()),
24 hasAnyName(
"contains",
"Contains"))
25 .bind(
"contains_fun")));
27 const auto CountCall =
28 cxxMemberCallExpr(argumentCountIs(1),
29 callee(cxxMethodDecl(hasAnyName(
"count",
"Count"),
30 ofClass(ClassWithContains))))
37 anyOf(argumentCountIs(1),
38 allOf(argumentCountIs(2), hasArgument(1, Literal0))),
39 callee(cxxMethodDecl(hasAnyName(
"find",
"Find"),
40 ofClass(ClassWithContains))))
43 const auto EndCall = cxxMemberCallExpr(
44 argumentCountIs(0), callee(cxxMethodDecl(hasAnyName(
"end",
"End"),
45 ofClass(ClassWithContains))));
47 const auto StringNpos = anyOf(declRefExpr(to(varDecl(hasName(
"npos")))),
48 memberExpr(member(hasName(
"npos"))));
50 auto AddSimpleMatcher = [&](
const auto &Matcher) {
51 Finder->addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, Matcher),
this);
55 Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(booleanType()),
56 hasSourceExpression(CountCall))
57 .bind(
"positiveComparison"),
60 binaryOperation(hasOperatorName(
"!="), hasOperands(CountCall, Literal0))
61 .bind(
"positiveComparison"));
63 binaryOperation(hasLHS(CountCall), hasOperatorName(
">"), hasRHS(Literal0))
64 .bind(
"positiveComparison"));
66 binaryOperation(hasLHS(Literal0), hasOperatorName(
"<"), hasRHS(CountCall))
67 .bind(
"positiveComparison"));
68 AddSimpleMatcher(binaryOperation(hasLHS(CountCall), hasOperatorName(
">="),
70 .bind(
"positiveComparison"));
71 AddSimpleMatcher(binaryOperation(hasLHS(Literal1), hasOperatorName(
"<="),
73 .bind(
"positiveComparison"));
77 binaryOperation(hasOperatorName(
"=="), hasOperands(CountCall, Literal0))
78 .bind(
"negativeComparison"));
79 AddSimpleMatcher(binaryOperation(hasLHS(CountCall), hasOperatorName(
"<="),
81 .bind(
"negativeComparison"));
82 AddSimpleMatcher(binaryOperation(hasLHS(Literal0), hasOperatorName(
">="),
84 .bind(
"negativeComparison"));
86 binaryOperation(hasLHS(CountCall), hasOperatorName(
"<"), hasRHS(Literal1))
87 .bind(
"negativeComparison"));
89 binaryOperation(hasLHS(Literal1), hasOperatorName(
">"), hasRHS(CountCall))
90 .bind(
"negativeComparison"));
94 binaryOperation(hasOperatorName(
"!="),
95 hasOperands(FindCall, anyOf(EndCall, StringNpos)))
96 .bind(
"positiveComparison"));
98 binaryOperation(hasOperatorName(
"=="),
99 hasOperands(FindCall, anyOf(EndCall, StringNpos)))
100 .bind(
"negativeComparison"));
105 const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"call");
106 const auto *PositiveComparison =
107 Result.Nodes.getNodeAs<Expr>(
"positiveComparison");
108 const auto *NegativeComparison =
109 Result.Nodes.getNodeAs<Expr>(
"negativeComparison");
110 assert((!PositiveComparison || !NegativeComparison) &&
111 "only one of PositiveComparison or NegativeComparison should be set");
112 const bool Negated = NegativeComparison !=
nullptr;
113 const auto *Comparison = Negated ? NegativeComparison : PositiveComparison;
114 const StringRef ContainsFunName =
115 Result.Nodes.getNodeAs<CXXMethodDecl>(
"contains_fun")->
getName();
116 const Expr *SearchExpr = Call->getArg(0)->IgnoreParenImpCasts();
119 auto Diag = diag(Call->getExprLoc(),
"use '%0' to check for membership")
123 const SourceLocation FuncCallLoc = Comparison->getEndLoc();
124 if (!FuncCallLoc.isValid() || FuncCallLoc.isMacroID())
127 const StringRef SearchExprText = Lexer::getSourceText(
128 CharSourceRange::getTokenRange(SearchExpr->getSourceRange()),
129 *Result.SourceManager, Result.Context->getLangOpts());
132 Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
133 Comparison->getBeginLoc(), Call->getBeginLoc()));
136 Diag << FixItHint::CreateReplacement(Call->getExprLoc(), ContainsFunName);
139 Diag << FixItHint::CreateReplacement(
140 CharSourceRange::getTokenRange(Call->getArg(0)->getBeginLoc(),
141 Comparison->getEndLoc()),
142 (SearchExprText +
")").str());
146 Diag << FixItHint::CreateInsertion(Call->getBeginLoc(),
"!");