diff --git a/ql/src/codeql_ruby/ast/Method.qll b/ql/src/codeql_ruby/ast/Method.qll index f01eba6c323..988bc8fde06 100644 --- a/ql/src/codeql_ruby/ast/Method.qll +++ b/ql/src/codeql_ruby/ast/Method.qll @@ -1,8 +1,40 @@ private import codeql_ruby.AST private import codeql_ruby.controlflow.ControlFlowGraph private import internal.AST +private import internal.Method private import internal.TreeSitter +/** + * A representation of a method. + */ +class Method extends TMethod { + /** Get a declaration of this module, if any. */ + MethodBase getADeclaration() { result.getMethod() = this } + + /** Gets a textual representation of this method. */ + string toString() { + exists(Module m, string name | + this = TInstanceMethod(m, name) and result = m.toString() + "." + name + ) + } + + /** Gets the location of this method. */ + Location getLocation() { + result = + min(MethodBase decl, Module m, string name, Location loc, int weight | + this = TInstanceMethod(m, name) and + decl = methodDeclaration(m, name) and + loc = decl.getLocation() and + if exists(loc.getFile().getRelativePath()) then weight = 0 else weight = 1 + | + loc + order by + weight, count(decl.getAStmt()) desc, loc.getFile().getAbsolutePath(), loc.getStartLine(), + loc.getStartColumn() + ) + } +} + /** A callable. */ class Callable extends Expr, Scope, TCallable { /** Gets the number of parameters of this callable. */ @@ -24,6 +56,9 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase { /** Gets the name of this method. */ string getName() { none() } + /** Gets the method defined by this declaration. */ + Method getMethod() { none() } + override AstNode getAChild(string pred) { result = Callable.super.getAChild(pred) or @@ -44,6 +79,12 @@ class MethodDeclaration extends MethodBase, TMethodDeclaration { result = g.getName().(Generated::Setter).getName().getValue() + "=" } + final override Method getMethod() { + exists(Module owner, string name | + result = TInstanceMethod(owner, name) and this = methodDeclaration(owner, name) + ) + } + /** * Holds if this is a setter method, as in the following example: * ```rb diff --git a/ql/src/codeql_ruby/ast/internal/Method.qll b/ql/src/codeql_ruby/ast/internal/Method.qll new file mode 100644 index 00000000000..82e0f53d47f --- /dev/null +++ b/ql/src/codeql_ruby/ast/internal/Method.qll @@ -0,0 +1,10 @@ +private import codeql_ruby.ast.Method +private import codeql_ruby.ast.Module +private import codeql_ruby.ast.internal.Module + +newtype TMethod = + TInstanceMethod(TModule owner, string name) { exists(methodDeclaration(owner, name)) } + +MethodDeclaration methodDeclaration(TModule owner, string name) { + exists(ModuleBase m | m.getModule() = owner and result = m.getMethod(name)) +}