mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-21 15:52:05 +00:00
Control flow graph: setup (#17064)
This PR contains the scaffolding for a new control flow graph implementation, along with its application to the `unreachable` rule. At the moment, the implementation is a maximal over-approximation: no control flow is modeled and all statements are counted as reachable. With each additional statement type we support, this approximation will improve. So this PR just contains: - A `ControlFlowGraph` struct and builder - Support for printing the flow graph as a Mermaid graph - Snapshot tests for the actual graphs - (a very bad!) reimplementation of `unreachable` using the new structs - Snapshot tests for `unreachable` # Instructions for Viewing Mermaid snapshots Unfortunately I don't know how to convince GitHub to render the Mermaid graphs in the snapshots. However, you can view these locally in VSCode if you install an extension that supports Mermaid graphs in Markdown, and then add this to your `settings.json`: ```json "files.associations": { "*.md.snap": "markdown", } ```
This commit is contained in:
parent
0073fd4945
commit
aa93005d8d
24 changed files with 775 additions and 6244 deletions
61
crates/ruff_python_semantic/src/cfg/mod.rs
Normal file
61
crates/ruff_python_semantic/src/cfg/mod.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
pub mod graph;
|
||||
pub mod visualize;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fmt::Write;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::cfg::graph::build_cfg;
|
||||
use crate::cfg::visualize::draw_cfg;
|
||||
use insta;
|
||||
|
||||
use ruff_python_parser::parse_module;
|
||||
use ruff_text_size::Ranged;
|
||||
use test_case::test_case;
|
||||
|
||||
#[test_case("no_flow.py")]
|
||||
fn control_flow_graph(filename: &str) {
|
||||
let path = PathBuf::from("resources/test/fixtures/cfg").join(filename);
|
||||
let source = fs::read_to_string(path).expect("failed to read file");
|
||||
let stmts = parse_module(&source)
|
||||
.unwrap_or_else(|err| panic!("failed to parse source: '{source}': {err}"))
|
||||
.into_suite();
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
for (i, stmt) in stmts.into_iter().enumerate() {
|
||||
let func = stmt.as_function_def_stmt().expect(
|
||||
"Snapshot test for control flow graph should consist only of function definitions",
|
||||
);
|
||||
let cfg = build_cfg(&func.body);
|
||||
|
||||
let mermaid_graph = draw_cfg(cfg, &source);
|
||||
writeln!(
|
||||
output,
|
||||
"## Function {}\n\
|
||||
### Source\n\
|
||||
```python\n\
|
||||
{}\n\
|
||||
```\n\n\
|
||||
### Control Flow Graph\n\
|
||||
```mermaid\n\
|
||||
{}\n\
|
||||
```\n",
|
||||
i,
|
||||
&source[func.range()],
|
||||
mermaid_graph,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
insta::with_settings!({
|
||||
omit_expression => true,
|
||||
input_file => filename,
|
||||
description => "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
|
||||
}, {
|
||||
insta::assert_snapshot!(format!("{filename}.md"), output);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue