Skip to content

Commit 95399b2

Browse files
committed
Refactor ApiGraphs.qll
1 parent 4f96834 commit 95399b2

1 file changed

Lines changed: 33 additions & 53 deletions

File tree

ql/src/codeql_ruby/ApiGraphs.qll

Lines changed: 33 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)