Consider smart pointers inferable, though we collect no evidence for them yet.
This changes the pipeline behavior when using kUnknownExplicit; all unannotated smart pointers will now be considered eligible for an annotation, and in kUnknownExplicit mode, will be annotated Unknown.
PiperOrigin-RevId: 634753587
Change-Id: Ic804bc7930a399bc0bcdbf219cb376f81730a118
diff --git a/nullability/inference/inferable_test.cc b/nullability/inference/inferable_test.cc
index 0b08e50..4650c66 100644
--- a/nullability/inference/inferable_test.cc
+++ b/nullability/inference/inferable_test.cc
@@ -51,45 +51,74 @@
return *Match;
}
+constexpr llvm::StringRef SmartPointerHeader = R"cc(
+ namespace std {
+ template <typename T>
+ struct unique_ptr {
+ using pointer = T*;
+ };
+ } // namespace std
+
+ template <typename T>
+ struct custom_smart_ptr {
+ using absl_nullability_compatible = void;
+ using pointer = T*;
+ };
+)cc";
+
TEST(IsInferenceTargetTest, GlobalVariables) {
- TestAST AST(R"cc(
- int* Pointer;
- int NotPointer;
- )cc");
+ TestAST AST((SmartPointerHeader + R"cc(
+ int* Pointer;
+ std::unique_ptr<int> StdSmartPointer;
+ custom_smart_ptr<int> CustomSmartPointer;
+ int NotPointer;
+ )cc")
+ .str());
auto &Ctx = AST.context();
EXPECT_TRUE(isInferenceTarget(lookup("Pointer", Ctx)));
+ EXPECT_TRUE(isInferenceTarget(lookup("StdSmartPointer", Ctx)));
+ EXPECT_TRUE(isInferenceTarget(lookup("CustomSmartPointer", Ctx)));
EXPECT_FALSE(isInferenceTarget(lookup("NotPointer", Ctx)));
}
TEST(IsInferenceTargetTest, Functions) {
- TestAST AST(R"cc(
- int* func(int*, int**) {
- int* Local;
- static int* StaticLocal;
- }
- void empty() {}
- auto Lambda = []() {};
- )cc");
+ TestAST AST((SmartPointerHeader + R"cc(
+ int* func(int*, int**, std::unique_ptr<int>,
+ custom_smart_ptr<int>) {
+ int* Local;
+ static int* StaticLocal;
+ std::unique_ptr<int> StdSmartLocal;
+ custom_smart_ptr<int> CustomSmartLocal;
+ }
+ void empty() {}
+ auto Lambda = []() {};
+ )cc")
+ .str());
auto &Ctx = AST.context();
EXPECT_TRUE(isInferenceTarget(lookup("func", Ctx)));
EXPECT_FALSE(isInferenceTarget(lookup("Local", Ctx)));
EXPECT_FALSE(isInferenceTarget(lookup("StaticLocal", Ctx)));
+ EXPECT_FALSE(isInferenceTarget(lookup("StdSmartLocal", Ctx)));
+ EXPECT_FALSE(isInferenceTarget(lookup("CustomSmartLocal", Ctx)));
EXPECT_TRUE(isInferenceTarget(lookup("empty", Ctx)));
EXPECT_FALSE(isInferenceTarget(lookup("Lambda", Ctx)));
EXPECT_FALSE(isInferenceTarget(lookup("operator()", Ctx)));
}
TEST(IsInferenceTargetTest, ClassAndMembers) {
- TestAST AST(R"cc(
- class C {
- void method();
- int NonPtrField;
- int* PtrField;
- static int* StaticField;
- };
- )cc");
+ TestAST AST((SmartPointerHeader + R"cc(
+ class C {
+ void method();
+ int NonPtrField;
+ int* PtrField;
+ static int* StaticField;
+ std::unique_ptr<int> StdSmartField;
+ custom_smart_ptr<int> CustomSmartField;
+ };
+ )cc")
+ .str());
auto &Ctx = AST.context();
EXPECT_FALSE(isInferenceTarget(lookup<CXXRecordDecl>("C", Ctx)));
@@ -97,6 +126,8 @@
EXPECT_FALSE(isInferenceTarget(lookup("NonPtrField", Ctx)));
EXPECT_TRUE(isInferenceTarget(lookup("PtrField", Ctx)));
EXPECT_TRUE(isInferenceTarget(lookup("StaticField", Ctx)));
+ EXPECT_TRUE(isInferenceTarget(lookup("StdSmartField", Ctx)));
+ EXPECT_TRUE(isInferenceTarget(lookup("CustomSmartField", Ctx)));
}
TEST(IsInferenceTargetTest, FunctionTemplate) {
@@ -164,26 +195,31 @@
}
TEST(InferableTest, CountInferableSlots) {
- TestAST AST(R"cc(
- using Pointer = int *;
- template <class T>
- struct S;
- struct T;
+ TestAST AST((SmartPointerHeader + R"cc(
+ using Pointer = int *;
+ template <class T>
+ struct S;
+ struct T;
- void f1(int *);
- void f2(Pointer);
- void f3(int **);
- void f4(Pointer *);
- void f5(int *&);
- void f6(int (*)()); // function pointer
+ void f1(int *);
+ void f2(Pointer);
+ void f3(int **);
+ void f4(Pointer *);
+ void f5(int *&);
+ void f6(int (*)()); // function pointer
+ void f7(std::unique_ptr<int>);
+ void f8(custom_smart_ptr<int>);
- int *g1(int);
- Pointer g2(int);
+ int *g1(int);
+ Pointer g2(int);
+ std::unique_ptr<int> g3(int);
+ custom_smart_ptr<int> g4(int);
- void h1(S<int *>);
- void h2(int T::*); // pointer to data member
- void h3(int (T::*)()); // pointer to member function
- )cc");
+ void h1(S<int *>);
+ void h2(int T::*); // pointer to data member
+ void h3(int (T::*)()); // pointer to member function
+ )cc")
+ .str());
auto &Ctx = AST.context();
// All the 'f's have a single pointer arg.
@@ -193,10 +229,14 @@
EXPECT_EQ(1, countInferableSlots(lookup("f4", Ctx)));
EXPECT_EQ(1, countInferableSlots(lookup("f5", Ctx)));
EXPECT_EQ(1, countInferableSlots(lookup("f6", Ctx)));
+ EXPECT_EQ(1, countInferableSlots(lookup("f7", Ctx)));
+ EXPECT_EQ(1, countInferableSlots(lookup("f8", Ctx)));
// All the 'g's have a pointer return.
EXPECT_EQ(1, countInferableSlots(lookup("g1", Ctx)));
EXPECT_EQ(1, countInferableSlots(lookup("g2", Ctx)));
+ EXPECT_EQ(1, countInferableSlots(lookup("g3", Ctx)));
+ EXPECT_EQ(1, countInferableSlots(lookup("g4", Ctx)));
// The 'h's have types that aren't really pointers.
EXPECT_EQ(0, countInferableSlots(lookup("h1", Ctx)));