@@ -110,6 +110,25 @@ AST_MATCHER_P(UserDefinedLiteral, hasLiteral,
110
110
return false ;
111
111
}
112
112
113
+ AST_MATCHER_P (CXXMethodDecl, hasCanonicalDecl,
114
+ clang::ast_matchers::internal::Matcher<CXXMethodDecl>,
115
+ InnerMatcher) {
116
+ return InnerMatcher.matches (*Node.getCanonicalDecl (), Finder, Builder);
117
+ }
118
+
119
+ AST_POLYMORPHIC_MATCHER_P (
120
+ matchMemberName,
121
+ AST_POLYMORPHIC_SUPPORTED_TYPES (MemberExpr, CXXDependentScopeMemberExpr),
122
+ std::string, MemberName) {
123
+ if (const auto *E = dyn_cast<MemberExpr>(&Node))
124
+ return E->getMemberDecl ()->getName () == MemberName;
125
+
126
+ if (const auto *E = dyn_cast<CXXDependentScopeMemberExpr>(&Node))
127
+ return E->getMember ().getAsString () == MemberName;
128
+
129
+ return false ;
130
+ }
131
+
113
132
} // namespace
114
133
115
134
using utils::isBinaryOrTernary;
@@ -140,9 +159,10 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
140
159
const auto ValidContainerNonTemplateType =
141
160
qualType (hasUnqualifiedDesugaredType (
142
161
recordType (hasDeclaration (ValidContainerRecord))));
143
- const auto ValidContainerTemplateType =
144
- qualType (hasUnqualifiedDesugaredType (templateSpecializationType (
145
- hasDeclaration (classTemplateDecl (has (ValidContainerRecord))))));
162
+ const auto ValidContainerTemplateType = qualType (hasUnqualifiedDesugaredType (
163
+ anyOf (templateSpecializationType (
164
+ hasDeclaration (classTemplateDecl (has (ValidContainerRecord)))),
165
+ injectedClassNameType (hasDeclaration (ValidContainerRecord)))));
146
166
147
167
const auto ValidContainer = qualType (
148
168
anyOf (ValidContainerNonTemplateType, ValidContainerTemplateType));
@@ -155,6 +175,9 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
155
175
.bind (" SizeBinaryOp" )),
156
176
usedInBooleanContext ());
157
177
178
+ const auto NotInEmptyMethodOfContainer = unless (
179
+ forCallable (cxxMethodDecl (hasCanonicalDecl (equalsBoundNode (" empty" )))));
180
+
158
181
Finder->addMatcher (
159
182
cxxMemberCallExpr (
160
183
argumentCountIs (0 ),
@@ -164,25 +187,23 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
164
187
.bind (" MemberCallObject" )),
165
188
callee (
166
189
cxxMethodDecl (hasAnyName (" size" , " length" )).bind (" SizeMethod" )),
167
- WrongUse,
168
- unless (hasAncestor (
169
- cxxMethodDecl (ofClass (equalsBoundNode (" container" ))))))
190
+ WrongUse, NotInEmptyMethodOfContainer)
170
191
.bind (" SizeCallExpr" ),
171
192
this );
172
193
173
194
Finder->addMatcher (
174
- callExpr (argumentCountIs ( 0 ),
175
- has ( cxxDependentScopeMemberExpr (
176
- hasObjectExpression (
177
- expr ( anyOf ( hasType (ValidContainer),
178
- hasType ( pointsTo (ValidContainer)),
179
- hasType ( references ( ValidContainer))))
180
- . bind ( " MemberCallObject " )),
181
- anyOf ( hasMemberName ( " size " ), hasMemberName ( " length " )))
182
- .bind (" DependentExpr " )),
183
- WrongUse,
184
- unless ( hasAncestor (
185
- cxxMethodDecl ( ofClass ( equalsBoundNode ( " container " ))))) )
195
+ callExpr (
196
+ argumentCountIs ( 0 ),
197
+ has ( mapAnyOf (memberExpr, cxxDependentScopeMemberExpr)
198
+ . with (
199
+ hasObjectExpression (
200
+ expr ( anyOf ( hasType ( ValidContainer),
201
+ hasType ( pointsTo (ValidContainer )),
202
+ hasType ( references (ValidContainer) )))
203
+ .bind (" MemberCallObject " )),
204
+ anyOf ( matchMemberName ( " size " ), matchMemberName ( " length " )))
205
+ . bind ( " MemberExpr " )),
206
+ WrongUse, NotInEmptyMethodOfContainer )
186
207
.bind (" SizeCallExpr" ),
187
208
this );
188
209
@@ -217,8 +238,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
217
238
hasAnyOperatorName (" ==" , " !=" ), hasOperands (WrongComparend, STLArg),
218
239
unless (allOf (hasLHS (hasType (ExcludedComparisonTypesMatcher)),
219
240
hasRHS (hasType (SameExcludedComparisonTypesMatcher)))),
220
- unless (hasAncestor (
221
- cxxMethodDecl (ofClass (equalsBoundNode (" container" ))))))
241
+ NotInEmptyMethodOfContainer)
222
242
.bind (" BinCmp" ),
223
243
this );
224
244
}
@@ -382,9 +402,12 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
382
402
Diag << SizeMethod;
383
403
else if (const auto *DependentExpr =
384
404
Result.Nodes .getNodeAs <CXXDependentScopeMemberExpr>(
385
- " DependentExpr " ))
405
+ " MemberExpr " ))
386
406
Diag << DependentExpr->getMember ();
387
- else
407
+ else if (const auto *ME =
408
+ Result.Nodes .getNodeAs <MemberExpr>(" MemberExpr" )) {
409
+ Diag << ME->getMemberNameInfo ().getName ();
410
+ } else
388
411
Diag << " unknown method" ;
389
412
Diag << Hint;
390
413
} else {
0 commit comments