codeql-development-mcp-server 2.25.1 → 2.25.2-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codeql-development-mcp-server.js +161887 -25576
- package/dist/codeql-development-mcp-server.js.map +4 -4
- package/package.json +15 -14
- package/ql/README.md +1 -0
- package/ql/actions/tools/src/codeql-pack.yml +1 -1
- package/ql/cpp/tools/src/codeql-pack.yml +1 -1
- package/ql/csharp/tools/src/codeql-pack.yml +1 -1
- package/ql/go/tools/src/codeql-pack.yml +1 -1
- package/ql/java/tools/src/codeql-pack.yml +1 -1
- package/ql/javascript/tools/src/codeql-pack.yml +1 -1
- package/ql/python/tools/src/codeql-pack.yml +1 -1
- package/ql/ruby/tools/src/codeql-pack.yml +1 -1
- package/ql/rust/tools/src/CallGraphFrom/CallGraphFrom.md +48 -0
- package/ql/rust/tools/src/CallGraphFrom/CallGraphFrom.ql +38 -0
- package/ql/rust/tools/src/CallGraphFromTo/CallGraphFromTo.md +48 -0
- package/ql/rust/tools/src/CallGraphFromTo/CallGraphFromTo.ql +69 -0
- package/ql/rust/tools/src/CallGraphTo/CallGraphTo.md +47 -0
- package/ql/rust/tools/src/CallGraphTo/CallGraphTo.ql +47 -0
- package/ql/rust/tools/src/ExternalPredicates.qll +14 -0
- package/ql/rust/tools/src/PrintAST/PrintAST.md +59 -0
- package/ql/rust/tools/src/PrintAST/PrintAST.ql +46 -0
- package/ql/rust/tools/src/PrintCFG/PrintCFG.md +56 -0
- package/ql/rust/tools/src/PrintCFG/PrintCFG.ql +58 -0
- package/ql/rust/tools/src/codeql-pack.lock.yml +28 -0
- package/ql/rust/tools/src/codeql-pack.yml +6 -0
- package/ql/swift/tools/src/codeql-pack.yml +1 -1
- package/scripts/setup-packs.sh +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeql-development-mcp-server",
|
|
3
|
-
"version": "2.25.
|
|
3
|
+
"version": "2.25.2-rc1",
|
|
4
4
|
"description": "An MCP server supporting LLM requests for CodeQL development tools and resources.",
|
|
5
5
|
"main": "dist/codeql-development-mcp-server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"ql/javascript/tools/src/",
|
|
19
19
|
"ql/python/tools/src/",
|
|
20
20
|
"ql/ruby/tools/src/",
|
|
21
|
+
"ql/rust/tools/src/",
|
|
21
22
|
"ql/swift/tools/src/",
|
|
22
23
|
"scripts/setup-packs.sh",
|
|
23
24
|
"package.json",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"typescript"
|
|
41
42
|
],
|
|
42
43
|
"author": "@github/ps-codeql",
|
|
43
|
-
"license": "
|
|
44
|
+
"license": "LicenseRef-CodeQL-Terms",
|
|
44
45
|
"repository": {
|
|
45
46
|
"type": "git",
|
|
46
47
|
"url": "git+https://github.com/advanced-security/codeql-development-mcp-server.git",
|
|
@@ -55,13 +56,13 @@
|
|
|
55
56
|
"npm": ">=11.6.2"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
59
|
-
"adm-zip": "^0.5.
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
60
|
+
"adm-zip": "^0.5.17",
|
|
60
61
|
"cors": "^2.8.6",
|
|
61
|
-
"dotenv": "^17.
|
|
62
|
+
"dotenv": "^17.4.0",
|
|
62
63
|
"express": "^5.2.1",
|
|
63
64
|
"js-yaml": "^4.1.1",
|
|
64
|
-
"
|
|
65
|
+
"sql.js": "^1.14.1",
|
|
65
66
|
"zod": "^3.25.76"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
@@ -70,16 +71,16 @@
|
|
|
70
71
|
"@types/cors": "^2.8.19",
|
|
71
72
|
"@types/express": "^5.0.6",
|
|
72
73
|
"@types/js-yaml": "^4.0.9",
|
|
73
|
-
"@types/node": "^25.
|
|
74
|
-
"@vitest/coverage-v8": "^4.1.
|
|
75
|
-
"esbuild": "^0.
|
|
76
|
-
"eslint": "^10.
|
|
74
|
+
"@types/node": "^25.6.0",
|
|
75
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
76
|
+
"esbuild": "^0.28.0",
|
|
77
|
+
"eslint": "^10.2.0",
|
|
77
78
|
"eslint-config-prettier": "^10.1.8",
|
|
78
79
|
"eslint-plugin-prettier": "^5.5.5",
|
|
79
|
-
"prettier": "^3.8.
|
|
80
|
-
"typescript": "^
|
|
81
|
-
"typescript-eslint": "^8.
|
|
82
|
-
"vitest": "^4.1.
|
|
80
|
+
"prettier": "^3.8.2",
|
|
81
|
+
"typescript": "^6.0.2",
|
|
82
|
+
"typescript-eslint": "^8.58.1",
|
|
83
|
+
"vitest": "^4.1.4"
|
|
83
84
|
},
|
|
84
85
|
"scripts": {
|
|
85
86
|
"build": "npm run clean && npm run lint && npm run bundle",
|
package/ql/README.md
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# CallGraphFrom for Rust
|
|
2
|
+
|
|
3
|
+
Displays calls made from a specified function, showing the call graph outbound from the source function.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all function calls made within the body of a named function, producing an outbound call graph. Given a source function name, it reports each call site and the callee, which is useful for understanding function dependencies and call chains.
|
|
8
|
+
|
|
9
|
+
The query accepts function names via an external predicate (`sourceFunction`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Mapping outbound dependencies of a specific function
|
|
16
|
+
- Understanding what a function calls and in what order
|
|
17
|
+
- Analyzing call chains for refactoring or security review
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
The following Rust code demonstrates outbound calls from `source_func`:
|
|
22
|
+
|
|
23
|
+
```rust
|
|
24
|
+
fn helper1() {}
|
|
25
|
+
|
|
26
|
+
fn helper2() {
|
|
27
|
+
helper1();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn source_func() { // Source function for analysis
|
|
31
|
+
helper1();
|
|
32
|
+
helper2();
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Running with `sourceFunction = "source_func"` produces results showing each call site with the message pattern ``Call from `source_func` to `helper1` ``.
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
The query is a `@kind problem` query producing rows of:
|
|
41
|
+
|
|
42
|
+
- ``select call, "Call from `source` to `callee`"``
|
|
43
|
+
|
|
44
|
+
## References
|
|
45
|
+
|
|
46
|
+
- [Rust Functions](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
|
|
47
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
48
|
+
- [CodeQL Library for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-rust/)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From for rust
|
|
3
|
+
* @description Displays calls made from a specified function, showing the call graph outbound from the source function.
|
|
4
|
+
* @id rust/tools/call-graph-from
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import rust
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source function name from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSourceFunctionName() {
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a function by matching against the selected source function names.
|
|
22
|
+
*/
|
|
23
|
+
Function getSourceFunction() { result.getName().getText() = getSourceFunctionName() }
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets the name of the called function.
|
|
27
|
+
*/
|
|
28
|
+
string getCalleeName(CallExpr call) {
|
|
29
|
+
if exists(call.getResolvedTarget().(Function).getName())
|
|
30
|
+
then result = call.getResolvedTarget().(Function).getName().getText()
|
|
31
|
+
else result = call.toString()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
from CallExpr call, Function source
|
|
35
|
+
where
|
|
36
|
+
call.getEnclosingCallable() = source and
|
|
37
|
+
source = getSourceFunction()
|
|
38
|
+
select call, "Call from `" + source.getName().getText() + "` to `" + getCalleeName(call) + "`"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# CallGraphFromTo for Rust
|
|
2
|
+
|
|
3
|
+
Displays calls on reachable paths from a source function to a target function, showing transitive call graph connectivity.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all call sites on paths that transitively connect a source function to a target function. It uses the `calls*` transitive closure to find functions reachable from the source that can also reach the target, then reports calls within those functions.
|
|
8
|
+
|
|
9
|
+
The query accepts both source and target function names via external predicates (`sourceFunction` and `targetFunction`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Understanding transitive call chains between two functions
|
|
16
|
+
- Analyzing reachability in the call graph
|
|
17
|
+
- Identifying intermediate functions on critical paths
|
|
18
|
+
- Security analysis of data flow through function boundaries
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
The following Rust code demonstrates a transitive call chain:
|
|
23
|
+
|
|
24
|
+
```rust
|
|
25
|
+
fn target() {}
|
|
26
|
+
|
|
27
|
+
fn intermediate() {
|
|
28
|
+
target();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
fn source() {
|
|
32
|
+
intermediate();
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Running with `sourceFunction = "source"` and `targetFunction = "target"` produces results showing each call site on the path with the message pattern ``Reachable call from `intermediate` to `target` ``.
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
The query is a `@kind problem` query producing rows of:
|
|
41
|
+
|
|
42
|
+
- ``select call, "Reachable call from `caller` to `callee`"``
|
|
43
|
+
|
|
44
|
+
## References
|
|
45
|
+
|
|
46
|
+
- [Rust Functions](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
|
|
47
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
48
|
+
- [CodeQL Library for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-rust/)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From To for rust
|
|
3
|
+
* @description Displays calls on reachable paths from a source function to a target function, showing transitive call graph connectivity.
|
|
4
|
+
* @id rust/tools/call-graph-from-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import rust
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source function name from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSourceFunctionName() {
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a single target function name from the comma-separated list.
|
|
22
|
+
*/
|
|
23
|
+
string getTargetFunctionName() {
|
|
24
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets a function by matching against the selected source function names.
|
|
29
|
+
*/
|
|
30
|
+
Function getSourceFunction() { result.getName().getText() = getSourceFunctionName() }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets a function by matching against the selected target function names.
|
|
34
|
+
*/
|
|
35
|
+
Function getTargetFunction() { result.getName().getText() = getTargetFunctionName() }
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Holds if function `caller` directly calls function `callee`.
|
|
39
|
+
*/
|
|
40
|
+
predicate calls(Function caller_, Function callee_) {
|
|
41
|
+
exists(CallExpr c |
|
|
42
|
+
c.getEnclosingCallable() = caller_ and
|
|
43
|
+
c.getResolvedTarget().(Function) = callee_
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Gets the name of the called function.
|
|
49
|
+
*/
|
|
50
|
+
string getCalleeName(CallExpr call) {
|
|
51
|
+
if exists(call.getResolvedTarget().(Function).getName())
|
|
52
|
+
then result = call.getResolvedTarget().(Function).getName().getText()
|
|
53
|
+
else result = call.toString()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
from CallExpr call, Function caller
|
|
57
|
+
where
|
|
58
|
+
call.getEnclosingCallable() = caller and
|
|
59
|
+
exists(Function source, Function target |
|
|
60
|
+
source = getSourceFunction() and
|
|
61
|
+
target = getTargetFunction() and
|
|
62
|
+
calls*(source, caller) and
|
|
63
|
+
exists(Function callee |
|
|
64
|
+
call.getResolvedTarget().(Function) = callee and
|
|
65
|
+
calls*(callee, target)
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
select call,
|
|
69
|
+
"Reachable call from `" + caller.getName().getText() + "` to `" + getCalleeName(call) + "`"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# CallGraphTo for Rust
|
|
2
|
+
|
|
3
|
+
Displays calls made to a specified function, showing the call graph inbound to the target function.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all call sites that invoke a named function, producing an inbound call graph. Given a target function name, it reports each call site and the enclosing caller, which is useful for understanding how a function is used throughout the codebase.
|
|
8
|
+
|
|
9
|
+
The query accepts function names via an external predicate (`targetFunction`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Finding all callers of a specific function
|
|
16
|
+
- Understanding how a function is used across modules
|
|
17
|
+
- Impact analysis when modifying or deprecating a function
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
The following Rust code demonstrates inbound calls to `target_func`:
|
|
22
|
+
|
|
23
|
+
```rust
|
|
24
|
+
fn target_func() {} // Target function for analysis
|
|
25
|
+
|
|
26
|
+
fn caller1() {
|
|
27
|
+
target_func();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn caller2() {
|
|
31
|
+
target_func();
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Running with `targetFunction = "target_func"` produces results showing each call site with the message pattern ``Call to `target_func` from `caller1` ``.
|
|
36
|
+
|
|
37
|
+
## Output Format
|
|
38
|
+
|
|
39
|
+
The query is a `@kind problem` query producing rows of:
|
|
40
|
+
|
|
41
|
+
- ``select call, "Call to `callee` from `caller`"``
|
|
42
|
+
|
|
43
|
+
## References
|
|
44
|
+
|
|
45
|
+
- [Rust Functions](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
|
|
46
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
47
|
+
- [CodeQL Library for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-rust/)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph To for rust
|
|
3
|
+
* @description Displays calls made to a specified function, showing the call graph inbound to the target function.
|
|
4
|
+
* @id rust/tools/call-graph-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import rust
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single target function name from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getTargetFunctionName() {
|
|
17
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a function by matching against the selected target function names.
|
|
22
|
+
*/
|
|
23
|
+
Function getTargetFunction() { result.getName().getText() = getTargetFunctionName() }
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Gets the caller name for a call expression.
|
|
27
|
+
*/
|
|
28
|
+
string getCallerName(CallExpr call) {
|
|
29
|
+
if exists(call.getEnclosingCallable().(Function).getName())
|
|
30
|
+
then result = call.getEnclosingCallable().(Function).getName().getText()
|
|
31
|
+
else result = "Top-level"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Gets the name of the called function.
|
|
36
|
+
*/
|
|
37
|
+
string getCalleeName(CallExpr call) {
|
|
38
|
+
if exists(call.getResolvedTarget().(Function).getName())
|
|
39
|
+
then result = call.getResolvedTarget().(Function).getName().getText()
|
|
40
|
+
else result = call.toString()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
from CallExpr call, Function target
|
|
44
|
+
where
|
|
45
|
+
target = getTargetFunction() and
|
|
46
|
+
call.getResolvedTarget() = target
|
|
47
|
+
select call, "Call to `" + getCalleeName(call) + "` from `" + getCallerName(call) + "`"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared extensible predicate declarations for MCP server tools queries.
|
|
3
|
+
* Values are provided via dataExtensions YAML files during testing,
|
|
4
|
+
* or via a temporary data extension pack at runtime from the MCP server.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Holds for each source function name for call graph analysis. */
|
|
8
|
+
extensible predicate sourceFunction(string name);
|
|
9
|
+
|
|
10
|
+
/** Holds for each target function name for call graph analysis. */
|
|
11
|
+
extensible predicate targetFunction(string name);
|
|
12
|
+
|
|
13
|
+
/** Holds for each selected source file path for AST/CFG printing. */
|
|
14
|
+
extensible predicate selectedSourceFiles(string path);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Print AST for Rust
|
|
2
|
+
|
|
3
|
+
Outputs a representation of the Abstract Syntax Tree (AST) for specified source files.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships.
|
|
8
|
+
|
|
9
|
+
This query produces the full AST for specified Rust source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses modules and functions, and debugging query logic that operates on AST nodes.
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Inspecting how CodeQL represents Rust functions, structs, and expressions
|
|
16
|
+
- Debugging queries that match on AST node types
|
|
17
|
+
- Understanding parent-child relationships between items and statements
|
|
18
|
+
- Verifying extractor behavior for ownership, borrowing, and pattern matching
|
|
19
|
+
- IDE integration for syntax tree visualization
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
The following Rust code demonstrates AST structure through function declarations and control flow:
|
|
24
|
+
|
|
25
|
+
```rust
|
|
26
|
+
struct Greeter {
|
|
27
|
+
name: String,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
impl Greeter {
|
|
31
|
+
fn greet(&self) {
|
|
32
|
+
println!("Hello, {}!", self.name);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fn main() {
|
|
37
|
+
let g = Greeter { name: "World".to_string() };
|
|
38
|
+
g.greet();
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
In the resulting AST:
|
|
43
|
+
|
|
44
|
+
- The module contains struct and function declarations as children
|
|
45
|
+
- Each function body contains a block expression with statement nodes
|
|
46
|
+
- Call expressions reference their target and arguments as child nodes
|
|
47
|
+
|
|
48
|
+
## Output Format
|
|
49
|
+
|
|
50
|
+
The query produces a graph via the parameterized `PrintAst` library module:
|
|
51
|
+
|
|
52
|
+
- `nodes`: Each AST node with its type, label, and properties
|
|
53
|
+
- `edges`: Parent-child relationships forming the syntax tree
|
|
54
|
+
|
|
55
|
+
## References
|
|
56
|
+
|
|
57
|
+
- [The Rust Reference](https://doc.rust-lang.org/reference/)
|
|
58
|
+
- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/)
|
|
59
|
+
- [CodeQL Library for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-rust/)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print AST for rust
|
|
3
|
+
* @description Outputs a representation of the Abstract Syntax Tree for specified source files.
|
|
4
|
+
* @id rust/tools/print-ast
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags ast
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import rust
|
|
10
|
+
private import codeql.rust.printast.PrintAst
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source file from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSelectedSourceFile() {
|
|
17
|
+
exists(string s | selectedSourceFiles(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a file by matching against the selected source file paths.
|
|
22
|
+
*/
|
|
23
|
+
File getSelectedFile() {
|
|
24
|
+
exists(string selectedFile |
|
|
25
|
+
selectedFile = getSelectedSourceFile() and
|
|
26
|
+
(
|
|
27
|
+
// Match by exact relative path from source root
|
|
28
|
+
result.getRelativePath() = selectedFile
|
|
29
|
+
or
|
|
30
|
+
// Match by file name if no path separators
|
|
31
|
+
not selectedFile.matches("%/%") and result.getBaseName() = selectedFile
|
|
32
|
+
or
|
|
33
|
+
// Match by ending path component
|
|
34
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
35
|
+
selectedFile
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Holds if a locatable element should be printed in the AST output.
|
|
42
|
+
* Restricts output to elements from the selected file.
|
|
43
|
+
*/
|
|
44
|
+
predicate shouldPrint(Locatable e) { e.getLocation().getFile() = getSelectedFile() }
|
|
45
|
+
|
|
46
|
+
import PrintAst<shouldPrint/1>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Print CFG for Rust
|
|
2
|
+
|
|
3
|
+
Produces a representation of a file's Control Flow Graph (CFG) for specified source files.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Control Flow Graph models the runtime execution order of statements and expressions within functions. Nodes represent individual executable elements and edges represent possible transitions between them, including branches, loops, and exceptional control flow.
|
|
8
|
+
|
|
9
|
+
This query produces the CFG for specified Rust source files, which is useful for understanding execution paths, identifying dead code, and debugging data flow queries that depend on control flow ordering.
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Visualizing execution paths through Rust functions
|
|
16
|
+
- Understanding how `if`, `match`, `loop`, `while`, and `for` affect control flow
|
|
17
|
+
- Debugging data flow queries that depend on CFG structure
|
|
18
|
+
- Identifying unreachable code or unexpected control flow edges
|
|
19
|
+
- Verifying CFG behavior for Rust-specific constructs like pattern matching
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
The following Rust code demonstrates control flow through branching and loops:
|
|
24
|
+
|
|
25
|
+
```rust
|
|
26
|
+
fn example(x: i32) -> i32 {
|
|
27
|
+
if x > 0 {
|
|
28
|
+
return x;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let mut val = x;
|
|
32
|
+
while val < 10 {
|
|
33
|
+
val += 1;
|
|
34
|
+
}
|
|
35
|
+
val
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
In the resulting CFG:
|
|
40
|
+
|
|
41
|
+
- The `if` condition creates a branch with two successors
|
|
42
|
+
- The early `return` creates an edge to the function exit
|
|
43
|
+
- The `while` loop creates a back-edge from the loop body to the condition
|
|
44
|
+
|
|
45
|
+
## Output Format
|
|
46
|
+
|
|
47
|
+
The query produces a graph with:
|
|
48
|
+
|
|
49
|
+
- `nodes`: Each CFG node with a `semmle.label` property
|
|
50
|
+
- `edges`: Control flow transitions between nodes
|
|
51
|
+
|
|
52
|
+
## References
|
|
53
|
+
|
|
54
|
+
- [The Rust Reference - Expressions](https://doc.rust-lang.org/reference/expressions.html)
|
|
55
|
+
- [CodeQL Control Flow Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
56
|
+
- [CodeQL Library for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-rust/)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Print CFG for rust
|
|
3
|
+
* @description Produces a representation of a file's Control Flow Graph for specified source files.
|
|
4
|
+
* @id rust/tools/print-cfg
|
|
5
|
+
* @kind graph
|
|
6
|
+
* @tags cfg
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import rust
|
|
10
|
+
import codeql.rust.controlflow.ControlFlowGraph
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source file from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSelectedSourceFile() {
|
|
17
|
+
exists(string s | selectedSourceFiles(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a file by matching against the selected source file paths.
|
|
22
|
+
*/
|
|
23
|
+
File getSelectedFile() {
|
|
24
|
+
exists(string selectedFile |
|
|
25
|
+
selectedFile = getSelectedSourceFile() and
|
|
26
|
+
(
|
|
27
|
+
// Match by exact relative path from source root
|
|
28
|
+
result.getRelativePath() = selectedFile
|
|
29
|
+
or
|
|
30
|
+
// Match by file name if no path separators
|
|
31
|
+
not selectedFile.matches("%/%") and result.getBaseName() = selectedFile
|
|
32
|
+
or
|
|
33
|
+
// Match by ending path component
|
|
34
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
35
|
+
selectedFile
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Holds if this CFG node should be included in output.
|
|
42
|
+
*/
|
|
43
|
+
predicate shouldPrintNode(CfgNode node) { node.getLocation().getFile() = getSelectedFile() }
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Configuration for PrintCFG that outputs filtered CFG nodes and edges.
|
|
47
|
+
*/
|
|
48
|
+
query predicate nodes(CfgNode node, string property, string value) {
|
|
49
|
+
shouldPrintNode(node) and
|
|
50
|
+
property = "semmle.label" and
|
|
51
|
+
value = node.toString()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
query predicate edges(CfgNode pred, CfgNode succ) {
|
|
55
|
+
shouldPrintNode(pred) and
|
|
56
|
+
shouldPrintNode(succ) and
|
|
57
|
+
pred.getASuccessor() = succ
|
|
58
|
+
}
|