Skip to content

Commit ce4d8d6

Browse files
authored
Merge pull request github#15490 from github/koesie10/ruby-model-constructor-on-new
Ruby: Model constructors in endpoint query on new instead of initialize
2 parents 1478709 + d5f0a5c commit ce4d8d6

File tree

3 files changed

+33
-8
lines changed

3 files changed

+33
-8
lines changed

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

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

6464
DataFlow::MethodNode getNode() { result = this }
6565

66-
override string getName() { result = super.getMethodName() }
66+
override string getName() {
67+
result = super.getMethodName() and not this.isConstructor()
68+
or
69+
// Constructors are modeled as Type!#new rather than Type#initialize
70+
result = "new" and this.isConstructor()
71+
}
6772

6873
/**
6974
* Gets the unbound type name of this endpoint.
7075
*/
7176
override string getType() {
7277
result =
73-
any(DataFlow::ModuleNode m | m.getOwnInstanceMethod(this.getName()) = this).getQualifiedName() or
78+
any(DataFlow::ModuleNode m | m.getOwnInstanceMethod(this.getName()) = this).getQualifiedName() and
79+
not this.isConstructor()
80+
or
81+
// Constructors are modeled on `Type!`, not on `Type`
82+
result =
83+
any(DataFlow::ModuleNode m | m.getOwnInstanceMethod(super.getMethodName()) = this)
84+
.getQualifiedName() + "!" and
85+
this.isConstructor()
86+
or
7487
result =
7588
any(DataFlow::ModuleNode m | m.getOwnSingletonMethod(this.getName()) = this)
7689
.getQualifiedName() + "!"
@@ -136,6 +149,14 @@ class MethodEndpoint extends Endpoint instanceof DataFlow::MethodNode {
136149
or
137150
not this.isSupported() and result = ""
138151
}
152+
153+
/**
154+
* Holds if this method is a constructor for a module.
155+
*/
156+
private predicate isConstructor() {
157+
super.getMethodName() = "initialize" and
158+
exists(DataFlow::ModuleNode m | m.getOwnInstanceMethod(super.getMethodName()) = this)
159+
}
139160
}
140161

141162
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)