Add more tests of evidence collection that already pass.
Modeled after the scenarios in the function_calls verification test suite.
PiperOrigin-RevId: 580890041
Change-Id: I179259469ce3955bc7ffb96d78538fc5eba5765d
diff --git a/nullability/inference/collect_evidence_test.cc b/nullability/inference/collect_evidence_test.cc
index bf2696a..fd5b285 100644
--- a/nullability/inference/collect_evidence_test.cc
+++ b/nullability/inference/collect_evidence_test.cc
@@ -583,6 +583,142 @@
EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
}
+TEST(CollectEvidenceFromImplementationTest, FunctionCallInLoop) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void target(int* p) {
+ for (int i = 0; i < 3; ++i) {
+ target(nullptr);
+ }
+ for (int i = 0; i < 3; ++i) {
+ target(&i);
+ }
+ for (int i = 0; i < 3; ++i) {
+ target(p);
+ }
+ }
+ )cc";
+ EXPECT_THAT(
+ collectEvidenceFromTargetFunction(Src),
+ UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
+ functionNamed("target")),
+ evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT,
+ functionNamed("target")),
+ evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT,
+ functionNamed("target"))));
+}
+
+TEST(CollectEvidenceFromImplementationTest, OutputParameterPointerToPointer) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void maybeModifyPtr(int** a);
+ void target(int* p) {
+ maybeModifyPtr(&p);
+ *p;
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Not(Contains(evidence(_, _, functionNamed("target")))));
+}
+
+TEST(CollectEvidenceFromImplementationTest, OutputParameterReferenceToPointer) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void maybeModifyPtr(int*& a);
+ void target(int* p) {
+ maybeModifyPtr(p);
+ *p;
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Not(Contains(evidence(_, _, functionNamed("target")))));
+}
+
+TEST(CollectEvidenceFromImplementationTest,
+ OutputParameterReferenceToConstPointer) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void dontModifyPtr(int* const& a);
+ void target(int* p) {
+ dontModifyPtr(p);
+ *p;
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE,
+ functionNamed("target"))));
+}
+
+TEST(CollectEvidenceFromImplementationTest,
+ OutputParameterReferenceToPointerToPointer) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void maybeModifyPtr(int**& a);
+ void target(int** p) {
+ maybeModifyPtr(p);
+ *p;
+ **p;
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Not(Contains(evidence(_, _, functionNamed("target")))));
+}
+
+TEST(CollectEvidenceFromImplementationTest,
+ OutputParameterPointerToConstPointer) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void dontModifyPtr(int* const* a);
+ void target(int* p) {
+ dontModifyPtr(&p);
+ *p;
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE,
+ functionNamed("target"))));
+}
+
+TEST(CollectEvidenceFromImplementationTest,
+ OutputParameterConstPointerToPointerToConst) {
+ static constexpr llvm::StringRef Src = R"cc(
+ // Outer pointer and int are const, but inner pointer can still be modified.
+ void maybeModifyPtr(const int** const a);
+ void target(const int* p) {
+ maybeModifyPtr(&p);
+ *p;
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Not(Contains(evidence(_, _, functionNamed("target")))));
+}
+
+TEST(CollectEvidenceFromImplementationTest,
+ PassAsOutputParameterOrDereference) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void maybeModifyPtr(int** a);
+ void target(int* p, bool b) {
+ if (b) {
+ maybeModifyPtr(&p);
+ } else {
+ *p;
+ }
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE,
+ functionNamed("target"))));
+}
+
+TEST(CollectEvidenceFromImplementationTest,
+ ConditionallyPassAsOutputParameterAlwaysDereference) {
+ static constexpr llvm::StringRef Src = R"cc(
+ void maybeModifyPtr(int** a);
+ void target(int* p, bool b) {
+ if (b) maybeModifyPtr(&p);
+ *p; // Because we model p as Unknown post-output-parameter-use, adding an
+ // annotation would not be considered sufficient to make this
+ // dereference safe, so we do not collect evidence for p.
+ }
+ )cc";
+ EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
+ Not(Contains(evidence(_, _, functionNamed("target")))));
+}
+
TEST(CollectEvidenceFromImplementationTest, NotInferenceTarget) {
static constexpr llvm::StringRef Src = R"cc(
void isATarget(Nonnull<int*> a);