Skip to content

Commit caef2c3

Browse files
authored
Merge pull request #162 from github/aibaars/modules
Basic implementation of module resolution
2 parents aad5d13 + cdfabbc commit caef2c3

20 files changed

Lines changed: 610 additions & 149 deletions

ql/src/codeql_ruby/AST.qll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ast.Scope
1313
import ast.Statement
1414
import ast.Variable
1515
private import ast.internal.AST
16+
private import ast.internal.Scope
1617

1718
/**
1819
* A node in the abstract syntax tree. This class is the base class for all Ruby
@@ -28,6 +29,20 @@ class AstNode extends TAstNode {
2829
*/
2930
string getAPrimaryQlClass() { result = "???" }
3031

32+
/** Gets the enclosing module, if any. */
33+
ModuleBase getEnclosingModule() {
34+
exists(Scope::Range s |
35+
s = scopeOf(toGenerated(this)) and toGenerated(result) = s.getEnclosingModule()
36+
)
37+
}
38+
39+
/** Gets the enclosing method, if any. */
40+
MethodBase getEnclosingMethod() {
41+
exists(Scope::Range s |
42+
s = scopeOf(toGenerated(this)) and toGenerated(result) = s.getEnclosingMethod()
43+
)
44+
}
45+
3146
/** Gets a textual representation of this node. */
3247
cached
3348
string toString() { none() }

ql/src/codeql_ruby/ast/Expr.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ class BodyStmt extends StmtSequence, TBodyStmt {
137137
result = any(Generated::Program g | this = TToplevel(g)).getChild(i) and
138138
not result instanceof Generated::BeginBlock
139139
or
140-
result = any(Generated::Class g | this = TClass(g)).getChild(i)
140+
result = any(Generated::Class g | this = TClassDeclaration(g)).getChild(i)
141141
or
142142
result = any(Generated::SingletonClass g | this = TSingletonClass(g)).getChild(i)
143143
or
144-
result = any(Generated::Module g | this = TModule(g)).getChild(i)
144+
result = any(Generated::Module g | this = TModuleDeclaration(g)).getChild(i)
145145
or
146146
result = any(Generated::Begin g | this = TBeginExpr(g)).getChild(i)
147147
}

ql/src/codeql_ruby/ast/Method.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ private import internal.AST
44
private import internal.TreeSitter
55

