@@ -564,7 +564,7 @@ namespace ts {
564564 if ( ! isIIFE ) {
565565 currentFlow = { flags : FlowFlags . Start } ;
566566 if ( containerFlags & ( ContainerFlags . IsFunctionExpression | ContainerFlags . IsObjectLiteralOrClassExpressionMethod ) ) {
567- currentFlow . container = < FunctionExpression | ArrowFunction | MethodDeclaration > node ;
567+ currentFlow . node = < FunctionExpression | ArrowFunction | MethodDeclaration > node ;
568568 }
569569 }
570570 // We create a return control flow graph for IIFEs and constructors. For constructors
@@ -581,6 +581,7 @@ namespace ts {
581581 if ( ! ( currentFlow . flags & FlowFlags . Unreachable ) && containerFlags & ContainerFlags . IsFunctionLike && nodeIsPresent ( ( < FunctionLikeDeclaration > node ) . body ) ) {
582582 node . flags |= NodeFlags . HasImplicitReturn ;
583583 if ( hasExplicitReturn ) node . flags |= NodeFlags . HasExplicitReturn ;
584+ ( < FunctionLikeDeclaration > node ) . endFlowNode = currentFlow ;
584585 }
585586 if ( node . kind === SyntaxKind . SourceFile ) {
586587 node . flags |= emitFlags ;
@@ -671,6 +672,9 @@ namespace ts {
671672 bindJSDoc ( node ) ;
672673 return ;
673674 }
675+ if ( node . kind >= SyntaxKind . FirstStatement && node . kind <= SyntaxKind . LastStatement && ! options . allowUnreachableCode ) {
676+ node . flowNode = currentFlow ;
677+ }
674678 switch ( node . kind ) {
675679 case SyntaxKind . WhileStatement :
676680 bindWhileStatement ( < WhileStatement > node ) ;
@@ -708,6 +712,9 @@ namespace ts {
708712 case SyntaxKind . CaseClause :
709713 bindCaseClause ( < CaseClause > node ) ;
710714 break ;
715+ case SyntaxKind . ExpressionStatement :
716+ bindExpressionStatement ( < ExpressionStatement > node ) ;
717+ break ;
711718 case SyntaxKind . LabeledStatement :
712719 bindLabeledStatement ( < LabeledStatement > node ) ;
713720 break ;
@@ -845,17 +852,11 @@ namespace ts {
845852 }
846853
847854 function createBranchLabel ( ) : FlowLabel {
848- return {
849- flags : FlowFlags . BranchLabel ,
850- antecedents : undefined
851- } ;
855+ return { flags : FlowFlags . BranchLabel , antecedents : undefined } ;
852856 }
853857
854858 function createLoopLabel ( ) : FlowLabel {
855- return {
856- flags : FlowFlags . LoopLabel ,
857- antecedents : undefined
858- } ;
859+ return { flags : FlowFlags . LoopLabel , antecedents : undefined } ;
859860 }
860861
861862 function setFlowNodeReferenced ( flow : FlowNode ) {
@@ -885,26 +886,30 @@ namespace ts {
885886 return antecedent ;
886887 }
887888 setFlowNodeReferenced ( antecedent ) ;
888- return flowNodeCreated ( { flags, expression , antecedent } ) ;
889+ return flowNodeCreated ( { flags, antecedent , node : expression } ) ;
889890 }
890891
891892 function createFlowSwitchClause ( antecedent : FlowNode , switchStatement : SwitchStatement , clauseStart : number , clauseEnd : number ) : FlowNode {
892893 if ( ! isNarrowingExpression ( switchStatement . expression ) ) {
893894 return antecedent ;
894895 }
895896 setFlowNodeReferenced ( antecedent ) ;
896- return flowNodeCreated ( { flags : FlowFlags . SwitchClause , switchStatement, clauseStart, clauseEnd, antecedent } ) ;
897+ return flowNodeCreated ( { flags : FlowFlags . SwitchClause , antecedent , switchStatement, clauseStart, clauseEnd } ) ;
897898 }
898899
899900 function createFlowAssignment ( antecedent : FlowNode , node : Expression | VariableDeclaration | BindingElement ) : FlowNode {
900901 setFlowNodeReferenced ( antecedent ) ;
901902 return flowNodeCreated ( { flags : FlowFlags . Assignment , antecedent, node } ) ;
902903 }
903904
905+ function createFlowCall ( antecedent : FlowNode , node : CallExpression ) : FlowNode {
906+ setFlowNodeReferenced ( antecedent ) ;
907+ return flowNodeCreated ( { flags : FlowFlags . Call , antecedent, node } ) ;
908+ }
909+
904910 function createFlowArrayMutation ( antecedent : FlowNode , node : CallExpression | BinaryExpression ) : FlowNode {
905911 setFlowNodeReferenced ( antecedent ) ;
906- const res : FlowArrayMutation = flowNodeCreated ( { flags : FlowFlags . ArrayMutation , antecedent, node } ) ;
907- return res ;
912+ return flowNodeCreated ( { flags : FlowFlags . ArrayMutation , antecedent, node } ) ;
908913 }
909914
910915 function finishFlowLabel ( flow : FlowLabel ) : FlowNode {
@@ -1030,12 +1035,12 @@ namespace ts {
10301035 function bindForInOrForOfStatement ( node : ForInOrOfStatement ) : void {
10311036 const preLoopLabel = createLoopLabel ( ) ;
10321037 const postLoopLabel = createBranchLabel ( ) ;
1038+ bind ( node . expression ) ;
10331039 addAntecedent ( preLoopLabel , currentFlow ) ;
10341040 currentFlow = preLoopLabel ;
10351041 if ( node . kind === SyntaxKind . ForOfStatement ) {
10361042 bind ( node . awaitModifier ) ;
10371043 }
1038- bind ( node . expression ) ;
10391044 addAntecedent ( postLoopLabel , currentFlow ) ;
10401045 bind ( node . initializer ) ;
10411046 if ( node . initializer . kind !== SyntaxKind . VariableDeclarationList ) {
@@ -1222,7 +1227,8 @@ namespace ts {
12221227 addAntecedent ( postSwitchLabel , currentFlow ) ;
12231228 const hasDefault = forEach ( node . caseBlock . clauses , c => c . kind === SyntaxKind . DefaultClause ) ;
12241229 // 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.
12261232 node . possiblyExhaustive = ! hasDefault && ! postSwitchLabel . antecedents ;
12271233 if ( ! hasDefault ) {
12281234 addAntecedent ( postSwitchLabel , createFlowSwitchClause ( preSwitchCaseFlow , node , 0 , 0 ) ) ;
@@ -1281,6 +1287,24 @@ namespace ts {
12811287 activeLabels ! . pop ( ) ;
12821288 }
12831289
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+
12841308 function bindLabeledStatement ( node : LabeledStatement ) : void {
12851309 const preStatementLabel = createLoopLabel ( ) ;
12861310 const postStatementLabel = createBranchLabel ( ) ;
0 commit comments