@@ -110,6 +110,25 @@ AST_MATCHER_P(UserDefinedLiteral, hasLiteral,
110110 return false ;
111111}
112112
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+
113132} // namespace
114133
115134using utils::isBinaryOrTernary;
@@ -140,9 +159,10 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
140159 const auto ValidContainerNonTemplateType =
141160 qualType (hasUnqualifiedDesugaredType (
142161 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)))));
146166
147167 const auto ValidContainer = qualType (
148168 anyOf (ValidContainerNonTemplateType, ValidContainerTemplateType));
@@ -155,6 +175,9 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
155175 .bind (" SizeBinaryOp" )),
156176 usedInBooleanContext ());
157177
178+ const auto NotInEmptyMethodOfContainer = unless (
179+ forCallable (cxxMethodDecl (hasCanonicalDecl (equalsBoundNode (" empty" )))));
180+
158181 Finder->addMatcher (
159182 cxxMemberCallExpr (
160183 argumentCountIs (0 ),
@@ -164,25 +187,23 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
164187 .bind (" MemberCallObject" )),
165188 callee (
166189 cxxMethodDecl (hasAnyName (" size" , " length" )).bind (" SizeMethod" )),
167- WrongUse,
168- unless (hasAncestor (
169- cxxMethodDecl (ofClass (equalsBoundNode (" container" ))))))
190+ WrongUse, NotInEmptyMethodOfContainer)
170191 .bind (" SizeCallExpr" ),
171192 this );
172193
173194 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 )
186207 .bind (" SizeCallExpr" ),
187208 this );
188209
@@ -217,8 +238,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
217238 hasAnyOperatorName (" ==" , " !=" ), hasOperands (WrongComparend, STLArg),
218239 unless (allOf (hasLHS (hasType (ExcludedComparisonTypesMatcher)),
219240 hasRHS (hasType (SameExcludedComparisonTypesMatcher)))),
220- unless (hasAncestor (
221- cxxMethodDecl (ofClass (equalsBoundNode (" container" ))))))
241+ NotInEmptyMethodOfContainer)
222242 .bind (" BinCmp" ),
223243 this );
224244}
@@ -382,9 +402,12 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
382402 Diag << SizeMethod;
383403 else if (const auto *DependentExpr =
384404 Result.Nodes .getNodeAs <CXXDependentScopeMemberExpr>(
385- " DependentExpr " ))
405+ " MemberExpr " ))
386406 Diag << DependentExpr->getMember ();
387- else
407+ else if (const auto *ME =
408+ Result.Nodes .getNodeAs <MemberExpr>(" MemberExpr" )) {
409+ Diag << ME->getMemberNameInfo ().getName ();
410+ } else
388411 Diag << " unknown method" ;
389412 Diag << Hint;
390413 } else {
0 commit comments