103 const auto ZeroLiteral = integerLiteral(equals(0));
105 const auto ClassTypeWithMethod = [](
const StringRef MethodBoundName,
106 const auto... Methods) {
107 return cxxRecordDecl(anyOf(
108 hasMethod(cxxMethodDecl(isConst(), parameterCountIs(1),
109 returns(booleanType()), hasAnyName(Methods))
110 .bind(MethodBoundName))...));
113 const auto OnClassWithStartsWithFunction =
114 ClassTypeWithMethod(
"starts_with_fun",
"starts_with",
"startsWith",
115 "startswith",
"StartsWith");
117 const auto OnClassWithEndsWithFunction = ClassTypeWithMethod(
118 "ends_with_fun",
"ends_with",
"endsWith",
"endswith",
"EndsWith");
121 const auto FindExpr = cxxMemberCallExpr(
123 cxxMethodDecl(hasName(
"find"), ofClass(OnClassWithStartsWithFunction))
125 hasArgument(0, expr().bind(
"needle")),
130 allOf(argumentCountIs(2), hasArgument(1, ZeroLiteral)),
132 allOf(argumentCountIs(3), hasArgument(1, ZeroLiteral),
133 hasArgument(2, lengthExprForStringNode(
"needle")))));
136 const auto RFindExpr = cxxMemberCallExpr(
137 callee(cxxMethodDecl(hasName(
"rfind"),
138 ofClass(OnClassWithStartsWithFunction))
140 hasArgument(0, expr().bind(
"needle")),
143 allOf(argumentCountIs(2), hasArgument(1, ZeroLiteral)),
145 allOf(argumentCountIs(3), hasArgument(1, ZeroLiteral),
146 hasArgument(2, lengthExprForStringNode(
"needle")))));
149 const auto CompareExpr = cxxMemberCallExpr(
150 argumentCountIs(3), hasArgument(0, ZeroLiteral),
151 callee(cxxMethodDecl(hasName(
"compare"),
152 ofClass(OnClassWithStartsWithFunction))
154 hasArgument(2, expr().bind(
"needle")),
155 hasArgument(1, lengthExprForStringNode(
"needle")));
158 const auto CompareEndsWithExpr = cxxMemberCallExpr(
160 callee(cxxMethodDecl(hasName(
"compare"),
161 ofClass(OnClassWithEndsWithFunction))
163 on(expr().bind(
"haystack")), hasArgument(2, expr().bind(
"needle")),
164 hasArgument(1, lengthExprForStringNode(
"needle")),
166 binaryOperator(hasOperatorName(
"-"),
167 hasLHS(lengthExprForStringNode(
"haystack")),
168 hasRHS(lengthExprForStringNode(
"needle")))));
173 matchers::isEqualityOperator(),
174 hasOperands(cxxMemberCallExpr(anyOf(FindExpr, RFindExpr, CompareExpr,
175 CompareEndsWithExpr))
184 matchers::isEqualityOperator(),
189 allOf(argumentCountIs(2),
192 anyOf(declRefExpr(to(varDecl(hasName(
"npos")))),
193 memberExpr(member(hasName(
"npos"))))))),
194 callee(cxxMethodDecl(hasName(
"rfind"),
195 ofClass(OnClassWithEndsWithFunction))
197 on(expr().bind(
"haystack")),
198 hasArgument(0, expr().bind(
"needle")))
200 binaryOperator(hasOperatorName(
"-"),
201 hasLHS(lengthExprForStringNode(
"haystack")),
202 hasRHS(lengthExprForStringNode(
"needle")))))
209 hasAnyOperatorName(
"==",
"!="),
211 expr().bind(
"needle"),
213 argumentCountIs(2), hasArgument(0, ZeroLiteral),
214 hasArgument(1, lengthExprForStringNode(
"needle")),
215 callee(cxxMethodDecl(hasName(
"substr"),
216 ofClass(OnClassWithStartsWithFunction))
224 const auto *ComparisonExpr = Result.Nodes.getNodeAs<Expr>(
"expr");
225 const auto *FindExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"find_expr");
226 const auto *FindFun = Result.Nodes.getNodeAs<CXXMethodDecl>(
"find_fun");
227 const auto *SearchExpr = Result.Nodes.getNodeAs<Expr>(
"needle");
228 const auto *StartsWithFunction =
229 Result.Nodes.getNodeAs<CXXMethodDecl>(
"starts_with_fun");
230 const auto *EndsWithFunction =
231 Result.Nodes.getNodeAs<CXXMethodDecl>(
"ends_with_fun");
232 assert(
bool(StartsWithFunction) !=
bool(EndsWithFunction));
234 const CXXMethodDecl *ReplacementFunction =
235 StartsWithFunction ? StartsWithFunction : EndsWithFunction;
237 if (ComparisonExpr->getBeginLoc().isMacroID() ||
238 FindExpr->getBeginLoc().isMacroID())
242 if (FindExpr->getNumArgs() == 0)
246 const auto SearchExprText = Lexer::getSourceText(
247 CharSourceRange::getTokenRange(SearchExpr->getSourceRange()),
248 *Result.SourceManager, Result.Context->getLangOpts());
250 auto Diagnostic = diag(FindExpr->getExprLoc(),
"use %0 instead of %1")
251 << ReplacementFunction->getName() << FindFun->getName();
254 Diagnostic << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
255 ComparisonExpr->getBeginLoc(), FindExpr->getBeginLoc()));
258 Diagnostic << FixItHint::CreateReplacement(FindExpr->getExprLoc(),
259 ReplacementFunction->getName());
262 Diagnostic << FixItHint::CreateReplacement(
263 CharSourceRange::getTokenRange(FindExpr->getArg(0)->getBeginLoc(),
264 ComparisonExpr->getEndLoc()),
265 (SearchExprText +
")").str());
269 Diagnostic << FixItHint::CreateInsertion(FindExpr->getBeginLoc(),
"!");
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.