Skip to content

Commit 8853acb

Browse files
committed
Ruby: Add query for access paths in model editor
1 parent 73d0b7e commit 8853acb

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @name Fetch a subset of valid access paths of input and output parameters of a method (framework mode).
3+
* @description A list of access paths for input and output parameters of a method. Excludes test and generated code.
4+
* @kind table
5+
* @id ruby/utils/modeleditor/framework-mode-access-paths
6+
* @tags modeleditor access-paths framework-mode
7+
*/
8+
9+
private import ruby
10+
private import codeql.ruby.ApiGraphs
11+
private import queries.modeling.internal.Util as Util
12+
13+
predicate simpleParameters(string type, string path, string value, string details) {
14+
exists(DataFlow::MethodNode methodNode, DataFlow::ParameterNode paramNode |
15+
methodNode.getLocation().getFile() instanceof Util::RelevantFile and
16+
(
17+
// Check that this parameter belongs to this method
18+
// Block parameter explicitly excluded because it's already included
19+
// as part of the blockArguments predicate
20+
paramNode = Util::getAnyParameter(methodNode) and
21+
paramNode != methodNode.getBlockParameter()
22+
)
23+
|
24+
Util::pathToMethod(methodNode, type, path) and
25+
value = Util::getArgumentPath(paramNode) and
26+
details = paramNode.toString()
27+
)
28+
}
29+
30+
predicate blockArguments(string type, string path, string value, string details) {
31+
exists(DataFlow::MethodNode methodNode, DataFlow::CallNode callNode |
32+
methodNode.getLocation().getFile() instanceof Util::RelevantFile and
33+
callNode = methodNode.getABlockCall()
34+
|
35+
(
36+
exists(DataFlow::ExprNode argNode, int i | argNode = callNode.getPositionalArgument(i) |
37+
value = "Argument[block].Parameter[" + i + "]" and
38+
details = argNode.toString()
39+
)
40+
or
41+
exists(DataFlow::ExprNode argNode, string keyword |
42+
argNode = callNode.getKeywordArgument(keyword)
43+
|
44+
value = "Argument[block].Parameter[" + keyword + ":]" and
45+
details = ":" + keyword
46+
)
47+
or
48+
value = "Argument[block]" and details = callNode.toString()
49+
) and
50+
Util::pathToMethod(methodNode, type, path)
51+
)
52+
}
53+
54+
predicate returnValue(string type, string path, string value, string details) {
55+
exists(DataFlow::MethodNode methodNode, DataFlow::Node returnNode |
56+
methodNode.getLocation().getFile() instanceof Util::RelevantFile and
57+
returnNode = methodNode.getAReturnNode()
58+
|
59+
Util::pathToMethod(methodNode, type, path) and
60+
value = "ReturnValue" and
61+
details = returnNode.toString()
62+
)
63+
}
64+
65+
predicate inputSuggestions(string type, string path, string value, string details, string defType) {
66+
simpleParameters(type, path, value, details) and defType = "parameter"
67+
or
68+
blockArguments(type, path, value, details) and defType = "parameter"
69+
}
70+
71+
predicate outputSuggestions(string type, string path, string value, string details, string defType) {
72+
simpleParameters(type, path, value, details) and defType = "parameter"
73+
or
74+
blockArguments(type, path, value, details) and defType = "parameter"
75+
or
76+
returnValue(type, path, value, details) and defType = "return"
77+
}
78+
79+
query predicate input = inputSuggestions/5;
80+
81+
query predicate output = outputSuggestions/5;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
input
2+
| A | Method[bar] | Argument[0] | x | parameter |
3+
| A | Method[bar] | Argument[self] | self in bar | parameter |
4+
| A | Method[foo] | Argument[0] | x | parameter |
5+
| A | Method[foo] | Argument[1] | y | parameter |
6+
| A | Method[foo] | Argument[2] | key1 | parameter |
7+
| A | Method[foo] | Argument[key1:] | key1 | parameter |
8+
| A | Method[foo] | Argument[self] | self in foo | parameter |
9+
| A! | Method[new] | Argument[0] | x | parameter |
10+
| A! | Method[new] | Argument[1] | y | parameter |
11+
| A! | Method[new] | Argument[self] | self in initialize | parameter |
12+
| A! | Method[self_foo] | Argument[0] | x | parameter |
13+
| A! | Method[self_foo] | Argument[1] | y | parameter |
14+
| A! | Method[self_foo] | Argument[self] | self in self_foo | parameter |
15+
| A::ANested | Method[foo] | Argument[0] | x | parameter |
16+
| A::ANested | Method[foo] | Argument[1] | y | parameter |
17+
| A::ANested | Method[foo] | Argument[self] | self in foo | parameter |
18+
| B | Method[foo] | Argument[0] | x | parameter |
19+
| B | Method[foo] | Argument[1] | y | parameter |
20+
| B | Method[foo] | Argument[self] | self in foo | parameter |
21+
| M1 | Method[foo] | Argument[0] | x | parameter |
22+
| M1 | Method[foo] | Argument[1] | y | parameter |
23+
| M1 | Method[foo] | Argument[self] | self in foo | parameter |
24+
| M1! | Method[self_foo] | Argument[0] | x | parameter |
25+
| M1! | Method[self_foo] | Argument[1] | y | parameter |
26+
| M1! | Method[self_foo] | Argument[self] | self in self_foo | parameter |
27+
| OtherLib::A | Method[foo] | Argument[0] | x | parameter |
28+
| OtherLib::A | Method[foo] | Argument[1] | y | parameter |
29+
| OtherLib::A | Method[foo] | Argument[self] | self in foo | parameter |
30+
output
31+
| A | Method[bar] | Argument[0] | x | parameter |
32+
| A | Method[bar] | Argument[self] | self in bar | parameter |
33+
| A | Method[foo] | Argument[0] | x | parameter |
34+
| A | Method[foo] | Argument[1] | y | parameter |
35+
| A | Method[foo] | Argument[2] | key1 | parameter |
36+
| A | Method[foo] | Argument[key1:] | key1 | parameter |
37+
| A | Method[foo] | Argument[self] | self in foo | parameter |
38+
| A! | Method[new] | Argument[0] | x | parameter |
39+
| A! | Method[new] | Argument[1] | y | parameter |
40+
| A! | Method[new] | Argument[self] | self in initialize | parameter |
41+
| A! | Method[self_foo] | Argument[0] | x | parameter |
42+
| A! | Method[self_foo] | Argument[1] | y | parameter |
43+
| A! | Method[self_foo] | Argument[self] | self in self_foo | parameter |
44+
| A::ANested | Method[foo] | Argument[0] | x | parameter |
45+
| A::ANested | Method[foo] | Argument[1] | y | parameter |
46+
| A::ANested | Method[foo] | Argument[self] | self in foo | parameter |
47+
| B | Method[foo] | Argument[0] | x | parameter |
48+
| B | Method[foo] | Argument[1] | y | parameter |
49+
| B | Method[foo] | Argument[self] | self in foo | parameter |
50+
| M1 | Method[foo] | Argument[0] | x | parameter |
51+
| M1 | Method[foo] | Argument[1] | y | parameter |
52+
| M1 | Method[foo] | Argument[self] | self in foo | parameter |
53+
| M1! | Method[self_foo] | Argument[0] | x | parameter |
54+
| M1! | Method[self_foo] | Argument[1] | y | parameter |
55+
| M1! | Method[self_foo] | Argument[self] | self in self_foo | parameter |
56+
| OtherLib::A | Method[foo] | Argument[0] | x | parameter |
57+
| OtherLib::A | Method[foo] | Argument[1] | y | parameter |
58+
| OtherLib::A | Method[foo] | Argument[self] | self in foo | parameter |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
utils/modeleditor/FrameworkModeAccessPaths.ql

0 commit comments

Comments
 (0)