Mark non-conflicting inferences made from existing annotations as trivial.
PiperOrigin-RevId: 570048944
Change-Id: Id2b75fbdc339512d8f3015520a5d1c5662976889
diff --git a/nullability/inference/BUILD b/nullability/inference/BUILD
index 93716e7..4773f6e 100644
--- a/nullability/inference/BUILD
+++ b/nullability/inference/BUILD
@@ -135,7 +135,6 @@
name = "infer_tu_main",
srcs = ["infer_tu_main.cc"],
deps = [
- ":collect_evidence",
":infer_tu",
":inference_cc_proto",
"@absl//absl/log:check",
diff --git a/nullability/inference/infer_tu_main.cc b/nullability/inference/infer_tu_main.cc
index 6591fe1..6ed1639 100644
--- a/nullability/inference/infer_tu_main.cc
+++ b/nullability/inference/infer_tu_main.cc
@@ -15,7 +15,6 @@
#include <utility>
#include "absl/log/check.h"
-#include "nullability/inference/collect_evidence.h"
#include "nullability/inference/infer_tu.h"
#include "nullability/inference/inference.proto.h"
#include "clang/AST/ASTConsumer.h"
@@ -134,15 +133,6 @@
}
};
-bool isTrivial(const Inference::SlotInference &I) {
- if (I.conflict()) return false;
- for (const auto &E : I.sample_evidence())
- if (E.kind() == Evidence::ANNOTATED_NONNULL ||
- E.kind() == Evidence::ANNOTATED_NULLABLE)
- return true;
- return false;
-}
-
// Selects which declarations to analyze based on filter flags.
struct DeclFilter {
bool operator()(const Decl &D) const {
@@ -199,7 +189,9 @@
auto Results = inferTU(Ctx, DeclFilter());
if (!IncludeTrivial)
llvm::erase_if(Results, [](Inference &I) {
- llvm::erase_if(*I.mutable_slot_inference(), isTrivial);
+ llvm::erase_if(
+ *I.mutable_slot_inference(),
+ [](const Inference::SlotInference &S) { return S.trivial(); });
return I.slot_inference_size() == 0;
});
if (PrintProtos)
diff --git a/nullability/inference/inference.proto b/nullability/inference/inference.proto
index b11fc5e..f096210 100644
--- a/nullability/inference/inference.proto
+++ b/nullability/inference/inference.proto
@@ -90,6 +90,11 @@
optional bool conflict = 3;
// Examples of evidence that contributed. Optional, for debugging only.
repeated Evidence sample_evidence = 4;
+ // Indicates that this inference does not represent new information beyond
+ // what is explicitly written in the source code, and so does not need to be
+ // separately propagated from one round of inference into the next.
+ // e.g. an inference gathered from ANNOTATED_NONNULL Evidence.
+ optional bool trivial = 5;
}
enum Nullability {
diff --git a/nullability/inference/merge.cc b/nullability/inference/merge.cc
index 52ddae4..5f60a54 100644
--- a/nullability/inference/merge.cc
+++ b/nullability/inference/merge.cc
@@ -85,6 +85,7 @@
auto Result = infer(KindCounts);
Slot.set_nullability(Result.Nullability);
if (Result.Conflict) Slot.set_conflict(true);
+ if (Result.Trivial) Slot.set_trivial(true);
}
return Result;
}
@@ -111,8 +112,10 @@
Counts[Evidence::ANNOTATED_NULLABLE]) {
return {Inference::UNKNOWN, /*Conflict=*/true};
}
- if (Counts[Evidence::ANNOTATED_NONNULL]) return {Inference::NONNULL};
- if (Counts[Evidence::ANNOTATED_NULLABLE]) return {Inference::NULLABLE};
+ if (Counts[Evidence::ANNOTATED_NONNULL])
+ return {Inference::NONNULL, /*Conflict=*/false, /*Trivial=*/true};
+ if (Counts[Evidence::ANNOTATED_NULLABLE])
+ return {Inference::NULLABLE, /*Conflict=*/false, /*Trivial=*/true};
// Mandatory inference rules, required by type-checking.
// Ordered from most confident to least.
diff --git a/nullability/inference/merge.h b/nullability/inference/merge.h
index e4e606d..7dc028b 100644
--- a/nullability/inference/merge.h
+++ b/nullability/inference/merge.h
@@ -32,6 +32,7 @@
struct InferResult {
Inference::Nullability Nullability;
bool Conflict = false;
+ bool Trivial = false;
};
// Final inference decisions, based on event counts.
// TODO: once this interface sticks, move to a dedicated file.
diff --git a/nullability/inference/merge_test.cc b/nullability/inference/merge_test.cc
index 69ce865..c3a5ad2 100644
--- a/nullability/inference/merge_test.cc
+++ b/nullability/inference/merge_test.cc
@@ -109,6 +109,7 @@
kind_count { key: 3 value: 1 } # UNCHECKED_DEREFERENCE
}
slot { kind_count { key: 0 value: 1 } } # ANNOTATED_UNKNOWN
+ slot { kind_count { key: 1 value: 1 } } # ANNOTATED_NULLABLE
)pb")),
EqualsProto(R"pb(
symbol { usr: "func" }
@@ -121,6 +122,7 @@
}
slot_inference { slot: 2 nullability: NONNULL }
slot_inference { slot: 3 nullability: UNKNOWN }
+ slot_inference { slot: 4 nullability: NULLABLE trivial: true }
)pb"));
}
@@ -142,7 +144,7 @@
symbol {}
slot_inference { slot: 0 nullability: UNKNOWN conflict: true }
slot_inference { slot: 2 nullability: NONNULL }
- slot_inference { slot: 4 nullability: NULLABLE }
+ slot_inference { slot: 4 nullability: NULLABLE trivial: true }
)pb");
EXPECT_THAT(
@@ -183,9 +185,11 @@
protected:
void add(Evidence::Kind E, int N = 1) { Counts[E] += N; }
- Inference::Nullability infer(bool ExpectConflict = false) {
+ Inference::Nullability infer(bool ExpectConflict = false,
+ bool ExpectTrivial = false) {
auto Result = nullability::infer(Counts);
EXPECT_EQ(ExpectConflict, Result.Conflict);
+ EXPECT_EQ(ExpectTrivial, Result.Trivial);
return Result.Nullability;
}
};
@@ -194,9 +198,11 @@
TEST_F(InferTest, Annotated) {
add(Evidence::ANNOTATED_NULLABLE);
- EXPECT_EQ(Inference::NULLABLE, infer());
+ EXPECT_EQ(Inference::NULLABLE,
+ infer(/*ExpectConflict=*/false, /*ExpectTrivial=*/true));
add(Evidence::UNCHECKED_DEREFERENCE); // No conflict, annotation wins.
- EXPECT_EQ(Inference::NULLABLE, infer());
+ EXPECT_EQ(Inference::NULLABLE,
+ infer(/*ExpectConflict=*/false, /*ExpectTrivial=*/true));
add(Evidence::ANNOTATED_NONNULL); // Conflicting annotations!
EXPECT_EQ(Inference::UNKNOWN, infer(/*ExpectConflict=*/true));
}