Skip to content

Commit 3018303

Browse files
Avoid parsing with Salsa (#13437)
## Summary For reasons I haven't investigated, this speeds up the resolver about 2x (from 6.404s to 3.612s on an extremely large codebase). ## Test Plan \cc @BurntSushi ``` [andrew@duff rippling]$ time ruff analyze graph --preview > /dev/null real 3.274 user 16.039 sys 7.609 maxmem 11631 MB faults 0 [andrew@duff rippling]$ time ruff-patch analyze graph --preview > /dev/null real 1.841 user 14.625 sys 3.639 maxmem 7173 MB faults 0 [andrew@duff rippling]$ time ruff-patch2 analyze graph --preview > /dev/null real 2.087 user 15.333 sys 4.869 maxmem 8642 MB faults 0 ``` Where that's `main`, then (`ruff-patch`) using the version with no `File`, no `SemanticModel`, then (`ruff-patch2`) using `File`.
1 parent 6c303b2 commit 3018303

File tree

5 files changed

+27
-26
lines changed

5 files changed

+27
-26
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ruff_graph/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ ruff_db = { workspace = true, features = ["os", "serde"] }
1616
ruff_linter = { workspace = true }
1717
ruff_macros = { workspace = true }
1818
ruff_python_ast = { workspace = true }
19+
ruff_python_parser = { workspace = true }
1920

2021
anyhow = { workspace = true }
2122
clap = { workspace = true, optional = true }

crates/ruff_graph/src/collector.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use red_knot_python_semantic::ModuleName;
2-
use ruff_python_ast::visitor::source_order::{walk_body, walk_expr, walk_stmt, SourceOrderVisitor};
3-
use ruff_python_ast::{self as ast, Expr, ModModule, Stmt};
2+
use ruff_python_ast::visitor::source_order::{
3+
walk_expr, walk_module, walk_stmt, SourceOrderVisitor,
4+
};
5+
use ruff_python_ast::{self as ast, Expr, Mod, Stmt};
46

57
/// Collect all imports for a given Python file.
68
#[derive(Default, Debug)]
@@ -23,8 +25,8 @@ impl<'a> Collector<'a> {
2325
}
2426

2527
#[must_use]
26-
pub(crate) fn collect(mut self, module: &ModModule) -> Vec<CollectedImport> {
27-
walk_body(&mut self, &module.body);
28+
pub(crate) fn collect(mut self, module: &Mod) -> Vec<CollectedImport> {
29+
walk_module(&mut self, module);
2830
self.imports
2931
}
3032
}

crates/ruff_graph/src/lib.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ pub use crate::db::ModuleDb;
33
use crate::resolver::Resolver;
44
pub use crate::settings::{AnalyzeSettings, Direction};
55
use anyhow::Result;
6-
use red_knot_python_semantic::SemanticModel;
7-
use ruff_db::files::system_path_to_file;
8-
use ruff_db::parsed::parsed_module;
96
use ruff_db::system::{SystemPath, SystemPathBuf};
107
use ruff_python_ast::helpers::to_module_path;
8+
use ruff_python_parser::{parse, Mode};
119
use serde::{Deserialize, Serialize};
1210
use std::collections::{BTreeMap, BTreeSet};
1311

@@ -29,11 +27,11 @@ impl ModuleImports {
2927
string_imports: bool,
3028
) -> Result<Self> {
3129
// Read and parse the source code.
32-
let file = system_path_to_file(db, path)?;
33-
let parsed = parsed_module(db, file);
30+
let source = std::fs::read_to_string(path)?;
31+
let parsed = parse(&source, Mode::Module)?;
32+
3433
let module_path =
3534
package.and_then(|package| to_module_path(package.as_std_path(), path.as_std_path()));
36-
let model = SemanticModel::new(db, file);
3735

3836
// Collect the imports.
3937
let imports =
@@ -42,7 +40,7 @@ impl ModuleImports {
4240
// Resolve the imports.
4341
let mut resolved_imports = ModuleImports::default();
4442
for import in imports {
45-
let Some(resolved) = Resolver::new(&model).resolve(import) else {
43+
let Some(resolved) = Resolver::new(db).resolve(import) else {
4644
continue;
4745
};
4846
let Some(path) = resolved.as_system_path() else {

crates/ruff_graph/src/resolver.rs

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,36 @@
1-
use red_knot_python_semantic::SemanticModel;
1+
use red_knot_python_semantic::resolve_module;
22
use ruff_db::files::FilePath;
33

44
use crate::collector::CollectedImport;
5+
use crate::ModuleDb;
56

67
/// Collect all imports for a given Python file.
78
pub(crate) struct Resolver<'a> {
8-
semantic: &'a SemanticModel<'a>,
9+
db: &'a ModuleDb,
910
}
1011

1112
impl<'a> Resolver<'a> {
12-
/// Initialize a [`Resolver`] with a given [`SemanticModel`].
13-
pub(crate) fn new(semantic: &'a SemanticModel<'a>) -> Self {
14-
Self { semantic }
13+
/// Initialize a [`Resolver`] with a given [`ModuleDb`].
14+
pub(crate) fn new(db: &'a ModuleDb) -> Self {
15+
Self { db }
1516
}
1617

1718
/// Resolve the [`CollectedImport`] into a [`FilePath`].
1819
pub(crate) fn resolve(&self, import: CollectedImport) -> Option<&'a FilePath> {
1920
match import {
20-
CollectedImport::Import(import) => self
21-
.semantic
22-
.resolve_module(import)
23-
.map(|module| module.file().path(self.semantic.db())),
21+
CollectedImport::Import(import) => {
22+
resolve_module(self.db, import).map(|module| module.file().path(self.db))
23+
}
2424
CollectedImport::ImportFrom(import) => {
2525
// Attempt to resolve the member (e.g., given `from foo import bar`, look for `foo.bar`).
2626
let parent = import.parent();
27-
self.semantic
28-
.resolve_module(import)
29-
.map(|module| module.file().path(self.semantic.db()))
27+
28+
resolve_module(self.db, import)
29+
.map(|module| module.file().path(self.db))
3030
.or_else(|| {
3131
// Attempt to resolve the module (e.g., given `from foo import bar`, look for `foo`).
32-
self.semantic
33-
.resolve_module(parent?)
34-
.map(|module| module.file().path(self.semantic.db()))
32+
33+
resolve_module(self.db, parent?).map(|module| module.file().path(self.db))
3534
})
3635
}
3736
}

0 commit comments

Comments
 (0)