@@ -778,17 +778,6 @@ module API {
778778 } or
779779 MkSyntheticCallbackArg ( DataFlow:: InvokeNode nd )
780780
781- private predicate needsDefNode ( DataFlow:: ClassNode cls ) {
782- hasSemantics ( cls ) and
783- (
784- cls = trackDefNode ( _)
785- or
786- cls .getAnInstanceReference ( ) = trackDefNode ( _)
787- or
788- needsDefNode ( cls .getADirectSubClass ( ) )
789- )
790- }
791-
792781 class TDef = MkModuleDef or TNonModuleDef ;
793782
794783 class TNonModuleDef = MkModuleExport or MkClassInstance or MkDef or MkSyntheticCallbackArg ;
@@ -805,8 +794,26 @@ module API {
805794 hasSemantics ( imp )
806795 }
807796
797+ private signature module StageInputSig {
798+ /** Holds if `node` should be seen as a use-node root, in addition to module imports (which are the usual roots). */
799+ predicate isAdditionalUseRoot ( Node node ) ;
800+
801+ /** Holds if `node` should be seen as a def-node root, in addition to module exports (which are the usual roots). */
802+ predicate isAdditionalDefRoot ( Node node ) ;
803+
804+ /**
805+ * Holds if `node` is considered "in scope" for this stage, meaning that we allow outgoing labelled edges
806+ * to be materialised from here, and continue API graph construction from the successors edges.
807+ *
808+ * Note that the "additional roots" contributed by the stage inputs may be out of scope but can be tracked to a node in scope.
809+ * This predicate should thus not be used to block the tracking of use/def nodes, but only block the creation of new labelled edges.
810+ */
811+ bindingset [ node]
812+ predicate inScope ( DataFlow:: Node node ) ;
813+ }
814+
808815 cached
809- private module Stage {
816+ private module Stage< StageInputSig S > {
810817 /**
811818 * Holds if `rhs` is the right-hand side of a definition of a node that should have an
812819 * incoming edge from `base` labeled `lbl` in the API graph.
@@ -999,9 +1006,11 @@ module API {
9991006 */
10001007 cached
10011008 predicate rhs ( TApiNode nd , DataFlow:: Node rhs ) {
1009+ ( S:: inScope ( rhs ) or S:: isAdditionalDefRoot ( nd ) ) and
10021010 exists ( string m | nd = MkModuleExport ( m ) | exports ( m , rhs ) )
10031011 or
10041012 rhs ( _, _, rhs ) and
1013+ S:: inScope ( rhs ) and
10051014 nd = MkDef ( rhs )
10061015 }
10071016
@@ -1052,7 +1061,8 @@ module API {
10521061 base = MkRoot ( ) and
10531062 exists ( EntryPoint e |
10541063 lbl = Label:: entryPoint ( e ) and
1055- ref = e .getASource ( )
1064+ ref = e .getASource ( ) and
1065+ S:: inScope ( ref )
10561066 )
10571067 or
10581068 // property reads
@@ -1224,35 +1234,57 @@ module API {
12241234 )
12251235 }
12261236
1237+ private predicate needsDefNode ( DataFlow:: ClassNode cls ) {
1238+ hasSemantics ( cls ) and
1239+ (
1240+ cls = trackDefNode ( _)
1241+ or
1242+ cls .getAnInstanceReference ( ) = trackDefNode ( _)
1243+ or
1244+ needsDefNode ( cls .getADirectSubClass ( ) )
1245+ or
1246+ S:: isAdditionalDefRoot ( MkClassInstance ( cls ) )
1247+ or
1248+ S:: isAdditionalUseRoot ( MkClassInstance ( cls ) ) // These are also tracked as use-nodes
1249+ )
1250+ }
1251+
12271252 /**
12281253 * Holds if `ref` is a use of node `nd`.
12291254 */
12301255 cached
12311256 predicate use ( TApiNode nd , DataFlow:: Node ref ) {
1232- exists ( string m , Module mod | nd = MkModuleDef ( m ) and mod = importableModule ( m ) |
1233- ref = DataFlow:: moduleVarNode ( mod )
1234- )
1235- or
1236- exists ( string m , Module mod | nd = MkModuleExport ( m ) and mod = importableModule ( m ) |
1237- ref = DataFlow:: exportsVarNode ( mod )
1257+ ( S:: inScope ( ref ) or S:: isAdditionalUseRoot ( nd ) ) and
1258+ (
1259+ exists ( string m , Module mod | nd = MkModuleDef ( m ) and mod = importableModule ( m ) |
1260+ ref = DataFlow:: moduleVarNode ( mod )
1261+ )
12381262 or
1239- exists ( DataFlow:: Node base | use ( MkModuleDef ( m ) , base ) |
1240- ref = trackUseNode ( base ) .getAPropertyRead ( "exports" )
1263+ exists ( string m , Module mod | nd = MkModuleExport ( m ) and mod = importableModule ( m ) |
1264+ ref = DataFlow:: exportsVarNode ( mod )
1265+ or
1266+ exists ( DataFlow:: Node base | use ( MkModuleDef ( m ) , base ) |
1267+ ref = trackUseNode ( base ) .getAPropertyRead ( "exports" )
1268+ )
1269+ )
1270+ or
1271+ exists ( string m |
1272+ nd = MkModuleImport ( m ) and
1273+ ref = DataFlow:: moduleImport ( m )
12411274 )
12421275 )
12431276 or
1244- exists ( string m |
1245- nd = MkModuleImport ( m ) and
1246- ref = DataFlow:: moduleImport ( m )
1247- )
1248- or
1249- exists ( DataFlow:: ClassNode cls | nd = MkClassInstance ( cls ) |
1277+ exists ( DataFlow:: ClassNode cls | nd = MkClassInstance ( cls ) and needsDefNode ( cls ) |
12501278 ref = cls .getAReceiverNode ( )
12511279 or
12521280 ref = cls .( DataFlow:: ClassNode ) .getAPrototypeReference ( )
12531281 )
12541282 or
12551283 use ( _, _, ref ) and
1284+ S:: inScope ( ref ) and
1285+ nd = MkUse ( ref )
1286+ or
1287+ S:: isAdditionalUseRoot ( nd ) and
12561288 nd = MkUse ( ref )
12571289 }
12581290
@@ -1492,7 +1524,18 @@ module API {
14921524 }
14931525 }
14941526
1495- import Stage
1527+ private module Stage1Input implements StageInputSig {
1528+ pragma [ inline]
1529+ predicate isAdditionalUseRoot ( Node node ) { none ( ) }
1530+
1531+ pragma [ inline]
1532+ predicate isAdditionalDefRoot ( Node node ) { none ( ) }
1533+
1534+ bindingset [ node]
1535+ predicate inScope ( DataFlow:: Node node ) { any ( ) }
1536+ }
1537+
1538+ import Stage< Stage1Input >
14961539
14971540 /**
14981541 * Holds if there is an edge from `pred` to `succ` in the API graph.
0 commit comments