Skip to content

Commit 704b585

Browse files
committed
Ruby: Include subclasses in more API calls
Change the behaviour of `API::getInstance()` and `API::getReturn()` to include results on subclasses of the current API node.
1 parent b01f81a commit 704b585

File tree

4 files changed

+35
-3
lines changed

4 files changed

+35
-3
lines changed

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,14 @@ module API {
8888
* This predicate may have multiple results when there are multiple constructor calls invoking this API component.
8989
* Consider using `getAnInstantiation()` if there is a need to distinguish between individual constructor calls.
9090
*/
91-
Node getInstance() { result = this.getASuccessor(Label::instance()) }
91+
Node getInstance() { result = this.getASubclass().getASuccessor(Label::instance()) }
9292

9393
/**
9494
* Gets a node representing the result of calling a method on the receiver represented by this node.
9595
*/
96-
Node getReturn(string method) { result = this.getASuccessor(Label::return(method)) }
96+
Node getReturn(string method) {
97+
result = this.getASubclass().getASuccessor(Label::return(method))
98+
}
9799

98100
/**
99101
* Gets a `new` call to the function represented by this API component.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
classMethodCalls
2+
| test1.rb:58:1:58:8 | Use getMember("M1").getMember("C1").getReturn("m") |
3+
| test1.rb:59:1:59:8 | Use getMember("M2").getMember("C3").getReturn("m") |
4+
instanceMethodCalls
5+
| test1.rb:61:1:61:12 | Use getMember("M1").getMember("C1").instance.getReturn("m") |
6+
| test1.rb:62:1:62:12 | Use getMember("M2").getMember("C3").instance.getReturn("m") |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Tests of the public API of API Graphs
3+
*/
4+
5+
import codeql.ruby.ApiGraphs
6+
7+
query predicate classMethodCalls(API::Node node) {
8+
node = API::getTopLevelMember("M1").getMember("C1").getReturn("m")
9+
}
10+
11+
query predicate instanceMethodCalls(API::Node node) {
12+
node = API::getTopLevelMember("M1").getMember("C1").getInstance().getReturn("m")
13+
}

ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ module Inner
3232

3333
module M1
3434
class C1
35+
def self.m
36+
end
37+
38+
def m
39+
end
3540
end
3641
end
3742

@@ -48,4 +53,10 @@ class C4 < C2 #$ use=getMember("C2")
4853

4954
C2 #$ use=getMember("C2") use=getMember("M1").getMember("C1").getASubclass()
5055
M2::C3 #$ use=getMember("M2").getMember("C3") use=getMember("M1").getMember("C1").getASubclass()
51-
M2::C4 #$ use=getMember("M2").getMember("C4") use=getMember("C2").getASubclass() use=getMember("M1").getMember("C1").getASubclass().getASubclass()
56+
M2::C4 #$ use=getMember("M2").getMember("C4") use=getMember("C2").getASubclass() use=getMember("M1").getMember("C1").getASubclass().getASubclass()
57+
58+
M1::C1.m #$ use=getMember("M1").getMember("C1").getReturn("m")
59+
M2::C3.m #$ use=getMember("M2").getMember("C3").getReturn("m") use=getMember("M1").getMember("C1").getASubclass().getReturn("m")
60+
61+
M1::C1.new.m #$ use=getMember("M1").getMember("C1").instance.getReturn("m")
62+
M2::C3.new.m #$ use=getMember("M2").getMember("C3").instance.getReturn("m")

0 commit comments

Comments
 (0)