@@ -42,7 +42,14 @@ class AssignedVariables<Statement, Variable> {
4242}
4343
4444class FlowAnalysis <Statement , Expression , Variable , Type > {
45+ static bool get _assertionsEnabled {
46+ bool result = false ;
47+ assert (result = true );
48+ return result;
49+ }
50+
4551 final _VariableSet <Variable > _emptySet;
52+
4653 final State <Variable , Type > _identity;
4754
4855 /// The [NodeOperations] , used to manipulate expressions.
@@ -63,8 +70,8 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
6370 /// states.
6471 final Map <Statement , int > _statementToStackIndex = {};
6572
66- /// The list of all variables.
67- final List <Variable > _variables = [];
73+ /// List of all variables passed to [add] .
74+ final List <Variable > _addedVariables = [];
6875
6976 State <Variable , Type > _current;
7077
@@ -77,6 +84,19 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
7784 /// The state when [_condition] evaluates to `false` .
7885 State <Variable , Type > _conditionFalse;
7986
87+ /// If assertions are enabled, keeps track of all variables that have been
88+ /// passed into the API (other than through a call to [add] ). The [finish]
89+ /// method uses this to verify that the caller doesn't forget to pass a
90+ /// variable to [add] .
91+ ///
92+ /// Note: the reason we have to keep track of this set (rather than simply
93+ /// checking each variable at the time it is passed into the API) is because
94+ /// the client doesn't call `add` until a variable is declared, and in
95+ /// erroneous code, it's possible that a variable might be used before its
96+ /// declaration.
97+ final Set <Variable > _referencedVariables =
98+ _assertionsEnabled ? < Variable > {} : null ;
99+
80100 factory FlowAnalysis (
81101 NodeOperations <Expression > nodeOperations,
82102 TypeOperations <Variable , Type > typeOperations,
@@ -108,7 +128,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
108128
109129 /// Add a new [variable] , which might be already [assigned] .
110130 void add (Variable variable, {bool assigned: false }) {
111- _variables .add (variable);
131+ _addedVariables .add (variable);
112132 _current = _current.add (variable, assigned: assigned);
113133 }
114134
@@ -174,6 +194,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
174194
175195 /// The [binaryExpression] checks that the [variable] is equal to `null` .
176196 void conditionEqNull (Expression binaryExpression, Variable variable) {
197+ _variableReferenced (variable);
177198 if (functionBody.isPotentiallyMutatedInClosure (variable)) {
178199 return ;
179200 }
@@ -185,6 +206,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
185206
186207 /// The [binaryExpression] checks that the [variable] is not equal to `null` .
187208 void conditionNotEqNull (Expression binaryExpression, Variable variable) {
209+ _variableReferenced (variable);
188210 if (functionBody.isPotentiallyMutatedInClosure (variable)) {
189211 return ;
190212 }
@@ -196,6 +218,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
196218
197219 void doStatement_bodyBegin (
198220 Statement doStatement, Set <Variable > loopAssigned) {
221+ _variablesReferenced (loopAssigned);
199222 _current = _current.removePromotedAll (loopAssigned);
200223
201224 _statementToStackIndex[doStatement] = _stack.length;
@@ -221,7 +244,21 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
221244 _current = _join (falseCondition, breakState);
222245 }
223246
247+ /// This method should be called at the conclusion of flow analysis for a top
248+ /// level function or method. Performs assertion checks.
249+ void finish () {
250+ assert (_stack.isEmpty);
251+ assert (() {
252+ var variablesNotAdded =
253+ _referencedVariables.difference (Set <Variable >.from (_addedVariables));
254+ assert (variablesNotAdded.isEmpty,
255+ 'Variables not passed to add: $variablesNotAdded ' );
256+ return true ;
257+ }());
258+ }
259+
224260 void forEachStatement_bodyBegin (Set <Variable > loopAssigned) {
261+ _variablesReferenced (loopAssigned);
225262 _stack.add (_current);
226263 _current = _current.removePromotedAll (loopAssigned);
227264 }
@@ -245,6 +282,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
245282 }
246283
247284 void forStatement_conditionBegin (Set <Variable > loopAssigned) {
285+ _variablesReferenced (loopAssigned);
248286 _current = _current.removePromotedAll (loopAssigned);
249287 }
250288
@@ -346,11 +384,13 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
346384
347385 /// Return whether the [variable] is definitely assigned in the current state.
348386 bool isAssigned (Variable variable) {
387+ _variableReferenced (variable);
349388 return ! _current.notAssigned.contains (variable);
350389 }
351390
352391 void isExpression_end (
353392 Expression isExpression, Variable variable, bool isNot, Type type) {
393+ _variableReferenced (variable);
354394 if (functionBody.isPotentiallyMutatedInClosure (variable)) {
355395 return ;
356396 }
@@ -474,6 +514,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
474514 /// Retrieves the type that the [variable] is promoted to, if the [variable]
475515 /// is currently promoted. Otherwise returns `null` .
476516 Type promotedType (Variable variable) {
517+ _variableReferenced (variable);
477518 return _current.promoted[variable];
478519 }
479520
@@ -482,6 +523,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
482523 /// these variables might have different types and are "un-promoted" from
483524 /// the "afterExpression" state.
484525 void switchStatement_beginCase (Set <Variable > notPromoted) {
526+ _variablesReferenced (notPromoted);
485527 _current = _stack.last.removePromotedAll (notPromoted);
486528 }
487529
@@ -511,6 +553,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
511553 }
512554
513555 void tryCatchStatement_bodyEnd (Set <Variable > assignedInBody) {
556+ _variablesReferenced (assignedInBody);
514557 var beforeBody = _stack.removeLast ();
515558 var beforeCatch = beforeBody.removePromotedAll (assignedInBody);
516559 _stack.add (beforeCatch);
@@ -539,6 +582,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
539582 }
540583
541584 void tryFinallyStatement_end (Set <Variable > assignedInFinally) {
585+ _variablesReferenced (assignedInFinally);
542586 var afterBody = _stack.removeLast ();
543587 _current = _current.restrict (
544588 typeOperations,
@@ -549,16 +593,13 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
549593 }
550594
551595 void tryFinallyStatement_finallyBegin (Set <Variable > assignedInBody) {
596+ _variablesReferenced (assignedInBody);
552597 var beforeTry = _stack.removeLast ();
553598 var afterBody = _current;
554599 _stack.add (afterBody);
555600 _current = _join (afterBody, beforeTry.removePromotedAll (assignedInBody));
556601 }
557602
558- void verifyStackEmpty () {
559- assert (_stack.isEmpty);
560- }
561-
562603 void whileStatement_bodyBegin (
563604 Statement whileStatement, Expression condition) {
564605 _conditionalEnd (condition);
@@ -574,6 +615,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
574615 }
575616
576617 void whileStatement_conditionBegin (Set <Variable > loopAssigned) {
618+ _variablesReferenced (loopAssigned);
577619 _current = _current.removePromotedAll (loopAssigned);
578620 }
579621
@@ -587,6 +629,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
587629
588630 /// Register write of the given [variable] in the current state.
589631 void write (Variable variable) {
632+ _variableReferenced (variable);
590633 _current = _current.write (typeOperations, _emptySet, variable);
591634 }
592635
@@ -623,6 +666,26 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
623666 newPromoted,
624667 );
625668 }
669+
670+ /// If assertions are enabled, records that the given variable has been
671+ /// referenced. The [finish] method will verify that all referenced variables
672+ /// were eventually passed to [add] .
673+ void _variableReferenced (Variable variable) {
674+ assert (() {
675+ _referencedVariables.add (variable);
676+ return true ;
677+ }());
678+ }
679+
680+ /// If assertions are enabled, records that the given variables have been
681+ /// referenced. The [finish] method will verify that all referenced variables
682+ /// were eventually passed to [add] .
683+ void _variablesReferenced (Iterable <Variable > variables) {
684+ assert (() {
685+ _referencedVariables.addAll (variables);
686+ return true ;
687+ }());
688+ }
626689}
627690
628691/// Accessor for function body information.
0 commit comments