llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tidy

Author: None (flovent)

<details>
<summary>Changes</summary>

`readability-container-size-empty` skip check in container's all method, but 
only `empty` method is nesscessary to skip because it's usually implemented by 
`size`, so this patch allows reporting in other methods.

Note: testcase about not reporting in `empty` is already added in the past, so 
i only add testcases for other methods.

Closes #<!-- -->152649

---
Full diff: https://github.com/llvm/llvm-project/pull/154017.diff


3 Files Affected:

- (modified) 
clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp (+45-22) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+2-1) 
- (modified) 
clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp 
(+43) 


``````````diff
diff --git 
a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
index c4dc319f23c38..38c0330c02a7e 100644
--- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -110,6 +110,25 @@ AST_MATCHER_P(UserDefinedLiteral, hasLiteral,
   return false;
 }
 
+AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl,
+              clang::ast_matchers::internal::Matcher<CXXMethodDecl>,
+              InnerMatcher) {
+  return InnerMatcher.matches(*Node.getCanonicalDecl(), Finder, Builder);
+}
+
+AST_POLYMORPHIC_MATCHER_P(
+    matchMemberName,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(MemberExpr, CXXDependentScopeMemberExpr),
+    std::string, MemberName) {
+  if (const auto *E = dyn_cast<MemberExpr>(&Node))
+    return E->getMemberDecl()->getName() == MemberName;
+
+  if (const auto *E = dyn_cast<CXXDependentScopeMemberExpr>(&Node))
+    return E->getMember().getAsString() == MemberName;
+
+  return false;
+}
+
 } // namespace
 
 using utils::isBinaryOrTernary;
@@ -140,9 +159,10 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder 
*Finder) {
   const auto ValidContainerNonTemplateType =
       qualType(hasUnqualifiedDesugaredType(
           recordType(hasDeclaration(ValidContainerRecord))));
-  const auto ValidContainerTemplateType =
-      qualType(hasUnqualifiedDesugaredType(templateSpecializationType(
-          hasDeclaration(classTemplateDecl(has(ValidContainerRecord))))));
+  const auto ValidContainerTemplateType = qualType(hasUnqualifiedDesugaredType(
+      anyOf(templateSpecializationType(
+                hasDeclaration(classTemplateDecl(has(ValidContainerRecord)))),
+            injectedClassNameType(hasDeclaration(ValidContainerRecord)))));
 
   const auto ValidContainer = qualType(
       anyOf(ValidContainerNonTemplateType, ValidContainerTemplateType));
@@ -155,6 +175,9 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder 
*Finder) {
                           .bind("SizeBinaryOp")),
             usedInBooleanContext());
 
+  const auto NotInEmptyMethodOfContainer = unless(
+      forCallable(cxxMethodDecl(hasCanonicalDecl(equalsBoundNode("empty")))));
+
   Finder->addMatcher(
       cxxMemberCallExpr(
           argumentCountIs(0),
@@ -164,25 +187,23 @@ void 
ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
                  .bind("MemberCallObject")),
           callee(
               cxxMethodDecl(hasAnyName("size", "length")).bind("SizeMethod")),
-          WrongUse,
-          unless(hasAncestor(
-              cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+          WrongUse, NotInEmptyMethodOfContainer)
           .bind("SizeCallExpr"),
       this);
 
   Finder->addMatcher(
-      callExpr(argumentCountIs(0),
-               has(cxxDependentScopeMemberExpr(
-                       hasObjectExpression(
-                           expr(anyOf(hasType(ValidContainer),
-                                      hasType(pointsTo(ValidContainer)),
-                                      hasType(references(ValidContainer))))
-                               .bind("MemberCallObject")),
-                       anyOf(hasMemberName("size"), hasMemberName("length")))
-                       .bind("DependentExpr")),
-               WrongUse,
-               unless(hasAncestor(
-                   cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+      callExpr(
+          argumentCountIs(0),
+          has(mapAnyOf(memberExpr, cxxDependentScopeMemberExpr)
+                  .with(
+                      hasObjectExpression(
+                          expr(anyOf(hasType(ValidContainer),
+                                     hasType(pointsTo(ValidContainer)),
+                                     hasType(references(ValidContainer))))
+                              .bind("MemberCallObject")),
+                      anyOf(matchMemberName("size"), 
matchMemberName("length")))
+                  .bind("MemberExpr")),
+          WrongUse, NotInEmptyMethodOfContainer)
           .bind("SizeCallExpr"),
       this);
 
@@ -217,8 +238,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder 
*Finder) {
           hasAnyOperatorName("==", "!="), hasOperands(WrongComparend, STLArg),
           unless(allOf(hasLHS(hasType(ExcludedComparisonTypesMatcher)),
                        hasRHS(hasType(SameExcludedComparisonTypesMatcher)))),
-          unless(hasAncestor(
-              cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+          NotInEmptyMethodOfContainer)
           .bind("BinCmp"),
       this);
 }
@@ -382,9 +402,12 @@ void ContainerSizeEmptyCheck::check(const 
MatchFinder::MatchResult &Result) {
       Diag << SizeMethod;
     else if (const auto *DependentExpr =
                  Result.Nodes.getNodeAs<CXXDependentScopeMemberExpr>(
-                     "DependentExpr"))
+                     "MemberExpr"))
       Diag << DependentExpr->getMember();
-    else
+    else if (const auto *ME =
+                 Result.Nodes.getNodeAs<MemberExpr>("MemberExpr")) {
+      Diag << ME->getMemberNameInfo().getName();
+    } else
       Diag << "unknown method";
     Diag << Hint;
   } else {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index fd81b0d47e82b..a0ef1b6767cbe 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -202,7 +202,8 @@ Changes in existing checks
 
 - Improved :doc:`readability-container-size-empty
   <clang-tidy/checks/readability/container-size-empty>` check by correctly
-  generating fix-it hints when size method is called from implicit ``this``.
+  generating fix-it hints when size method is called from implicit ``this``
+  and adding detection in container's method except ``empty``.
 
 - Improved :doc:`readability-identifier-naming
   <clang-tidy/checks/readability/identifier-naming>` check by ignoring
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
index b1e68672a3a9a..decc9d2782218 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
@@ -908,3 +908,46 @@ class foo : public std::string{
 };
 
 }
+
+class ReportInContainerNonEmptyMethod {
+public:
+  int size() const;
+  bool empty() const;
+
+  void doit() {
+    if (!size()) {
+      // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should 
be used to check for emptiness instead of 'size'
+      // CHECK-FIXES: if (empty())
+    }
+  }
+};
+
+template <typename T>
+class ReportInTemplateContainerNonEmptyMethod {
+public:
+  int size() const;
+  bool empty() const;
+
+  void doit() {
+    if (!size()) {
+      // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should 
be used to check for emptiness instead of 'size'
+      // CHECK-FIXES: if (empty()) {
+    }
+  }
+};
+
+
+
+class ReportInContainerNonEmptyMethodCompare {
+public:
+  bool operator==(const ReportInContainerNonEmptyMethodCompare& other) const;
+  int size() const;
+  bool empty() const;
+
+  void doit() {
+    if (*this == ReportInContainerNonEmptyMethodCompare()) {
+      // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: the 'empty' method should be 
used to check for emptiness instead of comparing to an empty object
+      // CHECK-FIXES: if (this->empty()) {
+    }
+  }
+};

``````````

</details>


https://github.com/llvm/llvm-project/pull/154017
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to