[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() {