@@ -43,7 +43,7 @@ export class CFGBuilder {
4343 const endNode = this . addNode ( "RETURN" , "implicit return" ) ;
4444 // `entry` will be non-null for any valid code
4545 if ( entry ) this . addEdge ( startNode , entry ) ;
46- if ( exit ) this . addEdge ( exit , endNode )
46+ if ( exit ) this . addEdge ( exit , endNode ) ;
4747 this . entry = startNode ;
4848 }
4949 return { graph : this . graph , entry : this . entry } ;
@@ -68,10 +68,10 @@ export class CFGBuilder {
6868 this . activeClusters . pop ( ) ;
6969 }
7070
71- private withCluster < T > ( type : ClusterType , fn : ( ) => T ) : T {
71+ private withCluster < T > ( type : ClusterType , fn : ( cluster : Cluster ) => T ) : T {
7272 const cluster = this . startCluster ( type ) ;
7373 try {
74- return fn ( ) ;
74+ return fn ( cluster ) ;
7575 } finally {
7676 this . endCluster ( cluster ) ;
7777 }
@@ -89,11 +89,12 @@ export class CFGBuilder {
8989 return id ;
9090 }
9191
92- private cloneNode ( node : string ) : string {
92+ private cloneNode ( node : string , overrides ?: { cluster : Cluster } ) : string {
9393 const id = `node${ this . nodeId ++ } ` ;
9494 const originalAttrs = this . graph . getNodeAttributes ( node ) ;
9595 const nodeAttrs = structuredClone ( originalAttrs ) ;
9696 nodeAttrs . cluster = originalAttrs . cluster ;
97+ Object . assign ( nodeAttrs , overrides ) ;
9798 this . graph . addNode ( id , nodeAttrs ) ;
9899 return id ;
99100 }
@@ -208,7 +209,7 @@ export class CFGBuilder {
208209
209210 const bodySyntax = this . getSyntax ( match , "try-body" ) ;
210211 const finallySyntax = this . getSyntax ( match , "finally-body" ) ;
211- return this . withCluster ( "try-complex" , ( ) => {
212+ return this . withCluster ( "try-complex" , ( tryComplexCluster ) => {
212213 const bodyBlock = this . withCluster ( "try" , ( ) =>
213214 getBlock ( bodySyntax ) ,
214215 ) as BasicBlock ;
@@ -222,10 +223,16 @@ export class CFGBuilder {
222223 // so that we can link them.
223224 const duplicateFinallyBlock = getBlock ( finallySyntax ) as BasicBlock ;
224225 // We also clone the return node, to place it _after_ the finally block
225- const returnNodeClone = this . cloneNode ( returnNode ) ;
226+ // We also override the cluster node, pulling it up to the `try-complex`,
227+ // as the return is neither in a `try`, `except`, or `finally` context.
228+ const returnNodeClone = this . cloneNode ( returnNode , {
229+ cluster : tryComplexCluster ,
230+ } ) ;
226231
227- if ( duplicateFinallyBlock . entry ) this . addEdge ( returnNode , duplicateFinallyBlock . entry ) ;
228- if ( duplicateFinallyBlock . exit ) this . addEdge ( duplicateFinallyBlock . exit , returnNodeClone )
232+ if ( duplicateFinallyBlock . entry )
233+ this . addEdge ( returnNode , duplicateFinallyBlock . entry ) ;
234+ if ( duplicateFinallyBlock . exit )
235+ this . addEdge ( duplicateFinallyBlock . exit , returnNodeClone ) ;
229236
230237 // We return the cloned return node as the new return node, in case we're nested
231238 // in a scope that will process it.
@@ -240,13 +247,13 @@ export class CFGBuilder {
240247 return finallyBlock ;
241248 } ) ;
242249
243- if ( bodyBlock . exit && finallyBlock ?. entry ) this . addEdge ( bodyBlock . exit , finallyBlock . entry ) ;
250+ if ( bodyBlock . exit && finallyBlock ?. entry )
251+ this . addEdge ( bodyBlock . exit , finallyBlock . entry ) ;
244252
245253 return blockHandler . update ( {
246254 entry : bodyBlock . entry ,
247255 exit : finallyBlock ?. exit ?? bodyBlock . exit ,
248256 } ) ;
249-
250257 } ) ;
251258 }
252259 private processWithStatement ( withSyntax : Parser . SyntaxNode ) : BasicBlock {
@@ -448,7 +455,10 @@ export class CFGBuilder {
448455 return match ;
449456 }
450457
451- private getSyntax ( match : Parser . QueryMatch , name : string ) : Parser . SyntaxNode | undefined {
458+ private getSyntax (
459+ match : Parser . QueryMatch ,
460+ name : string ,
461+ ) : Parser . SyntaxNode | undefined {
452462 return this . getSyntaxMany ( match , name ) [ 0 ] ;
453463 }
454464
0 commit comments