@@ -11,6 +11,10 @@ namespace Debug {
1111 type MethodDeclaration = Node ;
1212 type Expression = Node ;
1313 type SourceFile = Node ;
14+ type VariableDeclaration = Node ;
15+ type BindingElement = Node ;
16+ type CallExpression = Node ;
17+ type BinaryExpression = Node ;
1418
1519 interface SwitchStatement extends Node {
1620 caseBlock : CaseBlock ;
@@ -59,8 +63,6 @@ namespace Debug {
5963 }
6064
6165 type FlowNode =
62- | AfterFinallyFlow
63- | PreFinallyFlow
6466 | FlowStart
6567 | FlowLabel
6668 | FlowAssignment
@@ -76,14 +78,6 @@ namespace Debug {
7678 id ?: number ;
7779 }
7880
79- interface AfterFinallyFlow extends FlowNodeBase {
80- antecedent : FlowNode ;
81- }
82-
83- interface PreFinallyFlow extends FlowNodeBase {
84- antecedent : FlowNode ;
85- }
86-
8781 interface FlowStart extends FlowNodeBase {
8882 node ?: FunctionExpression | ArrowFunction | MethodDeclaration ;
8983 }
@@ -93,12 +87,12 @@ namespace Debug {
9387 }
9488
9589 interface FlowAssignment extends FlowNodeBase {
96- node : Expression ;
90+ node : Expression | VariableDeclaration | BindingElement ;
9791 antecedent : FlowNode ;
9892 }
9993
10094 interface FlowCall extends FlowNodeBase {
101- node : Expression ;
95+ node : CallExpression ;
10296 antecedent : FlowNode ;
10397 }
10498
@@ -115,7 +109,7 @@ namespace Debug {
115109 }
116110
117111 interface FlowArrayMutation extends FlowNodeBase {
118- node : Expression ;
112+ node : CallExpression | BinaryExpression ;
119113 antecedent : FlowNode ;
120114 }
121115
@@ -192,6 +186,7 @@ namespace Debug {
192186 lane : number ;
193187 endLane : number ;
194188 level : number ;
189+ circular : boolean | "circularity" ;
195190 }
196191
197192 interface FlowGraphEdge {
@@ -217,8 +212,9 @@ namespace Debug {
217212 const links : Record < number , FlowGraphNode > = Object . create ( /*o*/ null ) ; // eslint-disable-line no-null/no-null
218213 const nodes : FlowGraphNode [ ] = [ ] ;
219214 const edges : FlowGraphEdge [ ] = [ ] ;
220- const root = buildGraphNode ( flowNode ) ;
215+ const root = buildGraphNode ( flowNode , new Set ( ) ) ;
221216 for ( const node of nodes ) {
217+ node . text = renderFlowNode ( node . flowNode , node . circular ) ;
222218 computeLevel ( node ) ;
223219 }
224220
@@ -263,26 +259,43 @@ namespace Debug {
263259 return parents ;
264260 }
265261
266- function buildGraphNode ( flowNode : FlowNode ) {
262+ function buildGraphNode ( flowNode : FlowNode , seen : Set < FlowNode > ) : FlowGraphNode {
267263 const id = getDebugFlowNodeId ( flowNode ) ;
268264 let graphNode = links [ id ] ;
265+ if ( graphNode && seen . has ( flowNode ) ) {
266+ graphNode . circular = true ;
267+ graphNode = {
268+ id : - 1 ,
269+ flowNode,
270+ edges : [ ] ,
271+ text : "" ,
272+ lane : - 1 ,
273+ endLane : - 1 ,
274+ level : - 1 ,
275+ circular : "circularity"
276+ } ;
277+ nodes . push ( graphNode ) ;
278+ return graphNode ;
279+ }
280+ seen . add ( flowNode ) ;
269281 if ( ! graphNode ) {
270- links [ id ] = graphNode = { id, flowNode, edges : [ ] , text : renderFlowNode ( flowNode ) , lane : - 1 , endLane : - 1 , level : - 1 } ;
282+ links [ id ] = graphNode = { id, flowNode, edges : [ ] , text : "" , lane : - 1 , endLane : - 1 , level : - 1 , circular : false } ;
271283 nodes . push ( graphNode ) ;
272284 if ( hasAntecedents ( flowNode ) ) {
273285 for ( const antecedent of flowNode . antecedents ) {
274- buildGraphEdge ( graphNode , antecedent ) ;
286+ buildGraphEdge ( graphNode , antecedent , seen ) ;
275287 }
276288 }
277289 else if ( hasAntecedent ( flowNode ) ) {
278- buildGraphEdge ( graphNode , flowNode . antecedent ) ;
290+ buildGraphEdge ( graphNode , flowNode . antecedent , seen ) ;
279291 }
280292 }
293+ seen . delete ( flowNode ) ;
281294 return graphNode ;
282295 }
283296
284- function buildGraphEdge ( source : FlowGraphNode , antecedent : FlowNode ) {
285- const target = buildGraphNode ( antecedent ) ;
297+ function buildGraphEdge ( source : FlowGraphNode , antecedent : FlowNode , seen : Set < FlowNode > ) {
298+ const target = buildGraphNode ( antecedent , seen ) ;
286299 const edge : FlowGraphEdge = { source, target } ;
287300 edges . push ( edge ) ;
288301 source . edges . push ( edge ) ;
@@ -353,8 +366,11 @@ namespace Debug {
353366 return getSourceTextOfNodeFromSourceFile ( sourceFile , node , /*includeTrivia*/ false ) ;
354367 }
355368
356- function renderFlowNode ( flowNode : FlowNode ) {
369+ function renderFlowNode ( flowNode : FlowNode , circular : boolean | "circularity" ) {
357370 let text = getHeader ( flowNode . flags ) ;
371+ if ( circular ) {
372+ text = `${ text } #${ getDebugFlowNodeId ( flowNode ) } ` ;
373+ }
358374 if ( hasNode ( flowNode ) ) {
359375 if ( flowNode . node ) {
360376 text += ` (${ getNodeText ( flowNode . node ) } )` ;
@@ -373,7 +389,7 @@ namespace Debug {
373389 }
374390 text += ` (${ clauses . join ( ", " ) } )` ;
375391 }
376- return text ;
392+ return circular === "circularity" ? `Circular( ${ text } )` : text ;
377393 }
378394
379395 function renderGraph ( ) {
0 commit comments