Skip to content

Commit 046e669

Browse files
committed
Ruby: add getAncestorExpr
1 parent 77d1788 commit 046e669

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

ruby/ql/lib/codeql/ruby/ast/Module.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import codeql.ruby.CFG
33
private import internal.AST
44
private import internal.Module
55
private import internal.TreeSitter
6+
private import internal.Scope
67

78
/**
89
* A representation of a run-time `module` or `class` value.
@@ -263,6 +264,31 @@ class ModuleBase extends BodyStmt, Scope, TModuleBase {
263264
not this instanceof Namespace and
264265
result = this.getEnclosingModule().getNamespaceOrToplevel()
265266
}
267+
268+
/**
269+
* Gets an expression denoting the super class or an included or prepended module.
270+
*
271+
* For example, `C` is an ancestor expression of `M` in each of the following examples:
272+
* ```rb
273+
* class M < C
274+
* end
275+
*
276+
* module M
277+
* include C
278+
* prepend C
279+
* end
280+
* ```
281+
*/
282+
Expr getAnAncestorExpr() {
283+
exists(MethodCall call |
284+
call.getReceiver().(SelfVariableAccess).getVariable() = this.getModuleSelfVariable() and
285+
call.getMethodName() = ["include", "prepend"] and
286+
result = call.getArgument(0) and
287+
scopeOfInclSynth(call) = this // only permit calls directly in the module scope, not in a block
288+
)
289+
or
290+
result = this.(ClassDeclaration).getSuperclassExpr()
291+
}
266292
}
267293

268294
/**

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,24 @@ class ModuleNode instanceof Module {
738738
/** Gets a module that transitively subclasses, includes, or prepends this module. */
739739
final ModuleNode getADescendent() { result = super.getADescendent() }
740740

741+
/**
742+
* Gets the expression node denoting the super class or an included or prepended module.
743+
*
744+
* For example, `C` is an ancestor expression of `M` in each of the following examples:
745+
* ```rb
746+
* class M < C
747+
* end
748+
*
749+
* module M
750+
* include C
751+
* prepend C
752+
* end
753+
* ```
754+
*/
755+
final ExprNode getAnAncestorExpr() {
756+
result.asExpr().getExpr() = super.getADeclaration().getAnAncestorExpr()
757+
}
758+
741759
/** Holds if this module is a class. */
742760
predicate isClass() { super.isClass() }
743761

0 commit comments

Comments
 (0)