9
9
#include " UseStartsEndsWithCheck.h"
10
10
11
11
#include " ../utils/ASTUtils.h"
12
- #include " ../utils/OptionsUtils.h"
12
+ #include " ../utils/Matchers.h"
13
+ #include " clang/ASTMatchers/ASTMatchers.h"
13
14
#include " clang/Lex/Lexer.h"
14
15
15
16
#include < string>
@@ -82,60 +83,53 @@ UseStartsEndsWithCheck::UseStartsEndsWithCheck(StringRef Name,
82
83
void UseStartsEndsWithCheck::registerMatchers (MatchFinder *Finder) {
83
84
const auto ZeroLiteral = integerLiteral (equals (0 ));
84
85
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))...));
89
92
};
90
- const auto HasStartsWithMethod =
91
- anyOf (HasStartsWithMethodWithName (" starts_with" ),
92
- HasStartsWithMethodWithName (" startsWith" ),
93
- HasStartsWithMethodWithName (" startswith" ));
93
+
94
94
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" );
114
100
115
101
// Case 1: X.find(Y) [!=]= 0 -> starts_with.
116
102
const auto FindExpr = cxxMemberCallExpr (
117
103
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" )));
120
108
121
109
// Case 2: X.rfind(Y, 0) [!=]= 0 -> starts_with.
122
110
const auto RFindExpr = cxxMemberCallExpr (
123
111
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" )));
126
116
127
117
// Case 3: X.compare(0, LEN(Y), Y) [!=]= 0 -> starts_with.
128
118
const auto CompareExpr = cxxMemberCallExpr (
129
119
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" )),
132
124
hasArgument (1 , lengthExprForStringNode (" needle" )));
133
125
134
126
// Case 4: X.compare(LEN(X) - LEN(Y), LEN(Y), Y) [!=]= 0 -> ends_with.
135
127
const auto CompareEndsWithExpr = cxxMemberCallExpr (
136
128
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" )),
139
133
hasArgument (1 , lengthExprForStringNode (" needle" )),
140
134
hasArgument (0 ,
141
135
binaryOperator (hasOperatorName (" -" ),
@@ -145,7 +139,7 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
145
139
// All cases comparing to 0.
146
140
Finder->addMatcher (
147
141
binaryOperator (
148
- hasAnyOperatorName ( " == " , " != " ),
142
+ matchers::isEqualityOperator ( ),
149
143
hasOperands (cxxMemberCallExpr (anyOf (FindExpr, RFindExpr, CompareExpr,
150
144
CompareEndsWithExpr))
151
145
.bind (" find_expr" ),
@@ -156,7 +150,7 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
156
150
// Case 5: X.rfind(Y) [!=]= LEN(X) - LEN(Y) -> ends_with.
157
151
Finder->addMatcher (
158
152
binaryOperator (
159
- hasAnyOperatorName ( " == " , " != " ),
153
+ matchers::isEqualityOperator ( ),
160
154
hasOperands (
161
155
cxxMemberCallExpr (
162
156
anyOf (
@@ -166,8 +160,10 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
166
160
1 ,
167
161
anyOf (declRefExpr (to (varDecl (hasName (" npos" )))),
168
162
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" )),
171
167
hasArgument (0 , expr ().bind (" needle" )))
172
168
.bind (" find_expr" ),
173
169
binaryOperator (hasOperatorName (" -" ),
@@ -190,9 +186,8 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
190
186
const CXXMethodDecl *ReplacementFunction =
191
187
StartsWithFunction ? StartsWithFunction : EndsWithFunction;
192
188
193
- if (ComparisonExpr->getBeginLoc ().isMacroID ()) {
189
+ if (ComparisonExpr->getBeginLoc ().isMacroID ())
194
190
return ;
195
- }
196
191
197
192
const bool Neg = ComparisonExpr->getOpcode () == BO_NE;
198
193
@@ -220,9 +215,8 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
220
215
(ReplacementFunction->getName () + " (" ).str ());
221
216
222
217
// Add possible negation '!'.
223
- if (Neg) {
218
+ if (Neg)
224
219
Diagnostic << FixItHint::CreateInsertion (FindExpr->getBeginLoc (), " !" );
225
- }
226
220
}
227
221
228
222
} // namespace clang::tidy::modernize
0 commit comments