Skip to content

Commit 84ae17d

Browse files
committed
Ruby: ensure Object is a transitive superclass
1 parent 3fd2b9a commit 84ae17d

File tree

7 files changed

+44
-10
lines changed

7 files changed

+44
-10
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ class Module extends TModule {
2525

2626
/** Holds if this module is a class. */
2727
pragma[noinline]
28-
predicate isClass() { this.getADeclaration() instanceof ClassDeclaration }
28+
predicate isClass() {
29+
this.getADeclaration() instanceof ClassDeclaration
30+
or
31+
// If another class extends this, but we can't see the class declaration, assume it's a class
32+
getSuperClass(_) = this
33+
}
2934

3035
/** Gets a textual representation of this module. */
3136
string toString() {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ private module Cached {
6565
forex(ClassDeclaration d | d = cls.getADeclaration() |
6666
not exists(resolveConstantReadAccess(d.getSuperclassExpr()))
6767
)
68+
or
69+
// If a module is used as a base class of another class, but we don't see its class declaration
70+
// treat it as a class extending Object, so its subclasses transitively extend Object.
71+
result = TResolved("Object") and
72+
not cls.getADeclaration() instanceof ClassDeclaration and
73+
cls = resolveConstantReadAccess(any(ClassDeclaration d).getSuperclassExpr())
6874
)
6975
}
7076

ruby/ql/test/library-tests/modules/ancestors.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,6 @@ unresolved_subclass.rb:
257257

258258
# 7| UnresolvedNamespace::Subclass2
259259
#-----| super -> UnresolvedNamespace::Subclass1
260+
261+
# 11| UnresolvedNamespace::A
262+
#-----| super -> Object

ruby/ql/test/library-tests/modules/methods.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,9 @@ lookupMethod
608608
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | new | calls.rb:117:5:117:16 | new |
609609
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | puts | calls.rb:102:5:102:30 | puts |
610610
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | to_s | calls.rb:172:5:173:7 | to_s |
611+
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | new | calls.rb:117:5:117:16 | new |
612+
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | puts | calls.rb:102:5:102:30 | puts |
613+
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | to_s | calls.rb:172:5:173:7 | to_s |
611614
enclosingMethod
612615
| calls.rb:2:5:2:14 | call to puts | calls.rb:1:1:3:3 | foo |
613616
| calls.rb:2:5:2:14 | self | calls.rb:1:1:3:3 | foo |

ruby/ql/test/library-tests/modules/modules.expected

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ getModule
9292
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass |
9393
| unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 |
9494
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 |
95+
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A |
9596
getADeclaration
9697
| calls.rb:21:1:34:3 | M | calls.rb:21:1:34:3 | M |
9798
| calls.rb:43:1:58:3 | C | calls.rb:43:1:58:3 | C |
@@ -108,7 +109,7 @@ getADeclaration
108109
| calls.rb:115:1:118:3 | Object | modules_rec.rb:1:1:11:26 | modules_rec.rb |
109110
| calls.rb:115:1:118:3 | Object | private.rb:1:1:105:40 | private.rb |
110111
| calls.rb:115:1:118:3 | Object | toplevel_self_singleton.rb:1:1:34:4 | toplevel_self_singleton.rb |
111-
| calls.rb:115:1:118:3 | Object | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
112+
| calls.rb:115:1:118:3 | Object | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
112113
| calls.rb:120:1:123:3 | Hash | calls.rb:120:1:123:3 | Hash |
113114
| calls.rb:125:1:138:3 | Array | calls.rb:125:1:138:3 | Array |
114115
| calls.rb:165:1:169:3 | S | calls.rb:165:1:169:3 | S |
@@ -187,6 +188,7 @@ getADeclaration
187188
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass |
188189
| unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 | unresolved_subclass.rb:4:1:5:3 | Subclass1 |
189190
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | unresolved_subclass.rb:7:1:8:3 | Subclass2 |
191+
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | unresolved_subclass.rb:11:1:12:3 | A |
190192
getSuperClass
191193
| calls.rb:43:1:58:3 | C | calls.rb:115:1:118:3 | Object |
192194
| calls.rb:65:1:69:3 | D | calls.rb:43:1:58:3 | C |
@@ -245,6 +247,7 @@ getSuperClass
245247
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | calls.rb:115:1:118:3 | Object |
246248
| unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 | unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass |
247249
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 |
250+
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | calls.rb:115:1:118:3 | Object |
248251
getAPrependedModule
249252
| calls.rb:115:1:118:3 | Object | calls.rb:171:1:174:3 | A |
250253
| calls.rb:171:1:174:3 | A | toplevel_self_singleton.rb:2:5:5:7 | A::B |
@@ -398,6 +401,8 @@ resolveConstantReadAccess
398401
| unresolved_subclass.rb:7:7:7:25 | UnresolvedNamespace | UnresolvedNamespace |
399402
| unresolved_subclass.rb:7:40:7:58 | UnresolvedNamespace | UnresolvedNamespace |
400403
| unresolved_subclass.rb:7:40:7:69 | Subclass1 | UnresolvedNamespace::Subclass1 |
404+
| unresolved_subclass.rb:11:7:11:25 | UnresolvedNamespace | UnresolvedNamespace |
405+
| unresolved_subclass.rb:11:32:11:50 | UnresolvedNamespace | UnresolvedNamespace |
401406
resolveConstantWriteAccess
402407
| calls.rb:21:1:34:3 | M | M |
403408
| calls.rb:43:1:58:3 | C | C |
@@ -497,6 +502,7 @@ resolveConstantWriteAccess
497502
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | ResolvableBaseClass |
498503
| unresolved_subclass.rb:4:1:5:3 | Subclass1 | UnresolvedNamespace::Subclass1 |
499504
| unresolved_subclass.rb:7:1:8:3 | Subclass2 | UnresolvedNamespace::Subclass2 |
505+
| unresolved_subclass.rb:11:1:12:3 | A | UnresolvedNamespace::A |
500506
enclosingModule
501507
| calls.rb:1:1:3:3 | foo | calls.rb:1:1:616:32 | calls.rb |
502508
| calls.rb:2:5:2:14 | call to puts | calls.rb:1:1:616:32 | calls.rb |
@@ -1820,11 +1826,15 @@ enclosingModule
18201826
| toplevel_self_singleton.rb:30:13:30:19 | self | toplevel_self_singleton.rb:25:5:33:7 | class << ... |
18211827
| toplevel_self_singleton.rb:31:13:31:20 | call to call_you | toplevel_self_singleton.rb:25:5:33:7 | class << ... |
18221828
| toplevel_self_singleton.rb:31:13:31:20 | self | toplevel_self_singleton.rb:25:5:33:7 | class << ... |
1823-
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1824-
| unresolved_subclass.rb:4:1:5:3 | Subclass1 | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1825-
| unresolved_subclass.rb:4:7:4:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1826-
| unresolved_subclass.rb:4:40:4:58 | ResolvableBaseClass | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1827-
| unresolved_subclass.rb:7:1:8:3 | Subclass2 | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1828-
| unresolved_subclass.rb:7:7:7:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1829-
| unresolved_subclass.rb:7:40:7:58 | UnresolvedNamespace | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1830-
| unresolved_subclass.rb:7:40:7:69 | Subclass1 | unresolved_subclass.rb:1:1:8:4 | unresolved_subclass.rb |
1829+
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1830+
| unresolved_subclass.rb:4:1:5:3 | Subclass1 | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1831+
| unresolved_subclass.rb:4:7:4:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1832+
| unresolved_subclass.rb:4:40:4:58 | ResolvableBaseClass | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1833+
| unresolved_subclass.rb:7:1:8:3 | Subclass2 | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1834+
| unresolved_subclass.rb:7:7:7:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1835+
| unresolved_subclass.rb:7:40:7:58 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1836+
| unresolved_subclass.rb:7:40:7:69 | Subclass1 | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1837+
| unresolved_subclass.rb:11:1:12:3 | A | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1838+
| unresolved_subclass.rb:11:7:11:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1839+
| unresolved_subclass.rb:11:32:11:50 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
1840+
| unresolved_subclass.rb:11:32:11:53 | B | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |

ruby/ql/test/library-tests/modules/superclasses.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,6 @@ unresolved_subclass.rb:
248248

249249
# 7| UnresolvedNamespace::Subclass2
250250
#-----| -> UnresolvedNamespace::Subclass1
251+
252+
# 11| UnresolvedNamespace::A
253+
#-----| -> Object

ruby/ql/test/library-tests/modules/unresolved_subclass.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ class UnresolvedNamespace::Subclass1 < ResolvableBaseClass
66

77
class UnresolvedNamespace::Subclass2 < UnresolvedNamespace::Subclass1
88
end
9+
10+
# Ensure Object is a transitive superclass of this
11+
class UnresolvedNamespace::A < UnresolvedNamespace::B
12+
end

0 commit comments

Comments
 (0)