[nullability] Smart pointers: Use `thisPointerType` matcher instead of `on`.

The `on` matcher would only match if the implicit object argument was a smart
pointer glvalue (i.e. if the method was called with the syntax `.method()`, but
not if it was a raw pointer to a smart pointer (i.e. if the method was called
with the syntax `->method()`).

This patch adds tests for the affected matchers that fail without the fix.
The patch also adds an "integration test" that uses the `->method()` syntax in a
test for the transfer function.

PiperOrigin-RevId: 590092576
Change-Id: I4def104e6bfdb9cf199fb5dfac2eea0c88e9bdd3
diff --git a/nullability/BUILD b/nullability/BUILD
index e5f3721..b446160 100644
--- a/nullability/BUILD
+++ b/nullability/BUILD
@@ -42,6 +42,7 @@
     srcs = ["pointer_nullability_matchers_test.cc"],
     deps = [
         ":pointer_nullability_matchers",
+        ":type_nullability",
         "@llvm-project//clang:ast_matchers",
         "@llvm-project//clang:testing",
         "@llvm-project//llvm:Support",
diff --git a/nullability/pointer_nullability_matchers.cc b/nullability/pointer_nullability_matchers.cc
index 48fc671..f0c1e39 100644
--- a/nullability/pointer_nullability_matchers.cc
+++ b/nullability/pointer_nullability_matchers.cc
@@ -49,10 +49,10 @@
 using ast_matchers::isInStdNamespace;
 using ast_matchers::isMemberInitializer;
 using ast_matchers::memberExpr;
-using ast_matchers::on;
 using ast_matchers::parameterCountIs;
 using ast_matchers::returnStmt;
 using ast_matchers::statementCountIs;
+using ast_matchers::thisPointerType;
 using ast_matchers::unaryOperator;
 using ast_matchers::unless;
 using ast_matchers::internal::Matcher;
@@ -111,7 +111,7 @@
 }
 
 Matcher<Stmt> isSmartPointerMethodCall(llvm::StringRef Name) {
-  return cxxMemberCallExpr(on(hasType(isSupportedSmartPointer())),
+  return cxxMemberCallExpr(thisPointerType(isSupportedSmartPointer()),
                            callee(cxxMethodDecl(hasName(Name))));
 }
 
@@ -123,7 +123,7 @@
 }
 
 Matcher<Stmt> isSmartPointerBoolConversionCall() {
-  return cxxMemberCallExpr(on(hasType(isSupportedSmartPointer())),
+  return cxxMemberCallExpr(thisPointerType(isSupportedSmartPointer()),
                            callee(cxxConversionDecl()), hasType(booleanType()));
 }
 
diff --git a/nullability/pointer_nullability_matchers_test.cc b/nullability/pointer_nullability_matchers_test.cc
index 77c0717..11f27b8 100644
--- a/nullability/pointer_nullability_matchers_test.cc
+++ b/nullability/pointer_nullability_matchers_test.cc
@@ -4,6 +4,7 @@
 
 #include "nullability/pointer_nullability_matchers.h"
 
+#include "nullability/type_nullability.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Testing/TestAST.h"
 #include "llvm/ADT/StringRef.h"
@@ -12,6 +13,9 @@
 namespace clang::tidy::nullability {
 namespace {
 
+// Static initializer turns on support for smart pointers.
+test::EnableSmartPointers Enable;
+
 using ast_matchers::match;
 
 template <typename MatcherT>
@@ -85,5 +89,65 @@
   EXPECT_FALSE(matches(Input, "void target(){ C().get_nonconst(); }",
                        isZeroParamConstMemberCall()));
 }
+
+TEST(PointerNullabilityTest, MatchSmartPointerMethodCall) {
+  llvm::StringRef Input(R"cc(
+    namespace std {
+    template <class T>
+    struct unique_ptr {
+      T *get() const;
+    };
+    }  // namespace std
+    template <class T>
+    struct MyUniquePtr {
+      T *get() const;
+    };
+  )cc");
+  // Call using `.method()` syntax.
+  EXPECT_TRUE(matches(Input, "void target(){ std::unique_ptr<int>().get(); }",
+                      isSmartPointerMethodCall("get")));
+  // Call using `->method()` syntax.
+  EXPECT_TRUE(matches(Input,
+                      "void target(std::unique_ptr<int> *p) { p->get(); }",
+                      isSmartPointerMethodCall("get")));
+  // Querying for wrong method name.
+  EXPECT_FALSE(matches(Input, "void target(){ std::unique_ptr<int>().get(); }",
+                       isSmartPointerMethodCall("reset")));
+  // Not a supported smart pointer type.
+  EXPECT_FALSE(matches(Input, "void target(){ MyUniquePtr<int>().get(); }",
+                       isSmartPointerMethodCall("get")));
+}
+
+TEST(PointerNullabilityTest, MatchSmartPointerBoolConversionCall) {
+  llvm::StringRef Input(R"cc(
+    namespace std {
+    template <class T>
+    struct unique_ptr {
+      explicit operator bool() const;
+    };
+    }  // namespace std
+    template <class T>
+    struct MyUniquePtr {
+      explicit operator bool() const;
+    };
+  )cc");
+  // Call using `static_cast<bool>()` syntax.
+  EXPECT_TRUE(matches(
+      Input, "void target(){ static_cast<bool>(std::unique_ptr<int>()); }",
+      isSmartPointerBoolConversionCall()));
+  // Explicit call using `.method()` syntax.
+  EXPECT_TRUE(
+      matches(Input, "void target(){ std::unique_ptr<int>().operator bool(); }",
+              isSmartPointerBoolConversionCall()));
+  // Explicit call using `->method()` syntax.
+  EXPECT_TRUE(matches(
+      Input, "void target(std::unique_ptr<int> *p) { p->operator bool(); }",
+      isSmartPointerBoolConversionCall()));
+  // Not a supported smart pointer type.
+  EXPECT_FALSE(
+      matches(Input, "void target(){ static_cast<bool>(MyUniquePtr<int>()); }",
+              isSmartPointerBoolConversionCall()));
+}
+
 }  // namespace
 }  // namespace clang::tidy::nullability
diff --git a/nullability/test/smart_pointers.cc b/nullability/test/smart_pointers.cc
index 1825b28..bed5763 100644
--- a/nullability/test/smart_pointers.cc
+++ b/nullability/test/smart_pointers.cc
@@ -263,11 +263,19 @@
 
   std::unique_ptr<int> p(raw);
   provable(p.get() == raw);
+
+  // Test `->method()` call syntax.
+  provable((&null)->get() == nullptr);
+  provable((&p)->get() == raw);
 }
 
 TEST void operatorBool() {
   provable(!std::unique_ptr<int>());
   provable(static_cast<bool>(std::make_unique<int>()));
+
+  // Test `->method()` call syntax.
+  auto p = std::make_unique<int>();
+  provable((&p)->operator bool());
 }
 
 TEST void makeUnique() {