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));
 }