Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions ruby/ql/src/utils/modeleditor/FrameworkModeAccessPaths.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* @name Fetch a subset of valid access paths of input and output parameters of a method (framework mode).
* @description A list of access paths for input and output parameters of a method. Excludes test and generated code.
* @kind table
* @id ruby/utils/modeleditor/framework-mode-access-paths
* @tags modeleditor access-paths framework-mode
*/

private import ruby
private import codeql.ruby.AST
private import codeql.ruby.ApiGraphs
private import queries.modeling.internal.Util as Util

predicate simpleParameters(string type, string path, string value, DataFlow::Node node) {
exists(DataFlow::MethodNode methodNode, DataFlow::ParameterNode paramNode |
methodNode.getLocation().getFile() instanceof Util::RelevantFile and
(
// Check that this parameter belongs to this method
// Block parameter explicitly excluded because it's already included
// as part of the blockArguments predicate
paramNode = Util::getAnyParameter(methodNode) and
paramNode != methodNode.getBlockParameter()
)
|
Util::pathToMethod(methodNode, type, path) and
value = Util::getArgumentPath(paramNode) and
node = paramNode
)
}

predicate blockArguments(string type, string path, string value, DataFlow::Node node) {
exists(DataFlow::MethodNode methodNode, DataFlow::CallNode callNode |
methodNode.getLocation().getFile() instanceof Util::RelevantFile and
callNode = methodNode.getABlockCall()
|
(
exists(DataFlow::VariableAccessNode argNode, int i |
argNode = callNode.getPositionalArgument(i)
|
value = "Argument[block].Parameter[" + i + "]" and
node = argNode
)
or
exists(DataFlow::ExprNode argNode, string keyword |
argNode = callNode.getKeywordArgument(keyword)
|
value = "Argument[block].Parameter[" + keyword + ":]" and
node = argNode
)
or
value = "Argument[block]" and
node = callNode
) and
Util::pathToMethod(methodNode, type, path)
)
}

predicate returnValue(string type, string path, string value, DataFlow::Node node) {
exists(DataFlow::MethodNode methodNode, DataFlow::Node returnNode |
methodNode.getLocation().getFile() instanceof Util::RelevantFile and
returnNode = methodNode.getAReturnNode()
|
Util::pathToMethod(methodNode, type, path) and
value = "ReturnValue" and
node = returnNode
)
}

predicate inputAccessPaths(
string type, string path, string value, DataFlow::Node node, string defType
) {
simpleParameters(type, path, value, node) and defType = "parameter"
or
blockArguments(type, path, value, node) and defType = "parameter"
}

predicate outputAccessPaths(
string type, string path, string value, DataFlow::Node node, string defType
) {
simpleParameters(type, path, value, node) and defType = "parameter"
or
blockArguments(type, path, value, node) and defType = "parameter"
or
returnValue(type, path, value, node) and defType = "return"
}

query predicate input = inputAccessPaths/5;

