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 = [&](
auto Matcher) {
52 traverse(TK_IgnoreUnlessSpelledInSource, std::move(Matcher)),
this);
56 Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(booleanType()),
57 hasSourceExpression(CountCall))
58 .bind(
"positiveComparison"),
61 binaryOperation(hasOperatorName(
"!="), hasOperands(CountCall, Literal0))
62 .bind(
"positiveComparison"));
64 binaryOperation(hasLHS(CountCall), hasOperatorName(
">"), hasRHS(Literal0))
65 .bind(
"positiveComparison"));
67 binaryOperation(hasLHS(Literal0), hasOperatorName(
"<"), hasRHS(CountCall))
68 .bind(
"positiveComparison"));
69 AddSimpleMatcher(binaryOperation(hasLHS(CountCall), hasOperatorName(
">="),
71 .bind(
"positiveComparison"));
72 AddSimpleMatcher(binaryOperation(hasLHS(Literal1), hasOperatorName(
"<="),
74 .bind(
"positiveComparison"));
78 binaryOperation(hasOperatorName(
"=="), hasOperands(CountCall, Literal0))
79 .bind(
"negativeComparison"));
80 AddSimpleMatcher(binaryOperation(hasLHS(CountCall), hasOperatorName(
"<="),
82 .bind(
"negativeComparison"));
83 AddSimpleMatcher(binaryOperation(hasLHS(Literal0), hasOperatorName(
">="),
85 .bind(
"negativeComparison"));
87 binaryOperation(hasLHS(CountCall), hasOperatorName(
"<"), hasRHS(Literal1))
88 .bind(
"negativeComparison"));
90 binaryOperation(hasLHS(Literal1), hasOperatorName(
">"), hasRHS(CountCall))
91 .bind(
"negativeComparison"));
95 binaryOperation(hasOperatorName(
"!="),
96 hasOperands(FindCall, anyOf(EndCall, StringNpos)))
97 .bind(
"positiveComparison"));
99 binaryOperation(hasOperatorName(
"=="),
100 hasOperands(FindCall, anyOf(EndCall, StringNpos)))
101 .bind(
"negativeComparison"));
106 const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"call");
107 const auto *PositiveComparison =
108 Result.Nodes.getNodeAs<Expr>(
"positiveComparison");
109 const auto *NegativeComparison =
110 Result.Nodes.getNodeAs<Expr>(
"negativeComparison");
111 assert((!PositiveComparison || !NegativeComparison) &&
112 "only one of PositiveComparison or NegativeComparison should be set");
113 bool Negated = NegativeComparison !=
nullptr;
114 const auto *Comparison = Negated ? NegativeComparison : PositiveComparison;
115 const StringRef ContainsFunName =
116 Result.Nodes.getNodeAs<CXXMethodDecl>(
"contains_fun")->
getName();
117 const Expr *SearchExpr = Call->getArg(0)->IgnoreParenImpCasts();
120 auto Diag = diag(Call->getExprLoc(),
"use '%0' to check for membership")
124 SourceLocation FuncCallLoc = Comparison->getEndLoc();
125 if (!FuncCallLoc.isValid() || FuncCallLoc.isMacroID())
128 const StringRef SearchExprText = Lexer::getSourceText(
129 CharSourceRange::getTokenRange(SearchExpr->getSourceRange()),
130 *Result.SourceManager, Result.Context->getLangOpts());
133 Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
134 Comparison->getBeginLoc(), Call->getBeginLoc()));
137 Diag << FixItHint::CreateReplacement(Call->getExprLoc(), ContainsFunName);
140 Diag << FixItHint::CreateReplacement(
141 CharSourceRange::getTokenRange(Call->getArg(0)->getBeginLoc(),
142 Comparison->getEndLoc()),
143 (SearchExprText +
")").str());
147 Diag << FixItHint::CreateInsertion(Call->getBeginLoc(),
"!");