Mark ranges for nested pointers using `auto`, not just top-level.

PiperOrigin-RevId: 671745910
Change-Id: I40a787347f1006017ec0558d8b636233027fcedc
diff --git a/nullability/inference/eligible_ranges.cc b/nullability/inference/eligible_ranges.cc
index ac407f2..86545d6 100644
--- a/nullability/inference/eligible_ranges.cc
+++ b/nullability/inference/eligible_ranges.cc
@@ -415,9 +415,15 @@
       }
     }
 
-    if (auto PTL = MaybeLoc->getAsAdjusted<PointerTypeLoc>();
-        PTL && PTL.getPointeeLoc().getAs<AutoTypeLoc>()) {
-      Range->set_is_auto_star(true);
+    auto PTL = MaybeLoc->getAsAdjusted<PointerTypeLoc>();
+    if (PTL) {
+      while (auto PointeeTL =
+                 PTL.getPointeeLoc().getAsAdjusted<PointerTypeLoc>()) {
+        PTL = PointeeTL;
+      }
+      if (PTL.getPointeeLoc().getAs<AutoTypeLoc>()) {
+        Range->set_contains_auto_star(true);
+      }
     }
   }
 }
diff --git a/nullability/inference/eligible_ranges_test.cc b/nullability/inference/eligible_ranges_test.cc
index 8f56658..927f19c 100644
--- a/nullability/inference/eligible_ranges_test.cc
+++ b/nullability/inference/eligible_ranges_test.cc
@@ -891,7 +891,7 @@
 }
 
 MATCHER_P2(AutoSlotRangeWithNoExistingAnnotation, SlotID, Range, "") {
-  return arg.is_auto_star() && !arg.has_existing_annotation() &&
+  return arg.contains_auto_star() && !arg.has_existing_annotation() &&
          ExplainMatchResult(SlotRange(SlotID, Range), arg, result_listener);
 }
 
@@ -900,7 +900,7 @@
                         " and range equivalent to [", Range.Begin, ",",
                         Range.End, ") and existing annotation ",
                         ExistingAnnotation)) {
-  return arg.is_auto_star() &&
+  return arg.contains_auto_star() &&
          ExplainMatchResult(SlotRange(SlotID, Range, ExistingAnnotation), arg,
                             result_listener);
 }
@@ -915,6 +915,7 @@
     int* getPtr();
     $var_auto[[auto*]] g_star = getPtr();
     $var_auto_attributed[[auto*]] _Nullable g_star_nullable = getPtr();
+    $var_auto_star_star[[$var_auto_star_inner[[auto*]]*]] g_star_star = &g_star;
     )");
   EXPECT_THAT(getFunctionRanges(Input.code(), "star"),
               Optional(TypeLocRangesWithNoPragmaNullability(
@@ -925,7 +926,7 @@
                                               1, Input.range("func_not_auto")),
                                           ResultOf(
                                               [](const class SlotRange& SR) {
-                                                return SR.is_auto_star();
+                                                return SR.contains_auto_star();
                                               },
                                               testing::IsFalse()))))));
   EXPECT_THAT(getVarRanges(Input.code(), "g_star"),
@@ -938,6 +939,14 @@
                   MainFileName, UnorderedElementsAre(AutoSlotRange(
                                     0, Input.range("var_auto_attributed"),
                                     Nullability::NULLABLE)))));
+  EXPECT_THAT(
+      getVarRanges(Input.code(), "g_star_star"),
+      Optional(TypeLocRangesWithNoPragmaNullability(
+          MainFileName,
+          UnorderedElementsAre(AutoSlotRangeWithNoExistingAnnotation(
+                                   0, Input.range("var_auto_star_star")),
+                               AutoSlotRangeWithNoExistingAnnotation(
+                                   -1, Input.range("var_auto_star_inner"))))));
 }
 
 MATCHER(NoPreRangeLength, "") {
diff --git a/nullability/inference/inference.proto b/nullability/inference/inference.proto
index 3aa6e14..dd6c9d7 100644
--- a/nullability/inference/inference.proto
+++ b/nullability/inference/inference.proto
@@ -202,7 +202,7 @@
 
   optional ComplexDeclaratorRanges complex_declarator_ranges = 7;
 
-  optional bool is_auto_star = 8;
+  optional bool contains_auto_star = 8;
 }
 
 // A set of slot ranges and their associated file.