@@ -564,7 +564,7 @@ namespace ts {
564
564
if ( ! isIIFE ) {
565
565
currentFlow = { flags : FlowFlags . Start } ;
566
566
if ( containerFlags & ( ContainerFlags . IsFunctionExpression | ContainerFlags . IsObjectLiteralOrClassExpressionMethod ) ) {
567
- currentFlow . container = < FunctionExpression | ArrowFunction | MethodDeclaration > node ;
567
+ currentFlow . node = < FunctionExpression | ArrowFunction | MethodDeclaration > node ;
568
568
}
569
569
}
570
570
// We create a return control flow graph for IIFEs and constructors. For constructors
@@ -581,6 +581,7 @@ namespace ts {
581
581
if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) && containerFlags & ContainerFlags . IsFunctionLike && nodeIsPresent ( ( < FunctionLikeDeclaration > node ) . body ) ) {
582
582
node . flags |= NodeFlags . HasImplicitReturn ;
583
583
if ( hasExplicitReturn ) node . flags |= NodeFlags . HasExplicitReturn ;
584
+ ( < FunctionLikeDeclaration > node ) . endFlowNode = currentFlow ;
584
585
}
585
586
if ( node . kind === SyntaxKind . SourceFile ) {
586
587
node . flags |= emitFlags ;
@@ -671,6 +672,9 @@ namespace ts {
671
672
bindJSDoc ( node ) ;
672
673
return ;
673
674
}
675
+ if ( node . kind >= SyntaxKind . FirstStatement && node . kind <= SyntaxKind . LastStatement && ! options . allowUnreachableCode ) {
676
+ node . flowNode = currentFlow ;
677
+ }
674
678
switch ( node . kind ) {
675
679
case SyntaxKind . WhileStatement :
676
680
bindWhileStatement ( < WhileStatement > node ) ;
@@ -708,6 +712,9 @@ namespace ts {
708
712
case SyntaxKind . CaseClause :
709
713
bindCaseClause ( < CaseClause > node ) ;
710
714
break ;
715
+ case SyntaxKind . ExpressionStatement :
716
+ bindExpressionStatement ( < ExpressionStatement > node ) ;
717
+ break ;
711
718
case SyntaxKind . LabeledStatement :
712
719
bindLabeledStatement ( < LabeledStatement > node ) ;
713
720
break ;
@@ -845,17 +852,11 @@ namespace ts {
845
852
}
846
853
847
854
function createBranchLabel ( ) : FlowLabel {
848
- return {
849
- flags : FlowFlags . BranchLabel ,
850
- antecedents : undefined
851
- } ;
855
+ return { flags : FlowFlags . BranchLabel , antecedents : undefined } ;
852
856
}
853
857
854
858
function createLoopLabel ( ) : FlowLabel {
855
- return {
856
- flags : FlowFlags . LoopLabel ,
857
- antecedents : undefined
858
- } ;
859
+ return { flags : FlowFlags . LoopLabel , antecedents : undefined } ;
859
860
}
860
861
861
862
function setFlowNodeReferenced ( flow : FlowNode ) {
@@ -885,26 +886,30 @@ namespace ts {
885
886
return antecedent ;
886
887
}
887
888
setFlowNodeReferenced ( antecedent ) ;
888
- return flowNodeCreated ( { flags, expression , antecedent } ) ;
889
+ return flowNodeCreated ( { flags, antecedent , node : expression } ) ;
889
890
}
890
891
891
892
function createFlowSwitchClause ( antecedent : FlowNode , switchStatement : SwitchStatement , clauseStart : number , clauseEnd : number ) : FlowNode {
892
893
if ( ! isNarrowingExpression ( switchStatement . expression ) ) {
893
894
return antecedent ;
894
895
}
895
896
setFlowNodeReferenced ( antecedent ) ;
896
- return flowNodeCreated ( { flags : FlowFlags . SwitchClause , switchStatement, clauseStart, clauseEnd, antecedent } ) ;
897
+ return flowNodeCreated ( { flags : FlowFlags . SwitchClause , antecedent , switchStatement, clauseStart, clauseEnd } ) ;
897
898
}
898
899
899
900
function createFlowAssignment ( antecedent : FlowNode , node : Expression | VariableDeclaration | BindingElement ) : FlowNode {
900
901
setFlowNodeReferenced ( antecedent ) ;
901
902
return flowNodeCreated ( { flags : FlowFlags . Assignment , antecedent, node } ) ;
902
903
}
903
904
905
+ function createFlowCall ( antecedent : FlowNode , node : CallExpression ) : FlowNode {
906
+ setFlowNodeReferenced ( antecedent ) ;
907
+ return flowNodeCreated ( { flags : FlowFlags . Call , antecedent, node } ) ;
908
+ }
909
+
904
910
function createFlowArrayMutation ( antecedent : FlowNode , node : CallExpression | BinaryExpression ) : FlowNode {
905
911
setFlowNodeReferenced ( antecedent ) ;
906
- const res : FlowArrayMutation = flowNodeCreated ( { flags : FlowFlags . ArrayMutation , antecedent, node } ) ;
907
- return res ;
912
+ return flowNodeCreated ( { flags : FlowFlags . ArrayMutation , antecedent, node } ) ;
908
913
}
909
914
910
915
function finishFlowLabel ( flow : FlowLabel ) : FlowNode {
@@ -1030,12 +1035,12 @@ namespace ts {
1030
1035
function bindForInOrForOfStatement ( node : ForInOrOfStatement ) : void {
1031
1036
const preLoopLabel = createLoopLabel ( ) ;
1032
1037
const postLoopLabel = createBranchLabel ( ) ;
1038
+ bind ( node . expression ) ;
1033
1039
addAntecedent ( preLoopLabel , currentFlow ) ;
1034
1040
currentFlow = preLoopLabel ;
1035
1041
if ( node . kind === SyntaxKind . ForOfStatement ) {
1036
1042
bind ( node . awaitModifier ) ;
1037
1043
}
1038
- bind ( node . expression ) ;
1039
1044
addAntecedent ( postLoopLabel , currentFlow ) ;
1040
1045
bind ( node . initializer ) ;
1041
1046
if ( node . initializer . kind !== SyntaxKind . VariableDeclarationList ) {
@@ -1222,7 +1227,8 @@ namespace ts {
1222
1227
addAntecedent ( postSwitchLabel , currentFlow ) ;
1223
1228
const hasDefault = forEach ( node . caseBlock . clauses , c => c . kind === SyntaxKind . DefaultClause ) ;
1224
1229
// We mark a switch statement as possibly exhaustive if it has no default clause and if all
1225
- // case clauses have unreachable end points (e.g. they all return).
1230
+ // case clauses have unreachable end points (e.g. they all return). Note, we no longer need
1231
+ // this property in control flow analysis, it's there only for backwards compatibility.
1226
1232
node . possiblyExhaustive = ! hasDefault && ! postSwitchLabel . antecedents ;
1227
1233
if ( ! hasDefault ) {
1228
1234
addAntecedent ( postSwitchLabel , createFlowSwitchClause ( preSwitchCaseFlow , node , 0 , 0 ) ) ;
@@ -1281,6 +1287,24 @@ namespace ts {
1281
1287
activeLabels ! . pop ( ) ;
1282
1288
}
1283
1289
1290
+ function isDottedName ( node : Expression ) : boolean {
1291
+ return node . kind === SyntaxKind . Identifier || node . kind === SyntaxKind . ThisKeyword ||
1292
+ node . kind === SyntaxKind . PropertyAccessExpression && isDottedName ( ( < PropertyAccessExpression > node ) . expression ) ||
1293
+ node . kind === SyntaxKind . ParenthesizedExpression && isDottedName ( ( < ParenthesizedExpression > node ) . expression ) ;
1294
+ }
1295
+
1296
+ function bindExpressionStatement ( node : ExpressionStatement ) : void {
1297
+ bind ( node . expression ) ;
1298
+ // A top level call expression with a dotted function name and at least one argument
1299
+ // is potentially an assertion and is therefore included in the control flow.
1300
+ if ( node . expression . kind === SyntaxKind . CallExpression ) {
1301
+ const call = < CallExpression > node . expression ;
1302
+ if ( isDottedName ( call . expression ) ) {
1303
+ currentFlow = createFlowCall ( currentFlow , call ) ;
1304
+ }
1305
+ }
1306
+ }
1307
+
1284
1308
function bindLabeledStatement ( node : LabeledStatement ) : void {
1285
1309
const preStatementLabel = createLoopLabel ( ) ;
1286
1310
const postStatementLabel = createBranchLabel ( ) ;
0 commit comments