@@ -784,17 +784,6 @@ module API {
784784 } or
785785 MkSyntheticCallbackArg ( DataFlow:: InvokeNode nd )
786786
787- private predicate needsDefNode ( DataFlow:: ClassNode cls ) {
788- hasSemantics ( cls ) and
789- (
790- cls = trackDefNode ( _)
791- or
792- cls .getAnInstanceReference ( ) = trackDefNode ( _)
793- or
794- needsDefNode ( cls .getADirectSubClass ( ) )
795- )
796- }
797-
798787 class TDef = MkModuleDef or TNonModuleDef ;
799788
800789 class TNonModuleDef = MkModuleExport or MkClassInstance or MkDef or MkSyntheticCallbackArg ;
@@ -811,8 +800,26 @@ module API {
811800 hasSemantics ( imp )
812801 }
813802
803+ private signature module StageInputSig {
804+ /** Holds if `node` should be seen as a use-node root, in addition to module imports (which are the usual roots). */
805+ predicate isAdditionalUseRoot ( Node node ) ;
806+
807+ /** Holds if `node` should be seen as a def-node root, in addition to module exports (which are the usual roots). */
808+ predicate isAdditionalDefRoot ( Node node ) ;
809+
810+ /**
811+ * Holds if `node` is considered "in scope" for this stage, meaning that we allow outgoing labelled edges
812+ * to be materialised from here, and continue API graph construction from the successors edges.
813+ *
814+ * Note that the "additional roots" contributed by the stage inputs may be out of scope but can be tracked to a node in scope.
815+ * This predicate should thus not be used to block the tracking of use/def nodes, but only block the creation of new labelled edges.
816+ */
817+ bindingset [ node]
818+ predicate inScope ( DataFlow:: Node node ) ;
819+ }
820+
814821 cached
815- private module Stage {
822+ private module Stage< StageInputSig S > {
816823 /**
817824 * Holds if `rhs` is the right-hand side of a definition of a node that should have an
818825 * incoming edge from `base` labeled `lbl` in the API graph.
@@ -1005,9 +1012,11 @@ module API {
10051012 */
10061013 cached
10071014 predicate rhs ( TApiNode nd , DataFlow:: Node rhs ) {
1015+ ( S:: inScope ( rhs ) or S:: isAdditionalDefRoot ( nd ) ) and
10081016 exists ( string m | nd = MkModuleExport ( m ) | exports ( m , rhs ) )
10091017 or
10101018 rhs ( _, _, rhs ) and
1019+ S:: inScope ( rhs ) and
10111020 nd = MkDef ( rhs )
10121021 }
10131022
@@ -1058,7 +1067,8 @@ module API {
10581067 base = MkRoot ( ) and
10591068 exists ( EntryPoint e |
10601069 lbl = Label:: entryPoint ( e ) and
1061- ref = e .getASource ( )
1070+ ref = e .getASource ( ) and
1071+ S:: inScope ( ref )
10621072 )
10631073 or
10641074 // property reads
@@ -1230,35 +1240,57 @@ module API {
12301240 )
12311241 }
12321242
1243+ private predicate needsDefNode ( DataFlow:: ClassNode cls ) {
1244+ hasSemantics ( cls ) and
1245+ (
1246+ cls = trackDefNode ( _)
1247+ or
1248+ cls .getAnInstanceReference ( ) = trackDefNode ( _)
1249+ or
1250+ needsDefNode ( cls .getADirectSubClass ( ) )
1251+ or
1252+ S:: isAdditionalDefRoot ( MkClassInstance ( cls ) )
1253+ or
1254+ S:: isAdditionalUseRoot ( MkClassInstance ( cls ) ) // These are also tracked as use-nodes
1255+ )
1256+ }
1257+
12331258 /**
12341259 * Holds if `ref` is a use of node `nd`.
12351260 */
12361261 cached
12371262 predicate use ( TApiNode nd , DataFlow:: Node ref ) {
1238- exists ( string m , Module mod | nd = MkModuleDef ( m ) and mod = importableModule ( m ) |
1239- ref = DataFlow:: moduleVarNode ( mod )
1240- )
1241- or
1242- exists ( string m , Module mod | nd = MkModuleExport ( m ) and mod = importableModule ( m ) |
1243- ref = DataFlow:: exportsVarNode ( mod )
1263+ ( S:: inScope ( ref ) or S:: isAdditionalUseRoot ( nd ) ) and
1264+ (
1265+ exists ( string m , Module mod | nd = MkModuleDef ( m ) and mod = importableModule ( m ) |
1266+ ref = DataFlow:: moduleVarNode ( mod )
1267+ )
12441268 or
1245- exists ( DataFlow:: Node base | use ( MkModuleDef ( m ) , base ) |
1246- ref = trackUseNode ( base ) .getAPropertyRead ( "exports" )
1269+ exists ( string m , Module mod | nd = MkModuleExport ( m ) and mod = importableModule ( m ) |
1270+ ref = DataFlow:: exportsVarNode ( mod )
1271+ or
1272+ exists ( DataFlow:: Node base | use ( MkModuleDef ( m ) , base ) |
1273+ ref = trackUseNode ( base ) .getAPropertyRead ( "exports" )
1274+ )
1275+ )
1276+ or
1277+ exists ( string m |
1278+ nd = MkModuleImport ( m ) and
1279+ ref = DataFlow:: moduleImport ( m )
12471280 )
12481281 )
12491282 or
1250- exists ( string m |
1251- nd = MkModuleImport ( m ) and
1252- ref = DataFlow:: moduleImport ( m )
1253- )
1254- or
1255- exists ( DataFlow:: ClassNode cls | nd = MkClassInstance ( cls ) |
1283+ exists ( DataFlow:: ClassNode cls | nd = MkClassInstance ( cls ) and needsDefNode ( cls ) |
12561284 ref = cls .getAReceiverNode ( )
12571285 or
12581286 ref = cls .( DataFlow:: ClassNode ) .getAPrototypeReference ( )
12591287 )
12601288 or
12611289 use ( _, _, ref ) and
1290+ S:: inScope ( ref ) and
1291+ nd = MkUse ( ref )
1292+ or
1293+ S:: isAdditionalUseRoot ( nd ) and
12621294 nd = MkUse ( ref )
12631295 }
12641296
@@ -1498,7 +1530,18 @@ module API {
14981530 }
14991531 }
15001532
1501- import Stage
1533+ private module Stage1Input implements StageInputSig {
1534+ pragma [ inline]
1535+ predicate isAdditionalUseRoot ( Node node ) { none ( ) }
1536+
1537+ pragma [ inline]
1538+ predicate isAdditionalDefRoot ( Node node ) { none ( ) }
1539+
1540+ bindingset [ node]
1541+ predicate inScope ( DataFlow:: Node node ) { any ( ) }
1542+ }
1543+
1544+ import Stage< Stage1Input >
15021545
15031546 /**
15041547 * Holds if there is an edge from `pred` to `succ` in the API graph.
0 commit comments