2727@ CheckReturnValue
2828public final class CelNavigableExprUtil {
2929
30+ /**
31+ * Returns the nearest enclosing comprehension that declares {@code variableName} in scope for
32+ * {@code expr}, or {@code Optional.empty()} if none exists.
33+ *
34+ * <p>A comprehension declares {@code variableName} in scope for {@code expr} if {@code
35+ * variableName} matches {@code iterVar}, {@code iterVar2}, or {@code accuVar}, and {@code expr}
36+ * resides within the branch where that variable is active:
37+ *
38+ * <ul>
39+ * <li>In {@code loopCondition} and {@code loopStep}: {@code iterVar}, {@code iterVar2}, and
40+ * {@code accuVar} are in scope.
41+ * <li>In {@code result}: only {@code accuVar} is in scope.
42+ * <li>In {@code iterRange} and {@code accuInit}: none of the comprehension variables are in
43+ * scope.
44+ * </ul>
45+ */
46+ @ SuppressWarnings ("ReferenceEquality" ) // Required to disambiguate child branches
47+ public static <E extends Expression , T extends BaseNavigableExpr <E >>
48+ Optional <T > findDeclaringComprehension (T expr , String variableName ) {
49+ checkNotNull (expr );
50+ checkNotNull (variableName );
51+ if (variableName .isEmpty ()) {
52+ return Optional .empty ();
53+ }
54+ T curr = expr ;
55+ Optional <T > maybeParent = curr .parent ();
56+ while (maybeParent .isPresent ()) {
57+ T parent = maybeParent .get ();
58+ if (parent .getKind () == Kind .COMPREHENSION ) {
59+ Expression .Comprehension <?> comp = parent .expr ().comprehension ();
60+ Expression currExpr = curr .expr ();
61+
62+ if (currExpr != comp .iterRange () && currExpr != comp .accuInit ()) {
63+ if (currExpr == comp .result ()) {
64+ if (comp .accuVar ().equals (variableName )) {
65+ return Optional .of (parent );
66+ }
67+ } else {
68+ if (comp .iterVar ().equals (variableName )
69+ || comp .iterVar2 ().equals (variableName )
70+ || comp .accuVar ().equals (variableName )) {
71+ return Optional .of (parent );
72+ }
73+ }
74+ }
75+ }
76+ curr = parent ;
77+ maybeParent = parent .parent ();
78+ }
79+ return Optional .empty ();
80+ }
81+
3082 /**
3183 * Returns true if {@code variableName} is in scope and shadowed by an enclosing comprehension
3284 * above {@code expr}.
@@ -56,7 +108,7 @@ public final class CelNavigableExprUtil {
56108 * </ul>
57109 */
58110 public static boolean isVariableShadowed (BaseNavigableExpr <?> expr , String variableName ) {
59- return areVariablesShadowed (expr , Collections . singleton ( variableName ));
111+ return findDeclaringComprehension (expr , variableName ). isPresent ( );
60112 }
61113
62114 /**
@@ -72,38 +124,14 @@ public static boolean isVariableShadowed(BaseNavigableExpr<?> expr, String varia
72124 * At {@code y > 0}, {@code areVariablesShadowed(node, ImmutableSet.of("x", "z"))} is {@code true}
73125 * because {@code x} is in scope from the outer comprehension.
74126 */
75- @ SuppressWarnings ("ReferenceEquality" ) // Required to disambiguate child branches
76127 public static boolean areVariablesShadowed (
77128 BaseNavigableExpr <?> expr , Collection <String > variableNames ) {
78129 checkNotNull (expr );
79130 checkNotNull (variableNames );
80- if (variableNames .isEmpty ()) {
81- return false ;
82- }
83- BaseNavigableExpr <?> curr = expr ;
84- Optional <? extends BaseNavigableExpr <?>> maybeParent = curr .parent ();
85- while (maybeParent .isPresent ()) {
86- BaseNavigableExpr <?> parent = maybeParent .get ();
87- if (parent .getKind () == Kind .COMPREHENSION ) {
88- Expression .Comprehension <?> comp = parent .expr ().comprehension ();
89- Expression currExpr = curr .expr ();
90-
91- if (currExpr != comp .iterRange () && currExpr != comp .accuInit ()) {
92- if (currExpr == comp .result ()) {
93- if (variableNames .contains (comp .accuVar ())) {
94- return true ;
95- }
96- } else {
97- if (variableNames .contains (comp .iterVar ())
98- || variableNames .contains (comp .iterVar2 ())
99- || variableNames .contains (comp .accuVar ())) {
100- return true ;
101- }
102- }
103- }
131+ for (String varName : variableNames ) {
132+ if (findDeclaringComprehension (expr , varName ).isPresent ()) {
133+ return true ;
104134 }
105- curr = parent ;
106- maybeParent = parent .parent ();
107135 }
108136 return false ;
109137 }
0 commit comments