Rust: add flag to turn off extractor path resolution

This commit is contained in:
Paolo Tranquilli
2025-02-19 09:44:09 +01:00
parent 9865577bf5
commit c1df8d0e13
10 changed files with 218 additions and 5 deletions

View File

@@ -78,3 +78,7 @@ options:
Collect flame graph data using the `tracing-flame` crate. To render a flame graph Collect flame graph data using the `tracing-flame` crate. To render a flame graph
or chart, run the `inferno-flamegraph` command. See also: https://crates.io/crates/tracing-flame or chart, run the `inferno-flamegraph` command. See also: https://crates.io/crates/tracing-flame
type: string type: string
skip_path_resolution:
title: Skip path resolution
description: >
Skip path resolution. This is experimental, while we move path resolution from the extractor to the QL library.

View File

@@ -57,6 +57,7 @@ pub struct Config {
pub qltest: bool, pub qltest: bool,
pub qltest_cargo_check: bool, pub qltest_cargo_check: bool,
pub qltest_dependencies: Vec<String>, pub qltest_dependencies: Vec<String>,
pub skip_path_resolution: bool,
} }
impl Config { impl Config {

View File

@@ -1,5 +1,6 @@
use crate::diagnostics::{emit_extraction_diagnostics, ExtractionStep}; use crate::diagnostics::{emit_extraction_diagnostics, ExtractionStep};
use crate::rust_analyzer::path_to_file_id; use crate::rust_analyzer::path_to_file_id;
use crate::translate::ResolvePaths;
use crate::trap::TrapId; use crate::trap::TrapId;
use anyhow::Context; use anyhow::Context;
use archive::Archiver; use archive::Archiver;
@@ -43,7 +44,7 @@ impl<'a> Extractor<'a> {
} }
} }
fn extract(&mut self, rust_analyzer: &rust_analyzer::RustAnalyzer, file: &std::path::Path) { fn extract(&mut self, rust_analyzer: &RustAnalyzer, file: &Path, resolve_paths: ResolvePaths) {
self.archiver.archive(file); self.archiver.archive(file);
let before_parse = Instant::now(); let before_parse = Instant::now();
@@ -66,6 +67,7 @@ impl<'a> Extractor<'a> {
label, label,
line_index, line_index,
semantics_info.as_ref().ok(), semantics_info.as_ref().ok(),
resolve_paths,
); );
for err in errors { for err in errors {
@@ -102,12 +104,17 @@ impl<'a> Extractor<'a> {
file: &Path, file: &Path,
semantics: &Semantics<'_, RootDatabase>, semantics: &Semantics<'_, RootDatabase>,
vfs: &Vfs, vfs: &Vfs,
resolve_paths: ResolvePaths,
) { ) {
self.extract(&RustAnalyzer::new(vfs, semantics), file); self.extract(&RustAnalyzer::new(vfs, semantics), file, resolve_paths);
} }
pub fn extract_without_semantics(&mut self, file: &Path, reason: &str) { pub fn extract_without_semantics(&mut self, file: &Path, reason: &str) {
self.extract(&RustAnalyzer::WithoutSemantics { reason }, file); self.extract(
&RustAnalyzer::WithoutSemantics { reason },
file,
ResolvePaths::No,
);
} }
pub fn load_manifest( pub fn load_manifest(
@@ -236,12 +243,19 @@ fn main() -> anyhow::Result<()> {
extractor.extract_without_semantics(file, "no manifest found"); extractor.extract_without_semantics(file, "no manifest found");
} }
let cargo_config = cfg.to_cargo_config(&cwd()?); let cargo_config = cfg.to_cargo_config(&cwd()?);
let resolve_paths = if cfg.skip_path_resolution {
ResolvePaths::No
} else {
ResolvePaths::Yes
};
for (manifest, files) in map.values().filter(|(_, files)| !files.is_empty()) { for (manifest, files) in map.values().filter(|(_, files)| !files.is_empty()) {
if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config) { if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config) {
let semantics = Semantics::new(db); let semantics = Semantics::new(db);
for file in files { for file in files {
match extractor.load_source(file, &semantics, vfs) { match extractor.load_source(file, &semantics, vfs) {
Ok(()) => extractor.extract_with_semantics(file, &semantics, vfs), Ok(()) => {
extractor.extract_with_semantics(file, &semantics, vfs, resolve_paths)
}
Err(reason) => extractor.extract_without_semantics(file, &reason), Err(reason) => extractor.extract_without_semantics(file, &reason),
}; };
} }

View File

@@ -2,4 +2,4 @@ mod base;
mod generated; mod generated;
mod mappings; mod mappings;
pub use base::Translator; pub use base::{ResolvePaths, Translator};

View File

@@ -83,6 +83,12 @@ macro_rules! dispatch_to_tracing {
}; };
} }
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ResolvePaths {
Yes,
No,
}
pub struct Translator<'a> { pub struct Translator<'a> {
pub trap: TrapFile, pub trap: TrapFile,
path: &'a str, path: &'a str,
@@ -90,6 +96,7 @@ pub struct Translator<'a> {
line_index: LineIndex, line_index: LineIndex,
file_id: Option<EditionedFileId>, file_id: Option<EditionedFileId>,
pub semantics: Option<&'a Semantics<'a, RootDatabase>>, pub semantics: Option<&'a Semantics<'a, RootDatabase>>,
resolve_paths: ResolvePaths,
} }
const UNKNOWN_LOCATION: (LineCol, LineCol) = const UNKNOWN_LOCATION: (LineCol, LineCol) =
@@ -102,6 +109,7 @@ impl<'a> Translator<'a> {
label: Label<generated::File>, label: Label<generated::File>,
line_index: LineIndex, line_index: LineIndex,
semantic_info: Option<&FileSemanticInformation<'a>>, semantic_info: Option<&FileSemanticInformation<'a>>,
resolve_paths: ResolvePaths,
) -> Translator<'a> { ) -> Translator<'a> {
Translator { Translator {
trap, trap,
@@ -110,6 +118,7 @@ impl<'a> Translator<'a> {
line_index, line_index,
file_id: semantic_info.map(|i| i.file_id), file_id: semantic_info.map(|i| i.file_id),
semantics: semantic_info.map(|i| i.semantics), semantics: semantic_info.map(|i| i.semantics),
resolve_paths,
} }
} }
fn location(&self, range: TextRange) -> Option<(LineCol, LineCol)> { fn location(&self, range: TextRange) -> Option<(LineCol, LineCol)> {
@@ -497,6 +506,9 @@ impl<'a> Translator<'a> {
item: &T, item: &T,
label: Label<generated::Addressable>, label: Label<generated::Addressable>,
) { ) {
if self.resolve_paths == ResolvePaths::No {
return;
}
(|| { (|| {
let sema = self.semantics.as_ref()?; let sema = self.semantics.as_ref()?;
let def = T::Hir::try_from_source(item, sema)?; let def = T::Hir::try_from_source(item, sema)?;
@@ -517,6 +529,9 @@ impl<'a> Translator<'a> {
item: &ast::Variant, item: &ast::Variant,
label: Label<generated::Variant>, label: Label<generated::Variant>,
) { ) {
if self.resolve_paths == ResolvePaths::No {
return;
}
(|| { (|| {
let sema = self.semantics.as_ref()?; let sema = self.semantics.as_ref()?;
let def = sema.to_enum_variant_def(item)?; let def = sema.to_enum_variant_def(item)?;
@@ -537,6 +552,9 @@ impl<'a> Translator<'a> {
item: &impl PathAst, item: &impl PathAst,
label: Label<generated::Resolvable>, label: Label<generated::Resolvable>,
) { ) {
if self.resolve_paths == ResolvePaths::No {
return;
}
(|| { (|| {
let path = item.path()?; let path = item.path()?;
let sema = self.semantics.as_ref()?; let sema = self.semantics.as_ref()?;
@@ -557,6 +575,9 @@ impl<'a> Translator<'a> {
item: &ast::MethodCallExpr, item: &ast::MethodCallExpr,
label: Label<generated::MethodCallExpr>, label: Label<generated::MethodCallExpr>,
) { ) {
if self.resolve_paths == ResolvePaths::No {
return;
}
(|| { (|| {
let sema = self.semantics.as_ref()?; let sema = self.semantics.as_ref()?;
let resolved = sema.resolve_method_call_fallback(item)?; let resolved = sema.resolve_method_call_fallback(item)?;

View File

@@ -0,0 +1,39 @@
// would prefer to write `include!("../anonymous.rs");`
// but it seems `include!` does not work in rust-analyzer/our extractor
use super::regular::Trait;
fn canonicals() {
struct OtherStruct;
trait OtherTrait {
fn g(&self);
}
impl OtherTrait for OtherStruct {
fn g(&self) {}
}
impl OtherTrait for crate::regular::Struct {
fn g(&self) {}
}
impl crate::regular::Trait for OtherStruct {
fn f(&self) {}
}
fn nested() {
struct OtherStruct;
}
fn usage() {
let s = OtherStruct {};
s.f();
s.g();
nested();
}
}
fn other() {
struct OtherStruct;
}

View File

@@ -0,0 +1,66 @@
canonicalPaths
| anonymous.rs:4:1:4:26 | Use | None | None |
| anonymous.rs:6:1:35:1 | fn canonicals | None | None |
| anonymous.rs:7:5:7:23 | struct OtherStruct | None | None |
| anonymous.rs:9:5:11:5 | trait OtherTrait | None | None |
| anonymous.rs:10:9:10:20 | fn g | None | None |
| anonymous.rs:13:5:15:5 | impl OtherTrait for OtherStruct { ... } | None | None |
| anonymous.rs:14:9:14:22 | fn g | None | None |
| anonymous.rs:17:5:19:5 | impl OtherTrait for ...::Struct { ... } | None | None |
| anonymous.rs:18:9:18:22 | fn g | None | None |
| anonymous.rs:21:5:23:5 | impl ...::Trait for OtherStruct { ... } | None | None |
| anonymous.rs:22:9:22:22 | fn f | None | None |
| anonymous.rs:25:5:27:5 | fn nested | None | None |
| anonymous.rs:26:9:26:27 | struct OtherStruct | None | None |
| anonymous.rs:29:5:34:5 | fn usage | None | None |
| anonymous.rs:37:1:39:1 | fn other | None | None |
| anonymous.rs:38:5:38:23 | struct OtherStruct | None | None |
| lib.rs:1:1:1:14 | mod anonymous | None | None |
| lib.rs:2:1:2:12 | mod regular | None | None |
| regular.rs:4:1:5:18 | struct Struct | None | None |
| regular.rs:7:1:9:1 | trait Trait | None | None |
| regular.rs:8:5:8:16 | fn f | None | None |
| regular.rs:11:1:13:1 | impl Trait for Struct { ... } | None | None |
| regular.rs:12:5:12:18 | fn f | None | None |
| regular.rs:15:1:17:1 | impl Struct { ... } | None | None |
| regular.rs:16:5:16:18 | fn g | None | None |
| regular.rs:19:1:21:1 | trait TraitWithBlanketImpl | None | None |
| regular.rs:20:5:20:16 | fn h | None | None |
| regular.rs:23:1:25:1 | impl TraitWithBlanketImpl for T { ... } | None | None |
| regular.rs:24:5:24:18 | fn h | None | None |
| regular.rs:27:1:27:12 | fn free | None | None |
| regular.rs:29:1:35:1 | fn usage | None | None |
| regular.rs:37:1:41:1 | enum MyEnum | None | None |
| regular.rs:43:1:49:1 | fn enum_qualified_usage | None | None |
| regular.rs:51:1:58:1 | fn enum_unqualified_usage | None | None |
| regular.rs:54:5:54:18 | Use | None | None |
| regular.rs:60:1:66:1 | fn enum_match | None | None |
resolvedPaths
| anonymous.rs:30:17:30:30 | OtherStruct {...} | None | None |
| anonymous.rs:31:9:31:9 | s | None | None |
| anonymous.rs:31:9:31:13 | s.f(...) | None | None |
| anonymous.rs:32:9:32:9 | s | None | None |
| anonymous.rs:32:9:32:13 | s.g(...) | None | None |
| anonymous.rs:33:9:33:14 | nested | None | None |
| regular.rs:30:13:30:21 | Struct {...} | None | None |
| regular.rs:31:5:31:5 | s | None | None |
| regular.rs:31:5:31:9 | s.f(...) | None | None |
| regular.rs:32:5:32:5 | s | None | None |
| regular.rs:32:5:32:9 | s.g(...) | None | None |
| regular.rs:33:5:33:5 | s | None | None |
| regular.rs:33:5:33:9 | s.h(...) | None | None |
| regular.rs:34:5:34:8 | free | None | None |
| regular.rs:44:9:44:26 | ...::None::<...> | None | None |
| regular.rs:45:9:45:20 | ...::Some | None | None |
| regular.rs:46:9:46:24 | ...::Variant1 | None | None |
| regular.rs:47:9:47:24 | ...::Variant2 | None | None |
| regular.rs:48:9:48:33 | ...::Variant3 {...} | None | None |
| regular.rs:52:9:52:18 | None::<...> | None | None |
| regular.rs:53:9:53:12 | Some | None | None |
| regular.rs:55:9:55:16 | Variant1 | None | None |
| regular.rs:56:9:56:16 | Variant2 | None | None |
| regular.rs:57:9:57:25 | Variant3 {...} | None | None |
| regular.rs:61:11:61:11 | e | None | None |
| regular.rs:62:9:62:24 | ...::Variant1 | None | None |
| regular.rs:63:9:63:27 | ...::Variant2(...) | None | None |
| regular.rs:64:9:64:31 | ...::Variant3 {...} | None | None |

View File

@@ -0,0 +1 @@
extractor-tests/canonical_path/canonical_paths.ql

View File

@@ -0,0 +1 @@
skip_path_resolution: true

View File

@@ -0,0 +1,66 @@
// would prefer to write `include!("../regular.rs");`
// but it seems `include!` does not work in rust-analyzer/our extractor
#[derive(Eq, PartialEq)]
pub struct Struct;
pub trait Trait {
fn f(&self);
}
impl Trait for Struct {
fn f(&self) {}
}
impl Struct {
fn g(&self) {}
}
trait TraitWithBlanketImpl {
fn h(&self);
}
impl<T: Eq> TraitWithBlanketImpl for T {
fn h(&self) {}
}
fn free() {}
fn usage() {
let s = Struct {};
s.f();
s.g();
s.h();
free();
}
enum MyEnum {
Variant1,
Variant2(usize),
Variant3 { x: usize },
}
fn enum_qualified_usage() {
_ = Option::None::<()>;
_ = Option::Some(0);
_ = MyEnum::Variant1;
_ = MyEnum::Variant2(0);
_ = MyEnum::Variant3 { x: 1 };
}
fn enum_unqualified_usage() {
_ = None::<()>;
_ = Some(0);
use MyEnum::*;
_ = Variant1;
_ = Variant2(0);
_ = Variant3 { x: 1 };
}
fn enum_match(e: MyEnum) {
match e {
MyEnum::Variant1 => {}
MyEnum::Variant2(_) => {}
MyEnum::Variant3 { .. } => {}
}
}