Ruby: add getAncestorExpr

This commit is contained in:
Asger F
2022-10-20 14:29:52 +02:00
parent 77d1788619
commit 046e669c78
2 changed files with 44 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ private import codeql.ruby.CFG
private import internal.AST
private import internal.Module
private import internal.TreeSitter
private import internal.Scope
/**
* A representation of a run-time `module` or `class` value.
@@ -263,6 +264,31 @@ class ModuleBase extends BodyStmt, Scope, TModuleBase {
not this instanceof Namespace and
result = this.getEnclosingModule().getNamespaceOrToplevel()
}
/**
* Gets an expression denoting the super class or an included or prepended module.
*
* For example, `C` is an ancestor expression of `M` in each of the following examples:
* ```rb
* class M < C
* end
*
* module M
* include C
* prepend C
* end
* ```
*/
Expr getAnAncestorExpr() {
exists(MethodCall call |
call.getReceiver().(SelfVariableAccess).getVariable() = this.getModuleSelfVariable() and
call.getMethodName() = ["include", "prepend"] and
result = call.getArgument(0) and
scopeOfInclSynth(call) = this // only permit calls directly in the module scope, not in a block
)
or
result = this.(ClassDeclaration).getSuperclassExpr()
}
}
/**

View File

@@ -738,6 +738,24 @@ class ModuleNode instanceof Module {
/** Gets a module that transitively subclasses, includes, or prepends this module. */
final ModuleNode getADescendent() { result = super.getADescendent() }
/**
* Gets the expression node denoting the super class or an included or prepended module.
*
* For example, `C` is an ancestor expression of `M` in each of the following examples:
* ```rb
* class M < C
* end
*
* module M
* include C
* prepend C
* end
* ```
*/
final ExprNode getAnAncestorExpr() {
result.asExpr().getExpr() = super.getADeclaration().getAnAncestorExpr()
}
/** Holds if this module is a class. */
predicate isClass() { super.isClass() }