Author: FabianWolff
Date: 2025-05-27T12:06:08+02:00
New Revision: 47d5e94acb92ce4ec5040e95e167ba471d080244

URL: 
https://github.com/llvm/llvm-project/commit/47d5e94acb92ce4ec5040e95e167ba471d080244
DIFF: 
https://github.com/llvm/llvm-project/commit/47d5e94acb92ce4ec5040e95e167ba471d080244.diff

LOG: [clang-tidy] readability-redundant-smartptr-get: disable for smart 
pointers to arrays (#141092)

Currently we generate an incorrect suggestion for shared/unique pointers
to arrays; for instance ([Godbolt](https://godbolt.org/z/Tens1reGP)):
```c++
#include <memory>

void test_shared_ptr_to_array() {
  std::shared_ptr<int[]> i;
  auto s = sizeof(*i.get());
}
```
```
<source>:5:20: warning: redundant get() call on smart pointer 
[readability-redundant-smartptr-get]
    5 |   auto s = sizeof(*i.get());
      |                    ^~~~~~~
      |                    i
1 warning generated.
```
`sizeof(*i)` is incorrect, though, because the array specialization of
`std::shared/unique_ptr` does not have an `operator*()`. Therefore I
have disabled this check for smart pointers to arrays for now; future
work could, of course, improve on this by suggesting, say,
`sizeof(i[0])` in the above example.

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp
    
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get-msvc.cpp
    
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp
index be52af77ae0a5..baa977750d101 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp
@@ -49,29 +49,41 @@ internal::Matcher<Decl> knownSmartptr() {
 
 void registerMatchersForGetArrowStart(MatchFinder *Finder,
                                       MatchFinder::MatchCallback *Callback) {
-  const auto QuacksLikeASmartptr = recordDecl(
-      recordDecl().bind("duck_typing"),
-      has(cxxMethodDecl(hasName("operator->"),
-                        returns(qualType(pointsTo(type().bind("op->Type")))))),
-      has(cxxMethodDecl(hasName("operator*"), returns(qualType(references(
-                                                  type().bind("op*Type")))))));
+  const auto MatchesOpArrow =
+      allOf(hasName("operator->"),
+            returns(qualType(pointsTo(type().bind("op->Type")))));
+  const auto MatchesOpStar =
+      allOf(hasName("operator*"),
+            returns(qualType(references(type().bind("op*Type")))));
+  const auto HasRelevantOps =
+      allOf(anyOf(hasMethod(MatchesOpArrow),
+                  
has(functionTemplateDecl(has(functionDecl(MatchesOpArrow))))),
+            anyOf(hasMethod(MatchesOpStar),
+                  
has(functionTemplateDecl(has(functionDecl(MatchesOpStar))))));
+
+  const auto QuacksLikeASmartptr =
+      cxxRecordDecl(cxxRecordDecl().bind("duck_typing"), HasRelevantOps);
 
   // Make sure we are not missing the known standard types.
-  const auto Smartptr = anyOf(knownSmartptr(), QuacksLikeASmartptr);
+  const auto SmartptrAny = anyOf(knownSmartptr(), QuacksLikeASmartptr);
+  const auto SmartptrWithDeref =
+      anyOf(cxxRecordDecl(knownSmartptr(), HasRelevantOps), 
QuacksLikeASmartptr);
 
   // Catch 'ptr.get()->Foo()'
-  Finder->addMatcher(memberExpr(expr().bind("memberExpr"), isArrow(),
-                                hasObjectExpression(callToGet(Smartptr))),
-                     Callback);
+  Finder->addMatcher(
+      memberExpr(expr().bind("memberExpr"), isArrow(),
+                 hasObjectExpression(callToGet(SmartptrWithDeref))),
+      Callback);
 
   // Catch '*ptr.get()' or '*ptr->get()'
   Finder->addMatcher(
-      unaryOperator(hasOperatorName("*"), 
hasUnaryOperand(callToGet(Smartptr))),
+      unaryOperator(hasOperatorName("*"),
+                    hasUnaryOperand(callToGet(SmartptrWithDeref))),
       Callback);
 
   // Catch '!ptr.get()'
   const auto CallToGetAsBool = callToGet(
-      recordDecl(Smartptr, has(cxxConversionDecl(returns(booleanType())))));
+      recordDecl(SmartptrAny, has(cxxConversionDecl(returns(booleanType())))));
   Finder->addMatcher(
       unaryOperator(hasOperatorName("!"), hasUnaryOperand(CallToGetAsBool)),
       Callback);
@@ -84,7 +96,7 @@ void registerMatchersForGetArrowStart(MatchFinder *Finder,
                      Callback);
 
   Finder->addMatcher(cxxDependentScopeMemberExpr(hasObjectExpression(
-                         callExpr(has(callToGet(Smartptr))).bind("obj"))),
+                         callExpr(has(callToGet(SmartptrAny))))),
                      Callback);
 }
 

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get-msvc.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get-msvc.cpp
index bd8990a27b263..b360ccbadfa5f 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get-msvc.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get-msvc.cpp
@@ -16,6 +16,14 @@ struct unique_ptr {
   explicit operator bool() const noexcept;
 };
 
+template <typename T>
+struct unique_ptr<T[]> {
+  template <typename T2 = T>
+  T2* operator[](unsigned) const;
+  T* get() const;
+  explicit operator bool() const noexcept;
+};
+
 template <typename T>
 struct shared_ptr {
   template <typename T2 = T>
@@ -26,6 +34,14 @@ struct shared_ptr {
   explicit operator bool() const noexcept;
 };
 
+template <typename T>
+struct shared_ptr<T[]> {
+  template <typename T2 = T>
+  T2* operator[](unsigned) const;
+  T* get() const;
+  explicit operator bool() const noexcept;
+};
+
 }  // namespace std
 
 struct Bar {
@@ -92,3 +108,31 @@ void Positive() {
   // CHECK-MESSAGES: if (NULL == x.get());
   // CHECK-FIXES: if (NULL == x);
 }
+
+void test_smart_ptr_to_array() {
+  std::unique_ptr<int[]> i;
+  // The array specialization does not have operator*(), so make sure
+  // we do not incorrectly suggest sizeof(*i) here.
+  // FIXME: alternatively, we could suggest sizeof(i[0])
+  auto sz = sizeof(*i.get());
+
+  std::shared_ptr<Bar[]> s;
+  // The array specialization does not have operator->() either
+  s.get()->Do();
+
+  bool b1 = !s.get();
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant get() call
+  // CHECK-FIXES: bool b1 = !s;
+
+  if (s.get()) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call
+  // CHECK-FIXES: if (s) {}
+
+  int x = s.get() ? 1 : 2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant get() call
+  // CHECK-FIXES: int x = s ? 1 : 2;
+
+  bool b2 = s.get() == nullptr;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call
+  // CHECK-FIXES: bool b2 = s == nullptr;
+}

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get.cpp
index ec4ca4cb79484..42e948fcb2a7f 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-smartptr-get.cpp
@@ -12,6 +12,13 @@ struct unique_ptr {
   explicit operator bool() const noexcept;
 };
 
+template <typename T>
+struct unique_ptr<T[]> {
+  T& operator[](unsigned) const;
+  T* get() const;
+  explicit operator bool() const noexcept;
+};
+
 template <typename T>
 struct shared_ptr {
   T& operator*() const;
@@ -20,6 +27,13 @@ struct shared_ptr {
   explicit operator bool() const noexcept;
 };
 
+template <typename T>
+struct shared_ptr<T[]> {
+  T& operator[](unsigned) const;
+  T* get() const;
+  explicit operator bool() const noexcept;
+};
+
 template <typename T>
 struct vector {
   vector();
@@ -283,3 +297,31 @@ void test_redundant_get_with_member() {
     // CHECK-FIXES: f(**i->get()->getValue());
  }
 }
+
+void test_smart_ptr_to_array() {
+  std::unique_ptr<int[]> i;
+  // The array specialization does not have operator*(), so make sure
+  // we do not incorrectly suggest sizeof(*i) here.
+  // FIXME: alternatively, we could suggest sizeof(i[0])
+  auto sz = sizeof(*i.get());
+
+  std::shared_ptr<Inner[]> s;
+  // The array specialization does not have operator->() either
+  s.get()->getValue();
+
+  bool b1 = !s.get();
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant get() call
+  // CHECK-FIXES: bool b1 = !s;
+
+  if (s.get()) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call
+  // CHECK-FIXES: if (s) {}
+
+  int x = s.get() ? 1 : 2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant get() call
+  // CHECK-FIXES: int x = s ? 1 : 2;
+
+  bool b2 = s.get() == nullptr;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call
+  // CHECK-FIXES: bool b2 = s == nullptr;
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to