Skip to content

Commit c1aaf5a

Browse files
committed
Ruby: Model constructors in endpoint query on new
1 parent 4b5a203 commit c1aaf5a

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

ruby/ql/src/utils/modeleditor/ModelEditor.qll

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,27 @@ class MethodEndpoint extends Endpoint instanceof DataFlow::MethodNode {
6868

6969
DataFlow::MethodNode getNode() { result = this }
7070

71-
override string getName() { result = super.getMethodName() }
71+
override string getName() {
72+
result = super.getMethodName() and this.isConstructor() = false
73+
or
74+
// Constructors are modeled as Type!#new rather than Type#initialize
75+
result = "new" and this.isConstructor() = true
76+
}
7277

7378
/**
7479
* Gets the unbound type name of this endpoint.
7580
*/
7681
override string getType() {
7782
result =
78-
any(DataFlow::ModuleNode m | m.getOwnInstanceMethod(this.getName()) = this).getQualifiedName() or
83+
any(DataFlow::ModuleNode m | m.getOwnInstanceMethod(this.getName()) = this).getQualifiedName() and
84+
this.isConstructor() = false
85+
or
86+
// Constructors are modeled on `Type!`, not on `Type`
87+
result =
88+
any(DataFlow::ModuleNode m | m.getOwnInstanceMethod(super.getMethodName()) = this)
89+
.getQualifiedName() + "!" and
90+
this.isConstructor() = true
91+
or
7992
result =
8093
any(DataFlow::ModuleNode m | m.getOwnSingletonMethod(this.getName()) = this)
8194
.getQualifiedName() + "!"
@@ -141,6 +154,17 @@ class MethodEndpoint extends Endpoint instanceof DataFlow::MethodNode {
141154
or
142155
not this.isSupported() and result = ""
143156
}
157+
158+
/**
159+
* Holds if this method is a constructor for a module.
160+
*/
161+
private boolean isConstructor() {
162+
if
163+
super.getMethodName() = "initialize" and
164+
exists(DataFlow::ModuleNode m | m.getOwnInstanceMethod(super.getMethodName()) = this)
165+
then result = true
166+
else result = false
167+
}
144168
}
145169

146170
string methodClassification(Call method) {

ruby/ql/test/query-tests/utils/modeleditor/FrameworkModeEndpoints.expected

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
| lib/module.rb:1:1:7:3 | M1 | mylib | M1 | | | false | module.rb | |
22
| lib/module.rb:2:3:3:5 | foo | mylib | M1 | foo | (x,y) | false | module.rb | |
33
| lib/module.rb:5:3:6:5 | self_foo | mylib | M1! | self_foo | (x,y) | false | module.rb | |
4-
| lib/mylib.rb:3:1:27:3 | A | mylib | A | | | false | mylib.rb | |
5-
| lib/mylib.rb:4:3:5:5 | foo | mylib | A | foo | (x,y,key1:) | false | mylib.rb | |
6-
| lib/mylib.rb:7:3:8:5 | bar | mylib | A | bar | (x) | false | mylib.rb | |
7-
| lib/mylib.rb:10:3:11:5 | self_foo | mylib | A! | self_foo | (x,y) | false | mylib.rb | |
8-
| lib/mylib.rb:18:3:26:5 | ANested | mylib | A::ANested | | | false | mylib.rb | |
9-
| lib/mylib.rb:19:5:20:7 | foo | mylib | A::ANested | foo | (x,y) | false | mylib.rb | |
4+
| lib/mylib.rb:3:1:30:3 | A | mylib | A | | | false | mylib.rb | |
5+
| lib/mylib.rb:4:3:5:5 | initialize | mylib | A! | new | (x,y) | false | mylib.rb | |
6+
| lib/mylib.rb:7:3:8:5 | foo | mylib | A | foo | (x,y,key1:) | false | mylib.rb | |
7+
| lib/mylib.rb:10:3:11:5 | bar | mylib | A | bar | (x) | false | mylib.rb | |
8+
| lib/mylib.rb:13:3:14:5 | self_foo | mylib | A! | self_foo | (x,y) | false | mylib.rb | |
9+
| lib/mylib.rb:21:3:29:5 | ANested | mylib | A::ANested | | | false | mylib.rb | |
10+
| lib/mylib.rb:22:5:23:7 | foo | mylib | A::ANested | foo | (x,y) | false | mylib.rb | |
1011
| lib/other.rb:3:1:8:3 | B | mylib | B | | | false | other.rb | |
1112
| lib/other.rb:6:3:7:5 | foo | mylib | B | foo | (x,y) | false | other.rb | |
1213
| lib/other.rb:10:1:12:3 | C | mylib | C | | | false | other.rb | |

ruby/ql/test/query-tests/utils/modeleditor/lib/mylib.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
require_relative "./other"
22

33
class A
4+
def initialize(x, y)
5+
end
6+
47
def foo(x, y, key1:, **kwargs, &block)
58
end
69

0 commit comments

Comments
 (0)