mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
Merge pull request #7663 from github/hmac/api-graph-subclass
Ruby: Add basic subclassing support to API Graphs
This commit is contained in:
@@ -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") |
|
||||
13
ruby/ql/test/library-tests/dataflow/api-graphs/ApiGraphs.ql
Normal file
13
ruby/ql/test/library-tests/dataflow/api-graphs/ApiGraphs.ql
Normal 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")
|
||||
}
|
||||
@@ -29,3 +29,34 @@ module Outer
|
||||
end
|
||||
|
||||
Outer::Inner.foo #$ use=getMember("Outer").getMember("Inner").getReturn("foo")
|
||||
|
||||
module M1
|
||||
class C1
|
||||
def self.m
|
||||
end
|
||||
|
||||
def m
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class C2 < M1::C1 #$ use=getMember("M1").getMember("C1")
|
||||
end
|
||||
|
||||
module M2
|
||||
class C3 < M1::C1 #$ use=getMember("M1").getMember("C1")
|
||||
end
|
||||
|
||||
class C4 < C2 #$ use=getMember("C2")
|
||||
end
|
||||
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()
|
||||
|
||||
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")
|
||||
|
||||
@@ -30,6 +30,38 @@ class ApiUseTest extends InlineExpectationsTest {
|
||||
element = n.toString()
|
||||
)
|
||||
}
|
||||
|
||||
// We also permit optional annotations for any other path on the line.
|
||||
// This is used to test subclass paths, which typically have a shorter canonical path.
|
||||
override predicate hasOptionalResult(Location location, string element, string tag, string value) {
|
||||
exists(API::Node a, DataFlow::Node n | relevantNode(a, n, location) |
|
||||
tag = "use" and
|
||||
element = n.toString() and
|
||||
value = getAPath(a, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private int size(AstNode n) { not n instanceof StmtSequence and result = count(n.getAChild*()) }
|
||||
|
||||
/**
|
||||
* Gets a path of the given `length` from the root to the given node.
|
||||
* This is a copy of `API::getAPath()` without the restriction on path length,
|
||||
* which would otherwise rule out paths involving `getASubclass()`.
|
||||
*/
|
||||
string getAPath(API::Node node, int length) {
|
||||
node instanceof API::Root and
|
||||
length = 0 and
|
||||
result = ""
|
||||
or
|
||||
exists(API::Node pred, string lbl, string predpath |
|
||||
pred.getASuccessor(lbl) = node and
|
||||
lbl != "" and
|
||||
predpath = getAPath(pred, length - 1) and
|
||||
exists(string dot | if length = 1 then dot = "" else dot = "." |
|
||||
result = predpath + dot + lbl and
|
||||
// avoid producing strings longer than 1MB
|
||||
result.length() < 1000 * 1000
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -93,4 +93,4 @@ class BazController < BarController
|
||||
def yet_another_handler
|
||||
Admin.delete_by(params[:admin_condition])
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user