66
/** A callable. */
7-
class Callable extends Expr, TCallable {
7+
class Callable extends Expr, Scope, TCallable {
88
/** Gets the number of parameters of this callable. */
99
final int getNumberOfParameters() { result = count(this.getAParameter()) }
1010

ql/src/codeql_ruby/ast/Module.qll

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,68 @@
11
private import codeql_ruby.AST
22
private import codeql_ruby.ast.Constant
33
private import internal.AST
4+
private import internal.Module
45
private import internal.TreeSitter
56

7+
/**
8+
* A representation of a run-time `module` or `class` value.
9+
*/
10+
class Module extends TModule {
11+
/** Get a declaration of this module, if any. */
12+
ModuleBase getADeclaration() { result.getModule() = this }
13+
14+
/** Gets a textual representation of this module. */
15+
string toString() {
16+
this = TResolved(result)
17+
or
18+
exists(Namespace n | this = TUnresolved(n) and result = "...::" + n.toString())
19+
}
20+
21+
/** Gets the location of this module. */
22+
Location getLocation() {
23+
exists(Namespace n | this = TUnresolved(n) and result = n.getLocation())
24+
or
25+
result =
26+
min(Namespace n, string qName, Location loc, int weight |
27+
this = TResolved(qName) and
28+
qName = namespaceDeclaration(n) and
29+
loc = n.getLocation() and
30+
if exists(loc.getFile().getRelativePath()) then weight = 0 else weight = 1
31+
|
32+
loc
33+
order by
34+
weight, count(n.getAStmt()) desc, loc.getFile().getAbsolutePath(), loc.getStartLine(),
35+
loc.getStartColumn()
36+
)
37+
}
38+
}
39+
640
/**
741
* The base class for classes, singleton classes, and modules.
842
*/
9-
class ModuleBase extends BodyStmt, TModuleBase {
43+
class ModuleBase extends BodyStmt, Scope, TModuleBase {
1044
/** Gets a method defined in this module/class. */
1145
MethodBase getAMethod() { result = this.getAStmt() }
1246

1347
/** Gets the method named `name` in this module/class, if any. */
1448
MethodBase getMethod(string name) { result = this.getAMethod() and result.getName() = name }
1549

1650
/** Gets a class defined in this module/class. */
17-
Class getAClass() { result = this.getAStmt() }
51+
ClassDeclaration getAClass() { result = this.getAStmt() }
1852

1953
/** Gets the class named `name` in this module/class, if any. */
20-
Class getClass(string name) { result = this.getAClass() and result.getName() = name }
54+
ClassDeclaration getClass(string name) { result = this.getAClass() and result.getName() = name }
2155

2256
/** Gets a module defined in this module/class. */
23-
Module getAModule() { result = this.getAStmt() }
57+
ModuleDeclaration getAModule() { result = this.getAStmt() }
2458

2559
/** Gets the module named `name` in this module/class, if any. */
26-
Module getModule(string name) { result = this.getAModule() and result.getName() = name }
60+
ModuleDeclaration getModule(string name) {
61+
result = this.getAModule() and result.getName() = name
62+
}
63+
64+
/** Gets the representation of the run-time value of this module or class. */
65+
Module getModule() { none() }
2766
}
2867

2968
/**
@@ -62,6 +101,8 @@ class Toplevel extends ModuleBase, TToplevel {
62101
pred = "getBeginBlock" and result = this.getBeginBlock(_)
63102
}
64103

104+
final override Module getModule() { result = TResolved("Object") }
105+
65106
final override string toString() { result = g.getLocation().getFile().getBaseName() }
66107
}
67108

@@ -132,6 +173,12 @@ class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace {
132173
*/
133174
override predicate hasGlobalScope() { none() }
134175

176+
final override Module getModule() {
177+
result = any(string qName | qName = namespaceDeclaration(this) | TResolved(qName))
178+
or
179+
result = TUnresolved(this)
180+
}
181+
135182
override AstNode getAChild(string pred) {
136183
result = ModuleBase.super.getAChild(pred) or
137184
result = ConstantWriteAccess.super.getAChild(pred)
@@ -150,12 +197,12 @@ class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace {
150197
* end
151198
* ```
152199
*/
153-
class Class extends Namespace, TClass {
200+
class ClassDeclaration extends Namespace, TClassDeclaration {
154201
private Generated::Class g;
155202

156-
Class() { this = TClass(g) }
203+
ClassDeclaration() { this = TClassDeclaration(g) }
157204

158-
final override string getAPrimaryQlClass() { result = "Class" }
205+
final override string getAPrimaryQlClass() { result = "ClassDeclaration" }
159206

160207
/**
161208
* Gets the `Expr` used as the superclass in the class definition, if any.
@@ -214,7 +261,7 @@ class SingletonClass extends ModuleBase, TSingletonClass {
214261

215262
SingletonClass() { this = TSingletonClass(g) }
216263

217-
final override string getAPrimaryQlClass() { result = "Class" }
264+
final override string getAPrimaryQlClass() { result = "ClassDeclaration" }
218265

219266
/**
220267
* Gets the expression resulting in the object on which the singleton class
@@ -249,7 +296,7 @@ class SingletonClass extends ModuleBase, TSingletonClass {
249296
* N.B. this class represents a single instance of a module definition. In the
250297
* following example, classes `Bar` and `Baz` are both defined in the module
251298
* `Foo`, but in two syntactically distinct definitions, meaning that there
252-
* will be two instances of `Module` in the database.
299+
* will be two instances of `ModuleDeclaration` in the database.
253300
*
254301
* ```rb
255302
* module Foo
@@ -261,12 +308,12 @@ class SingletonClass extends ModuleBase, TSingletonClass {
261308
* end
262309
* ```
263310
*/
264-
class Module extends Namespace, TModule {
311+
class ModuleDeclaration extends Namespace, TModuleDeclaration {
265312
private Generated::Module g;
266313

267-
Module() { this = TModule(g) }
314+
ModuleDeclaration() { this = TModuleDeclaration(g) }
268315

269-
final override string getAPrimaryQlClass() { result = "Module" }
316+
final override string getAPrimaryQlClass() { result = "ModuleDeclaration" }
270317

271318
final override string getName() {
272319
result = g.getName().(Generated::Token).getValue() or

ql/src/codeql_ruby/ast/Scope.qll

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ class Scope extends AstNode, TScopeType {
88

99
Scope() { range = toGenerated(this) }
1010

11-
/** Gets the enclosing module, if any. */
12-
ModuleBase getEnclosingModule() { toGenerated(result) = range.getEnclosingModule() }
13-
14-
/** Gets the enclosing method, if any. */
15-
MethodBase getEnclosingMethod() { toGenerated(result) = range.getEnclosingMethod() }
16-
1711
/** Gets the scope in which this scope is nested, if any. */
1812
Scope getOuterScope() { toGenerated(result) = range.getOuterScope() }
1913

ql/src/codeql_ruby/ast/internal/AST.qll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private module Cached {
8282
TCaseEqExpr(Generated::Binary g) { g instanceof @binary_equalequalequal } or
8383
TCaseExpr(Generated::Case g) or
8484
TCharacterLiteral(Generated::Character g) or
85-
TClass(Generated::Class g) or
85+
TClassDeclaration(Generated::Class g) or
8686
TClassVariableAccess(Generated::ClassVariable g, AST::ClassVariable v) {
8787
ClassVariableAccess::range(g, v)
8888
} or
@@ -139,7 +139,7 @@ private module Cached {
139139
} or
140140
TLogicalOrExpr(Generated::Binary g) { g instanceof @binary_or or g instanceof @binary_pipepipe } or
141141
TMethod(Generated::Method g) or
142-
TModule(Generated::Module g) or
142+
TModuleDeclaration(Generated::Module g) or
143143
TModuloExpr(Generated::Binary g) { g instanceof @binary_percent } or
144144
TMulExpr(Generated::Binary g) { g instanceof @binary_star } or
145145
TNEExpr(Generated::Binary g) { g instanceof @binary_bangequal } or
@@ -257,7 +257,7 @@ private module Cached {
257257
n = TCaseEqExpr(result) or
258258
n = TCaseExpr(result) or
259259
n = TCharacterLiteral(result) or
260-
n = TClass(result) or
260+
n = TClassDeclaration(result) or
261261
n = TClassVariableAccess(result, _) or
262262
n = TComplementExpr(result) or
263263
n = TComplexLiteral(result) or
@@ -302,7 +302,7 @@ private module Cached {
302302
n = TLogicalAndExpr(result) or
303303
n = TLogicalOrExpr(result) or
304304
n = TMethod(result) or
305-
n = TModule(result) or
305+
n = TModuleDeclaration(result) or
306306
n = TModuloExpr(result) or
307307
n = TMulExpr(result) or
308308
n = TNEExpr(result) or
@@ -434,7 +434,7 @@ class TBlock = TDoBlock or TBraceBlock;
434434

435435
class TModuleBase = TToplevel or TNamespace or TSingletonClass;
436436

437-
class TNamespace = TClass or TModule;
437+
class TNamespace = TClassDeclaration or TModuleDeclaration;
438438

439439
class TOperation = TUnaryOperation or TBinaryOperation or TAssignment;
440440

0 commit comments

Comments
 (0)