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/collect_evidence_test.cc b/nullability/inference/collect_evidence_test.cc
index 65fca77..b3a24d6 100644
--- a/nullability/inference/collect_evidence_test.cc
+++ b/nullability/inference/collect_evidence_test.cc
@@ -2435,18 +2435,26 @@
}
TEST(EvidenceSitesTest, GlobalVariables) {
- TestAST AST(R"cc(
+ TestAST AST = getInputsWithAnnotationDefinitions(R"cc(
+#include <memory>
int* x = true ? nullptr : nullptr;
int* y;
int a;
int b = *y;
+ std::unique_ptr<int> p;
+ std::unique_ptr<int> q = nullptr;
)cc");
auto Sites = EvidenceSites::discover(AST.context());
EXPECT_THAT(Sites.Declarations,
- UnorderedElementsAre(declNamed("x"), declNamed("y")));
- EXPECT_THAT(Sites.Definitions,
- UnorderedElementsAre(declNamed("x"), declNamed("b")));
+ UnorderedElementsAre(declNamed("x"), declNamed("y"),
+ declNamed("p"), declNamed("q")));
+ EXPECT_THAT(
+ Sites.Definitions,
+ UnorderedElementsAre(
+ declNamed("x"), declNamed("b"),
+ // unique_ptr p has an initializer because of default construction.
+ declNamed("p"), declNamed("q")));
}
TEST(EvidenceSitesTest, StaticMemberVariables) {
@@ -2471,15 +2479,19 @@
}
TEST(EvidenceSitesTest, NonStaticMemberVariables) {
- TestAST AST(R"cc(
+ TestAST AST = getInputsWithAnnotationDefinitions(R"cc(
+#include <memory>
struct S {
int* a = nullptr;
int* b;
+ std::unique_ptr<int> p = nullptr;
+ std::unique_ptr<int> q;
};
)cc");
auto Sites = EvidenceSites::discover(AST.context());
EXPECT_THAT(Sites.Declarations,
- UnorderedElementsAre(declNamed("S::a"), declNamed("S::b")));
+ UnorderedElementsAre(declNamed("S::a"), declNamed("S::b"),
+ declNamed("S::p"), declNamed("S::q")));
EXPECT_THAT(Sites.Definitions, IsEmpty());
}
diff --git a/nullability/inference/eligible_ranges_test.cc b/nullability/inference/eligible_ranges_test.cc
index acff441..f878f11 100644
--- a/nullability/inference/eligible_ranges_test.cc
+++ b/nullability/inference/eligible_ranges_test.cc
@@ -235,17 +235,15 @@
)");
EXPECT_THAT(getFunctionRanges(Input.code()),
Optional(TypeLocRanges(
- MainFileName, UnorderedElementsAre(
- SlotRange(1, Input.range("one_o")),
- SlotRange(-1, Input.range("one_i")),
- // TODO(b/330702908) When supported, Slot 2.
- SlotRange(-1, Input.range("two_o")),
- SlotRange(-1, Input.range("two_i")),
- SlotRange(3, Input.range("three_o")),
- SlotRange(-1, Input.range("three_i")),
- // TODO(b/330702908) When supported, Slot 4.
- SlotRange(-1, Input.range("four_o")),
- SlotRange(-1, Input.range("four_i"))))));
+ MainFileName,
+ UnorderedElementsAre(SlotRange(1, Input.range("one_o")),
+ SlotRange(-1, Input.range("one_i")),
+ SlotRange(2, Input.range("two_o")),
+ SlotRange(-1, Input.range("two_i")),
+ SlotRange(3, Input.range("three_o")),
+ SlotRange(-1, Input.range("three_i")),
+ SlotRange(4, Input.range("four_o")),
+ SlotRange(-1, Input.range("four_i"))))));
}
TEST(EligibleRangesTest, NestedPointersInnerAnnotated) {
@@ -263,17 +261,15 @@
)");
EXPECT_THAT(getFunctionRanges(Input.code()),
Optional(TypeLocRanges(
- MainFileName, UnorderedElementsAre(
- SlotRange(1, Input.range("one_o")),
- SlotRange(-1, Input.range("one_i")),
- // TODO(b/330702908) When supported, Slot 2.
- SlotRange(-1, Input.range("two_o")),
- SlotRange(-1, Input.range("two_i")),
- SlotRange(3, Input.range("three_o")),
- SlotRange(-1, Input.range("three_i")),
- // TODO(b/330702908) When supported, Slot 4.
- SlotRange(-1, Input.range("four_o")),
- SlotRange(-1, Input.range("four_i"))))));
+ MainFileName,
+ UnorderedElementsAre(SlotRange(1, Input.range("one_o")),
+ SlotRange(-1, Input.range("one_i")),
+ SlotRange(2, Input.range("two_o")),
+ SlotRange(-1, Input.range("two_i")),
+ SlotRange(3, Input.range("three_o")),
+ SlotRange(-1, Input.range("three_i")),
+ SlotRange(4, Input.range("four_o")),
+ SlotRange(-1, Input.range("four_i"))))));
}
TEST(EligibleRangesTest, RefToPointer) {
@@ -329,13 +325,11 @@
void foo($one[[std::unique_ptr<int>]] std_smart,
Nonnull<$two[[std::unique_ptr<int>]]> nonnull_std_smart);
)");
- EXPECT_THAT(
- getFunctionRanges(Input.code()),
- Optional(TypeLocRanges(
- MainFileName, UnorderedElementsAre(
- // TODO(b/330702908) When supported, Slots 1 and 2.
- SlotRange(-1, Input.range("one")),
- SlotRange(-1, Input.range("two"))))));
+ EXPECT_THAT(getFunctionRanges(Input.code()),
+ Optional(TypeLocRanges(
+ MainFileName,
+ UnorderedElementsAre(SlotRange(1, Input.range("one")),
+ SlotRange(2, Input.range("two"))))));
}
TEST(EligibleRangesTest, UserDefinedSmartPointer) {
@@ -348,13 +342,11 @@
void foo($one[[MySmartIntPtr]] user_defined_smart,
Nonnull<$two[[MySmartIntPtr]]> nonnull_user_defined_smart);
)");
- EXPECT_THAT(
- getFunctionRanges(Input.code()),
- Optional(TypeLocRanges(
- MainFileName, UnorderedElementsAre(
- // TODO(b/330702908) When supported, Slots 1 and 2.
- SlotRange(-1, Input.range("one")),
- SlotRange(-1, Input.range("two"))))));
+ EXPECT_THAT(getFunctionRanges(Input.code()),
+ Optional(TypeLocRanges(
+ MainFileName,
+ UnorderedElementsAre(SlotRange(1, Input.range("one")),
+ SlotRange(2, Input.range("two"))))));
}
TEST(EligibleRangesTest, UserDefinedTemplatedSmartPointer) {
@@ -367,13 +359,11 @@
void foo($one[[MySmartPtr<int>]] user_defined_smart,
Nonnull<$two[[MySmartPtr<int>]]> nonnull_user_defined_smart);
)");
- EXPECT_THAT(
- getFunctionRanges(Input.code()),
- Optional(TypeLocRanges(
- MainFileName, UnorderedElementsAre(
- // TODO(b/330702908) When supported, Slots 1 and 2.
- SlotRange(-1, Input.range("one")),
- SlotRange(-1, Input.range("two"))))));
+ EXPECT_THAT(getFunctionRanges(Input.code()),
+ Optional(TypeLocRanges(
+ MainFileName,
+ UnorderedElementsAre(SlotRange(1, Input.range("one")),
+ SlotRange(2, Input.range("two"))))));
}
TEST(EligibleRangesTest, SimpleAlias) {
@@ -643,7 +633,7 @@
EXPECT_THAT(getFunctionRanges(Input.code()),
Optional(TypeLocRanges(
MainFileName,
- UnorderedElementsAre(SlotRange(-1, Input.range("unique_ptr")),
+ UnorderedElementsAre(SlotRange(1, Input.range("unique_ptr")),
SlotRange(-1, Input.range("inner"))))));
}
diff --git a/nullability/inference/infer_tu_test.cc b/nullability/inference/infer_tu_test.cc
index 0a11b3f..6c14260 100644
--- a/nullability/inference/infer_tu_test.cc
+++ b/nullability/inference/infer_tu_test.cc
@@ -522,8 +522,8 @@
)cc");
// TODO(b/304963199): Currently not inferring anything because we don't
- // support smart pointers. The expected result is the same as for the
- // `ParamsFromCallSite` test.
+ // collect evidence for smart pointers. The expected result is the same as for
+ // the `ParamsFromCallSite` test.
ASSERT_THAT(infer(), IsEmpty());
}
@@ -533,7 +533,8 @@
std::unique_ptr<int> target() { return std::unique_ptr<int>(); }
)cc");
// TODO(b/304963199): Currently not inferring anything because we don't
- // support smart pointers. The expected result is a nullable return type.
+ // collect evidence for smart pointers. The expected result is a nullable
+ // return type.
EXPECT_THAT(infer(), IsEmpty());
}
@@ -543,7 +544,8 @@
std::unique_ptr<int> target() { return std::make_unique<int>(0); }
)cc");
// TODO(b/304963199): Currently not inferring anything because we don't
- // support smart pointers. The expected result is a nonnull return type.
+ // collect evidence for smart pointers. The expected result is a nonnull
+ // return type.
EXPECT_THAT(infer(), IsEmpty());
}
diff --git a/nullability/inference/inferable.cc b/nullability/inference/inferable.cc
index ea85898..a9ac46e 100644
--- a/nullability/inference/inferable.cc
+++ b/nullability/inference/inferable.cc
@@ -15,7 +15,7 @@
namespace clang::tidy::nullability {
bool hasInferable(QualType T) {
- return isSupportedRawPointerType(T.getNonReferenceType());
+ return isSupportedPointerType(T.getNonReferenceType());
}
int countInferableSlots(const Decl& D) {
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)));