99#include " UseStartsEndsWithCheck.h"
1010
1111#include " ../utils/ASTUtils.h"
12- #include " ../utils/OptionsUtils.h"
12+ #include " ../utils/Matchers.h"
13+ #include " clang/ASTMatchers/ASTMatchers.h"
1314#include " clang/Lex/Lexer.h"
1415
1516#include < string>
@@ -82,60 +83,53 @@ UseStartsEndsWithCheck::UseStartsEndsWithCheck(StringRef Name,
8283void UseStartsEndsWithCheck::registerMatchers (MatchFinder *Finder) {
8384 const auto ZeroLiteral = integerLiteral (equals (0 ));
8485
85- const auto HasStartsWithMethodWithName = [](const std::string &Name) {
86- return hasMethod (
87- cxxMethodDecl (hasName (Name), isConst (), parameterCountIs (1 ))
88- .bind (" starts_with_fun" ));
86+ const auto ClassTypeWithMethod = [](const StringRef MethodBoundName,
87+ const auto ... Methods) {
88+ return cxxRecordDecl (anyOf (
89+ hasMethod (cxxMethodDecl (isConst (), parameterCountIs (1 ),
90+ returns (booleanType ()), hasAnyName (Methods))
91+ .bind (MethodBoundName))...));
8992 };
90- const auto HasStartsWithMethod =
91- anyOf (HasStartsWithMethodWithName (" starts_with" ),
92- HasStartsWithMethodWithName (" startsWith" ),
93- HasStartsWithMethodWithName (" startswith" ));
93+
9494 const auto OnClassWithStartsWithFunction =
95- on (hasType (hasCanonicalType (hasDeclaration (cxxRecordDecl (
96- anyOf (HasStartsWithMethod,
97- hasAnyBase (hasType (hasCanonicalType (
98- hasDeclaration (cxxRecordDecl (HasStartsWithMethod)))))))))));
99-
100- const auto HasEndsWithMethodWithName = [](const std::string &Name) {
101- return hasMethod (
102- cxxMethodDecl (hasName (Name), isConst (), parameterCountIs (1 ))
103- .bind (" ends_with_fun" ));
104- };
105- const auto HasEndsWithMethod = anyOf (HasEndsWithMethodWithName (" ends_with" ),
106- HasEndsWithMethodWithName (" endsWith" ),
107- HasEndsWithMethodWithName (" endswith" ));
108- const auto OnClassWithEndsWithFunction =
109- on (expr (hasType (hasCanonicalType (hasDeclaration (cxxRecordDecl (
110- anyOf (HasEndsWithMethod,
111- hasAnyBase (hasType (hasCanonicalType (hasDeclaration (
112- cxxRecordDecl (HasEndsWithMethod)))))))))))
113- .bind (" haystack" ));
95+ ClassTypeWithMethod (" starts_with_fun" , " starts_with" , " startsWith" ,
96+ " startswith" , " StartsWith" );
97+
98+ const auto OnClassWithEndsWithFunction = ClassTypeWithMethod (
99+ " ends_with_fun" , " ends_with" , " endsWith" , " endswith" , " EndsWith" );
114100
115101 // Case 1: X.find(Y) [!=]= 0 -> starts_with.
116102 const auto FindExpr = cxxMemberCallExpr (
117103 anyOf (argumentCountIs (1 ), hasArgument (1 , ZeroLiteral)),
118- callee (cxxMethodDecl (hasName (" find" )).bind (" find_fun" )),
119- OnClassWithStartsWithFunction, hasArgument (0 , expr ().bind (" needle" )));
104+ callee (
105+ cxxMethodDecl (hasName (" find" ), ofClass (OnClassWithStartsWithFunction))
106+ .bind (" find_fun" )),
107+ hasArgument (0 , expr ().bind (" needle" )));
120108
121109 // Case 2: X.rfind(Y, 0) [!=]= 0 -> starts_with.
122110 const auto RFindExpr = cxxMemberCallExpr (
123111 hasArgument (1 , ZeroLiteral),
124- callee (cxxMethodDecl (hasName (" rfind" )).bind (" find_fun" )),
125- OnClassWithStartsWithFunction, hasArgument (0 , expr ().bind (" needle" )));
112+ callee (cxxMethodDecl (hasName (" rfind" ),
113+ ofClass (OnClassWithStartsWithFunction))
114+ .bind (" find_fun" )),
115+ hasArgument (0 , expr ().bind (" needle" )));
126116
127117 // Case 3: X.compare(0, LEN(Y), Y) [!=]= 0 -> starts_with.
128118 const auto CompareExpr = cxxMemberCallExpr (
129119 argumentCountIs (3 ), hasArgument (0 , ZeroLiteral),
130- callee (cxxMethodDecl (hasName (" compare" )).bind (" find_fun" )),
131- OnClassWithStartsWithFunction, hasArgument (2 , expr ().bind (" needle" )),
120+ callee (cxxMethodDecl (hasName (" compare" ),
121+ ofClass (OnClassWithStartsWithFunction))
122+ .bind (" find_fun" )),
123+ hasArgument (2 , expr ().bind (" needle" )),
132124 hasArgument (1 , lengthExprForStringNode (" needle" )));
133125
134126 // Case 4: X.compare(LEN(X) - LEN(Y), LEN(Y), Y) [!=]= 0 -> ends_with.
135127 const auto CompareEndsWithExpr = cxxMemberCallExpr (
136128 argumentCountIs (3 ),
137- callee (cxxMethodDecl (hasName (" compare" )).bind (" find_fun" )),
138- OnClassWithEndsWithFunction, hasArgument (2 , expr ().bind (" needle" )),
129+ callee (cxxMethodDecl (hasName (" compare" ),
130+ ofClass (OnClassWithEndsWithFunction))
131+ .bind (" find_fun" )),
132+ on (expr ().bind (" haystack" )), hasArgument (2 , expr ().bind (" needle" )),
139133 hasArgument (1 , lengthExprForStringNode (" needle" )),
140134 hasArgument (0 ,
141135 binaryOperator (hasOperatorName (" -" ),
@@ -145,7 +139,7 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
145139 // All cases comparing to 0.
146140 Finder->addMatcher (
147141 binaryOperator (
148- hasAnyOperatorName ( " == " , " != " ),
142+ matchers::isEqualityOperator ( ),
149143 hasOperands (cxxMemberCallExpr (anyOf (FindExpr, RFindExpr, CompareExpr,
150144 CompareEndsWithExpr))
151145 .bind (" find_expr" ),
@@ -156,7 +150,7 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
156150 // Case 5: X.rfind(Y) [!=]= LEN(X) - LEN(Y) -> ends_with.
157151 Finder->addMatcher (
158152 binaryOperator (
159- hasAnyOperatorName ( " == " , " != " ),
153+ matchers::isEqualityOperator ( ),
160154 hasOperands (
161155 cxxMemberCallExpr (
162156 anyOf (
@@ -166,8 +160,10 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
166160 1 ,
167161 anyOf (declRefExpr (to (varDecl (hasName (" npos" )))),
168162 memberExpr (member (hasName (" npos" ))))))),
169- callee (cxxMethodDecl (hasName (" rfind" )).bind (" find_fun" )),
170- OnClassWithEndsWithFunction,
163+ callee (cxxMethodDecl (hasName (" rfind" ),
164+ ofClass (OnClassWithEndsWithFunction))
165+ .bind (" find_fun" )),
166+ on (expr ().bind (" haystack" )),
171167 hasArgument (0 , expr ().bind (" needle" )))
172168 .bind (" find_expr" ),
173169 binaryOperator (hasOperatorName (" -" ),
@@ -190,9 +186,8 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
190186 const CXXMethodDecl *ReplacementFunction =
191187 StartsWithFunction ? StartsWithFunction : EndsWithFunction;
192188
193- if (ComparisonExpr->getBeginLoc ().isMacroID ()) {
189+ if (ComparisonExpr->getBeginLoc ().isMacroID ())
194190 return ;
195- }
196191
197192 const bool Neg = ComparisonExpr->getOpcode () == BO_NE;
198193
@@ -220,9 +215,8 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
220215 (ReplacementFunction->getName () + " (" ).str ());
221216
222217 // Add possible negation '!'.
223- if (Neg) {
218+ if (Neg)
224219 Diagnostic << FixItHint::CreateInsertion (FindExpr->getBeginLoc (), " !" );
225- }
226220}
227221
228222} // namespace clang::tidy::modernize
0 commit comments