| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // Test for dangling-else detection when the then-part has a label. The |
| // then-part of an if-then-else statement sometimes needs to be wrapped in a |
| // block to avoid an inner if-then 'capturing' the else part. |
| |
| import 'dart:convert'; |
| import 'package:expect/expect.dart'; |
| import 'package:js_ast/js_ast.dart'; |
| |
| void check1(String expected, Statement then) { |
| final actual = DebugPrint( |
| If(VariableUse('x'), then, ExpressionStatement(VariableUse('E'))), |
| ); |
| Expect.equals( |
| expected, |
| actual, |
| '\n' |
| '\nexpected ${json.encode(expected)}' |
| '\nactual: ${json.encode(actual)}', |
| ); |
| } |
| |
| void check( |
| String expected, |
| Statement then1, [ |
| Statement? then2, |
| Statement? then3, |
| Statement? then4, |
| ]) { |
| check1(expected, then1); |
| if (then2 != null) check1(expected, then2); |
| if (then3 != null) check1(expected, then3); |
| if (then4 != null) check1(expected, then4); |
| } |
| |
| void main() { |
| final y = VariableUse('y'); |
| final z = VariableUse('z'); |
| final S1 = ExpressionStatement(VariableUse('S1')); |
| final S2 = ExpressionStatement(VariableUse('S2')); |
| |
| check(r''' |
| if (x) |
| L: |
| if (y) |
| S1; |
| else |
| S2; |
| else |
| E; |
| ''', LabeledStatement('L', If(y, S1, S2))); |
| |
| check(r''' |
| if (x) { |
| L: |
| if (y) |
| S1; |
| else |
| S2; |
| } else |
| E; |
| ''', Block([LabeledStatement('L', If(y, S1, S2))])); |
| |
| check(r''' |
| if (x) |
| L: { |
| if (y) |
| S1; |
| else |
| S2; |
| } |
| else |
| E; |
| ''', LabeledStatement('L', Block([If(y, S1, S2)]))); |
| |
| check( |
| r''' |
| if (x) { |
| L: |
| if (y) |
| S1; |
| } else |
| E; |
| ''', |
| LabeledStatement('L', If.noElse(y, S1)), |
| Block([LabeledStatement('L', If.noElse(y, S1))]), |
| ); |
| |
| check(r''' |
| if (x) { |
| L: { |
| if (y) |
| S1; |
| } |
| } else |
| E; |
| ''', LabeledStatement('L', Block([If.noElse(y, S1)]))); |
| |
| check(r''' |
| if (x) |
| L: { |
| if (y) |
| S1; |
| S2; |
| } |
| else |
| E; |
| ''', LabeledStatement('L', Block([If.noElse(y, S1), S2]))); |
| |
| check( |
| r''' |
| if (x) { |
| L: |
| if (y) |
| S1; |
| else if (z) |
| S2; |
| } else |
| E; |
| ''', |
| LabeledStatement('L', If(y, S1, If.noElse(z, S2))), |
| Block([LabeledStatement('L', If(y, S1, If.noElse(z, S2)))]), |
| ); |
| |
| check(r''' |
| if (x) { |
| L: { |
| if (y) |
| S1; |
| else if (z) |
| S2; |
| } |
| } else |
| E; |
| ''', LabeledStatement('L', Block([If(y, S1, If.noElse(z, S2))]))); |
| |
| check( |
| r''' |
| if (x) { |
| L: |
| if (y) |
| S1; |
| else { |
| if (z) |
| S2; |
| } |
| } else |
| E; |
| ''', |
| LabeledStatement('L', If(y, S1, Block([If.noElse(z, S2)]))), |
| Block([ |
| LabeledStatement('L', If(y, S1, Block([If.noElse(z, S2)]))), |
| ]), |
| ); |
| |
| check( |
| r''' |
| if (x) { |
| L: |
| while (y) |
| if (z) |
| S1; |
| } else |
| E; |
| ''', |
| LabeledStatement('L', While(y, If.noElse(z, S1))), |
| Block([LabeledStatement('L', While(y, If.noElse(z, S1)))]), |
| ); |
| |
| check(r''' |
| if (x) { |
| L: { |
| while (y) |
| if (z) |
| S1; |
| } |
| } else |
| E; |
| ''', LabeledStatement('L', Block([While(y, If.noElse(z, S1))]))); |
| |
| check(r''' |
| if (x) { |
| L: |
| while (y) { |
| if (z) |
| S1; |
| } |
| } else |
| E; |
| ''', LabeledStatement('L', While(y, Block([If.noElse(z, S1)])))); |
| |
| check( |
| r''' |
| if (x) { |
| L: |
| for (;;) |
| if (z) |
| S1; |
| } else |
| E; |
| ''', |
| LabeledStatement('L', For(null, null, null, If.noElse(z, S1))), |
| Block([LabeledStatement('L', For(null, null, null, If.noElse(z, S1)))]), |
| ); |
| |
| check(r''' |
| if (x) { |
| L: { |
| for (;;) |
| if (z) |
| S1; |
| } |
| } else |
| E; |
| ''', LabeledStatement('L', Block([For(null, null, null, If.noElse(z, S1))]))); |
| |
| check(r''' |
| if (x) { |
| L: |
| for (;;) { |
| if (z) |
| S1; |
| } |
| } else |
| E; |
| ''', LabeledStatement('L', For(null, null, null, Block([If.noElse(z, S1)])))); |
| } |