query predicate output = outputAccessPaths/5;
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
input
| A | Method[bar] | Argument[0] | lib/mylib.rb:13:11:13:11 | x | parameter |
| A | Method[bar] | Argument[self] | lib/mylib.rb:13:3:14:5 | self in bar | parameter |
| A | Method[foo] | Argument[0] | lib/mylib.rb:7:11:7:11 | x | parameter |
| A | Method[foo] | Argument[1] | lib/mylib.rb:7:14:7:14 | y | parameter |
| A | Method[foo] | Argument[2] | lib/mylib.rb:7:17:7:20 | key1 | parameter |
| A | Method[foo] | Argument[block] | lib/mylib.rb:8:5:8:32 | call to call | parameter |
| A | Method[foo] | Argument[block] | lib/mylib.rb:10:5:10:26 | yield ... | parameter |
| A | Method[foo] | Argument[block].Parameter[0] | lib/mylib.rb:8:16:8:16 | x | parameter |
| A | Method[foo] | Argument[block].Parameter[0] | lib/mylib.rb:10:11:10:11 | x | parameter |
| A | Method[foo] | Argument[block].Parameter[1] | lib/mylib.rb:8:19:8:19 | y | parameter |
| A | Method[foo] | Argument[block].Parameter[1] | lib/mylib.rb:10:14:10:14 | y | parameter |
| A | Method[foo] | Argument[block].Parameter[key2:] | lib/mylib.rb:8:28:8:31 | key1 | parameter |
| A | Method[foo] | Argument[block].Parameter[key2:] | lib/mylib.rb:10:23:10:26 | key1 | parameter |
| A | Method[foo] | Argument[key1:] | lib/mylib.rb:7:17:7:20 | key1 | parameter |
| A | Method[foo] | Argument[self] | lib/mylib.rb:7:3:11:5 | self in foo | parameter |
| A! | Method[new] | Argument[0] | lib/mylib.rb:4:18:4:18 | x | parameter |
| A! | Method[new] | Argument[1] | lib/mylib.rb:4:21:4:21 | y | parameter |
| A! | Method[new] | Argument[self] | lib/mylib.rb:4:3:5:5 | self in initialize | parameter |
| A! | Method[self_foo] | Argument[0] | lib/mylib.rb:16:21:16:21 | x | parameter |
| A! | Method[self_foo] | Argument[1] | lib/mylib.rb:16:24:16:24 | y | parameter |
| A! | Method[self_foo] | Argument[self] | lib/mylib.rb:16:3:17:5 | self in self_foo | parameter |
| A::ANested | Method[foo] | Argument[0] | lib/mylib.rb:25:13:25:13 | x | parameter |
| A::ANested | Method[foo] | Argument[1] | lib/mylib.rb:25:16:25:16 | y | parameter |
| A::ANested | Method[foo] | Argument[self] | lib/mylib.rb:25:5:26:7 | self in foo | parameter |
| B | Method[foo] | Argument[0] | lib/other.rb:6:11:6:11 | x | parameter |
| B | Method[foo] | Argument[1] | lib/other.rb:6:14:6:14 | y | parameter |
| B | Method[foo] | Argument[self] | lib/other.rb:6:3:7:5 | self in foo | parameter |
| M1 | Method[foo] | Argument[0] | lib/module.rb:2:11:2:11 | x | parameter |
| M1 | Method[foo] | Argument[1] | lib/module.rb:2:14:2:14 | y | parameter |
| M1 | Method[foo] | Argument[self] | lib/module.rb:2:3:3:5 | self in foo | parameter |
| M1! | Method[self_foo] | Argument[0] | lib/module.rb:5:21:5:21 | x | parameter |
| M1! | Method[self_foo] | Argument[1] | lib/module.rb:5:24:5:24 | y | parameter |
| M1! | Method[self_foo] | Argument[self] | lib/module.rb:5:3:6:5 | self in self_foo | parameter |
| OtherLib::A | Method[foo] | Argument[0] | other_lib/lib/other_gem.rb:3:17:3:17 | x | parameter |
| OtherLib::A | Method[foo] | Argument[1] | other_lib/lib/other_gem.rb:3:20:3:20 | y | parameter |
| OtherLib::A | Method[foo] | Argument[self] | other_lib/lib/other_gem.rb:3:9:4:11 | self in foo | parameter |
output
| A | Method[bar] | Argument[0] | lib/mylib.rb:13:11:13:11 | x | parameter |
| A | Method[bar] | Argument[self] | lib/mylib.rb:13:3:14:5 | self in bar | parameter |
| A | Method[foo] | Argument[0] | lib/mylib.rb:7:11:7:11 | x | parameter |
| A | Method[foo] | Argument[1] | lib/mylib.rb:7:14:7:14 | y | parameter |
| A | Method[foo] | Argument[2] | lib/mylib.rb:7:17:7:20 | key1 | parameter |
| A | Method[foo] | Argument[block] | lib/mylib.rb:8:5:8:32 | call to call | parameter |
| A | Method[foo] | Argument[block] | lib/mylib.rb:10:5:10:26 | yield ... | parameter |
| A | Method[foo] | Argument[block].Parameter[0] | lib/mylib.rb:8:16:8:16 | x | parameter |
| A | Method[foo] | Argument[block].Parameter[0] | lib/mylib.rb:10:11:10:11 | x | parameter |
| A | Method[foo] | Argument[block].Parameter[1] | lib/mylib.rb:8:19:8:19 | y | parameter |
| A | Method[foo] | Argument[block].Parameter[1] | lib/mylib.rb:10:14:10:14 | y | parameter |
| A | Method[foo] | Argument[block].Parameter[key2:] | lib/mylib.rb:8:28:8:31 | key1 | parameter |
| A | Method[foo] | Argument[block].Parameter[key2:] | lib/mylib.rb:10:23:10:26 | key1 | parameter |
| A | Method[foo] | Argument[key1:] | lib/mylib.rb:7:17:7:20 | key1 | parameter |
| A | Method[foo] | Argument[self] | lib/mylib.rb:7:3:11:5 | self in foo | parameter |
| A | Method[foo] | ReturnValue | lib/mylib.rb:10:5:10:26 | yield ... | return |
| A! | Method[new] | Argument[0] | lib/mylib.rb:4:18:4:18 | x | parameter |
| A! | Method[new] | Argument[1] | lib/mylib.rb:4:21:4:21 | y | parameter |
| A! | Method[new] | Argument[self] | lib/mylib.rb:4:3:5:5 | self in initialize | parameter |
| A! | Method[self_foo] | Argument[0] | lib/mylib.rb:16:21:16:21 | x | parameter |
| A! | Method[self_foo] | Argument[1] | lib/mylib.rb:16:24:16:24 | y | parameter |
| A! | Method[self_foo] | Argument[self] | lib/mylib.rb:16:3:17:5 | self in self_foo | parameter |
| A::ANested | Method[foo] | Argument[0] | lib/mylib.rb:25:13:25:13 | x | parameter |
| A::ANested | Method[foo] | Argument[1] | lib/mylib.rb:25:16:25:16 | y | parameter |
| A::ANested | Method[foo] | Argument[self] | lib/mylib.rb:25:5:26:7 | self in foo | parameter |
| B | Method[foo] | Argument[0] | lib/other.rb:6:11:6:11 | x | parameter |
| B | Method[foo] | Argument[1] | lib/other.rb:6:14:6:14 | y | parameter |
| B | Method[foo] | Argument[self] | lib/other.rb:6:3:7:5 | self in foo | parameter |
| M1 | Method[foo] | Argument[0] | lib/module.rb:2:11:2:11 | x | parameter |
| M1 | Method[foo] | Argument[1] | lib/module.rb:2:14:2:14 | y | parameter |
| M1 | Method[foo] | Argument[self] | lib/module.rb:2:3:3:5 | self in foo | parameter |
| M1! | Method[self_foo] | Argument[0] | lib/module.rb:5:21:5:21 | x | parameter |
| M1! | Method[self_foo] | Argument[1] | lib/module.rb:5:24:5:24 | y | parameter |
| M1! | Method[self_foo] | Argument[self] | lib/module.rb:5:3:6:5 | self in self_foo | parameter |
| OtherLib::A | Method[foo] | Argument[0] | other_lib/lib/other_gem.rb:3:17:3:17 | x | parameter |
| OtherLib::A | Method[foo] | Argument[1] | other_lib/lib/other_gem.rb:3:20:3:20 | y | parameter |
| OtherLib::A | Method[foo] | Argument[self] | other_lib/lib/other_gem.rb:3:9:4:11 | self in foo | parameter |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
utils/modeleditor/FrameworkModeAccessPaths.ql
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
| lib/module.rb:1:1:7:3 | M1 | mylib | M1 | | | false | module.rb | |
| lib/module.rb:2:3:3:5 | foo | mylib | M1 | foo | (x,y) | false | module.rb | |
| lib/module.rb:5:3:6:5 | self_foo | mylib | M1! | self_foo | (x,y) | false | module.rb | |
| lib/mylib.rb:3:1:30:3 | A | mylib | A | | | false | mylib.rb | |
| lib/mylib.rb:3:1:33:3 | A | mylib | A | | | false | mylib.rb | |
| lib/mylib.rb:4:3:5:5 | initialize | mylib | A! | new | (x,y) | false | mylib.rb | |
| lib/mylib.rb:7:3:8:5 | foo | mylib | A | foo | (x,y,key1:) | false | mylib.rb | |
| lib/mylib.rb:10:3:11:5 | bar | mylib | A | bar | (x) | false | mylib.rb | |
| lib/mylib.rb:13:3:14:5 | self_foo | mylib | A! | self_foo | (x,y) | false | mylib.rb | |
| lib/mylib.rb:21:3:29:5 | ANested | mylib | A::ANested | | | false | mylib.rb | |
| lib/mylib.rb:22:5:23:7 | foo | mylib | A::ANested | foo | (x,y) | false | mylib.rb | |
| lib/mylib.rb:7:3:11:5 | foo | mylib | A | foo | (x,y,key1:) | false | mylib.rb | |
| lib/mylib.rb:13:3:14:5 | bar | mylib | A | bar | (x) | false | mylib.rb | |
| lib/mylib.rb:16:3:17:5 | self_foo | mylib | A! | self_foo | (x,y) | false | mylib.rb | |
| lib/mylib.rb:24:3:32:5 | ANested | mylib | A::ANested | | | false | mylib.rb | |
| lib/mylib.rb:25:5:26:7 | foo | mylib | A::ANested | foo | (x,y) | false | mylib.rb | |
| lib/other.rb:3:1:8:3 | B | mylib | B | | | false | other.rb | |
| lib/other.rb:6:3:7:5 | foo | mylib | B | foo | (x,y) | false | other.rb | |
| lib/other.rb:10:1:12:3 | C | mylib | C | | | false | other.rb | |
Expand Down
3 changes: 3 additions & 0 deletions ruby/ql/test/query-tests/utils/modeleditor/lib/mylib.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ def initialize(x, y)
end

def foo(x, y, key1:, **kwargs, &block)
block.call(x, y, key2: key1)

yield x, y, key2: key1
end

def bar(x, *args)
Expand Down