@@ -203,7 +203,7 @@ module API {
203203 exists ( string type |
204204 this = Impl:: MkUse ( _) and type = "Use "
205205 or
206- this = Impl:: MkModuleImport ( _) and type = "ModuleImport "
206+ this = Impl:: MkModule ( _) and type = "ModuleUse "
207207 |
208208 result = type + getPath ( )
209209 or
@@ -222,7 +222,21 @@ module API {
222222 * you should use `.getMember` on the parent module/class. For example, for nodes corresponding to the class `Gem::Version`,
223223 * use `moduleImport("Gem").getMember("Version")`.
224224 */
225- Node moduleImport ( string m ) { result = Impl:: MkModuleImport ( m ) }
225+ Node moduleImport ( string m ) {
226+ result = Impl:: MkModule ( m ) and not m .matches ( "%::%" )
227+ or
228+ result = Impl:: MkUse ( unresolvedModuleReference ( m ) )
229+ }
230+
231+ DataFlow:: Node unresolvedModuleReference ( string m ) {
232+ exists ( ConstantReadAccess iexpr , DataFlow:: Node node |
233+ not exists ( resolveScopeExpr ( iexpr ) ) and
234+ not exists ( iexpr .getScopeExpr ( ) ) and
235+ m = iexpr .getName ( ) and
236+ result = node and
237+ node .asExpr ( ) .getExpr ( ) = iexpr
238+ )
239+ }
226240
227241 /**
228242 * Provides the actual implementation of API graphs, cached for performance.
@@ -253,39 +267,15 @@ module API {
253267 /** The root of the API graph. */
254268 MkRoot ( ) or
255269 /** An abstract representative for imports of the module called `name`. */
256- MkModuleImport ( string name ) { topLevelModule ( _ , name ) } or
270+ MkModule ( string name ) { exists ( TResolved ( name ) ) } or
257271 /** A use of an API member at the node `nd`. */
258- MkUse ( DataFlow:: Node nd ) { use ( _, _, nd ) }
259-
260- class TUse = MkModuleImport or MkUse ;
272+ MkUse ( DataFlow:: Node nd ) {
273+ use ( _, _, nd )
274+ or
275+ nd = unresolvedModuleReference ( _)
276+ }
261277
262- /**
263- * Holds if `imp` is a data-flow node of a constant read access that refers to a top-level module by the
264- * name `name`.
265- */
266- private predicate topLevelModule ( DataFlow:: Node imp , string name ) {
267- // Nodes of the form `::Rails`
268- exists ( ConstantReadAccess iexpr |
269- imp .asExpr ( ) .getExpr ( ) = iexpr and
270- iexpr .hasGlobalScope ( ) and
271- name = iexpr .getName ( )
272- )
273- or
274- // Nodes that could be resolved to a definition
275- exists ( ConstantReadAccess iexpr |
276- TResolved ( name ) = resolveScopeExpr ( iexpr ) and
277- iexpr = imp .asExpr ( ) .getExpr ( )
278- )
279- or
280- // Nodes like `Rails` in `Rails::View::Whatever` that couldn't be resolved to a definition.
281- // The module `Rails` could plausibly be a top-level module.
282- exists ( ConstantReadAccess iexpr |
283- imp .asExpr ( ) .getExpr ( ) = iexpr and
284- ( not iexpr .hasGlobalScope ( ) and not exists ( iexpr .getScopeExpr ( ) ) ) and
285- name = iexpr .getName ( ) and
286- not exists ( resolveScopeExpr ( iexpr ) )
287- )
288- }
278+ class TUse = MkModule or MkUse ;
289279
290280 /**
291281 * Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled
@@ -307,12 +297,12 @@ module API {
307297 // pred = `Rails` part of `Rails::Whatever`
308298 // lbl = `Whatever`
309299 // ref = `Rails::Whatever`
310- exists ( ConstantAccess c , DataFlow:: Node node |
311- not exists ( resolveScopeExpr ( c ) ) and
300+ exists ( ExprNodes :: ConstantAccessCfgNode c , DataFlow:: Node node |
301+ not exists ( resolveScopeExpr ( c . getExpr ( ) ) ) and
312302 pred .flowsTo ( node ) and
313- node .asExpr ( ) . getExpr ( ) = c .getScopeExpr ( ) and
314- lbl = Label:: member ( c .getName ( ) ) and
315- ref .asExpr ( ) . getExpr ( ) = c
303+ node .asExpr ( ) = c .getScopeExpr ( ) and
304+ lbl = Label:: member ( c .getExpr ( ) . getName ( ) ) and
305+ ref .asExpr ( ) = c
316306 )
317307 or
318308 // Calling a method on a node that is a use of `base`
@@ -341,9 +331,10 @@ module API {
341331 */
342332 cached
343333 predicate use ( TApiNode nd , DataFlow:: Node ref ) {
344- exists ( string name |
345- nd = MkModuleImport ( name ) and
346- topLevelModule ( ref , name )
334+ exists ( string name , ExprNodes:: ConstantAccessCfgNode access |
335+ access = ref .asExpr ( ) and
336+ nd = MkModule ( name ) and
337+ TResolved ( name ) = resolveScopeExpr ( access .getExpr ( ) )
347338 )
348339 or
349340 nd = MkUse ( ref )
@@ -382,18 +373,7 @@ module API {
382373 pred = MkRoot ( ) and
383374 lbl = Label:: mod ( m )
384375 |
385- succ = MkModuleImport ( m ) and
386- // Only allow unqualified names to count as top-level modules.
387- not m .matches ( "%::%" )
388- )
389- or
390- exists ( ConstantReadAccess c , string name |
391- TResolved ( name ) = resolveScopeExpr ( c ) and
392- lbl = Label:: member ( c .getName ( ) ) and
393- succ = MkModuleImport ( name )
394- |
395- use ( pred , any ( DataFlow:: Node n | n .asExpr ( ) .getExpr ( ) = c .getScopeExpr ( ) ) ) or
396- pred = MkModuleImport ( name .regexpReplaceAll ( "::" + c .getName ( ) + "$" , "" ) )
376+ succ = moduleImport ( m )
397377 )
398378 or
399379 /* Every node that is a use of an API component is itself added to the API graph. */
0 commit comments