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.
This commit is contained in:
Harry Maclean
2022-02-03 11:35:59 +13:00
parent b01f81aab3
commit 704b58519f
4 changed files with 35 additions and 3 deletions

View File

@@ -88,12 +88,14 @@ module API {
* This predicate may have multiple results when there are multiple constructor calls invoking this API component.
* Consider using `getAnInstantiation()` if there is a need to distinguish between individual constructor calls.
*/
Node getInstance() { result = this.getASuccessor(Label::instance()) }
Node getInstance() { result = this.getASubclass().getASuccessor(Label::instance()) }
/**
* Gets a node representing the result of calling a method on the receiver represented by this node.
*/
Node getReturn(string method) { result = this.getASuccessor(Label::return(method)) }
Node getReturn(string method) {
result = this.getASubclass().getASuccessor(Label::return(method))
}
/**
* Gets a `new` call to the function represented by this API component.

View File

@@ -0,0 +1,6 @@
classMethodCalls
| test1.rb:58:1:58:8 | Use getMember("M1").getMember("C1").getReturn("m") |
| test1.rb:59:1:59:8 | Use getMember("M2").getMember("C3").getReturn("m") |
instanceMethodCalls
| test1.rb:61:1:61:12 | Use getMember("M1").getMember("C1").instance.getReturn("m") |
| test1.rb:62:1:62:12 | Use getMember("M2").getMember("C3").instance.getReturn("m") |

View File

@@ -0,0 +1,13 @@
/**
* Tests of the public API of API Graphs
*/
import codeql.ruby.ApiGraphs
query predicate classMethodCalls(API::Node node) {
node = API::getTopLevelMember("M1").getMember("C1").getReturn("m")
}
query predicate instanceMethodCalls(API::Node node) {
node = API::getTopLevelMember("M1").getMember("C1").getInstance().getReturn("m")
}

View File

@@ -32,6 +32,11 @@ Outer::Inner.foo #$ use=getMember("Outer").getMember("Inner").getReturn("foo")
module M1
class C1
def self.m
end
def m
end
end
end
@@ -48,4 +53,10 @@ end
C2 #$ use=getMember("C2") use=getMember("M1").getMember("C1").getASubclass()
M2::C3 #$ use=getMember("M2").getMember("C3") use=getMember("M1").getMember("C1").getASubclass()
M2::C4 #$ use=getMember("M2").getMember("C4") use=getMember("C2").getASubclass() use=getMember("M1").getMember("C1").getASubclass().getASubclass()
M2::C4 #$ use=getMember("M2").getMember("C4") use=getMember("C2").getASubclass() use=getMember("M1").getMember("C1").getASubclass().getASubclass()
M1::C1.m #$ use=getMember("M1").getMember("C1").getReturn("m")
M2::C3.m #$ use=getMember("M2").getMember("C3").getReturn("m") use=getMember("M1").getMember("C1").getASubclass().getReturn("m")
M1::C1.new.m #$ use=getMember("M1").getMember("C1").instance.getReturn("m")
M2::C3.new.m #$ use=getMember("M2").getMember("C3").instance.getReturn("m")