diff options
11 files changed, 489 insertions, 26 deletions
diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore index 68c87a6b1ed..c4470a45078 100644 --- a/src/tools/rust-analyzer/.gitignore +++ b/src/tools/rust-analyzer/.gitignore @@ -1,6 +1,5 @@ -/target/ +target/ /dist/ -crates/*/target **/*.rs.bk **/*.rs.pending-snap .idea/* diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 2716a10343b..d0e45f530bc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -203,6 +203,10 @@ impl<DB: HirDatabase> Semantics<'_, DB> { self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast)) } + pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> { + self.imp.resolve_range_pat(range_pat).map(Struct::from) + } + pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> { self.imp.resolve_range_expr(range_expr).map(Struct::from) } @@ -1367,6 +1371,10 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call) } + fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> { + self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat) + } + fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> { self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index be0e57b0b1d..9d32229e8f7 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -348,6 +348,25 @@ impl SourceAnalyzer { } } + pub(crate) fn resolve_range_pat( + &self, + db: &dyn HirDatabase, + range_pat: &ast::RangePat, + ) -> Option<StructId> { + let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) { + (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo], + (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom], + (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range], + (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive], + (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive], + + (RangeOp::Exclusive, None, None) => return None, + (RangeOp::Inclusive, None, None) => return None, + (RangeOp::Inclusive, Some(_), None) => return None, + }; + self.resolver.resolve_known_struct(db.upcast(), &path) + } + pub(crate) fn resolve_range_expr( &self, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index a253e086f81..fdac4dd2efb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -178,7 +178,19 @@ impl Definition { Definition::Static(it) => it.docs(db), Definition::Trait(it) => it.docs(db), Definition::TraitAlias(it) => it.docs(db), - Definition::TypeAlias(it) => it.docs(db), + Definition::TypeAlias(it) => { + it.docs(db).or_else(|| { + // docs are missing, try to fall back to the docs of the aliased item. + let adt = it.ty(db).as_adt()?; + let docs = adt.docs(db)?; + let docs = format!( + "*This is the documentation for* `{}`\n\n{}", + adt.display(db, edition), + docs.as_str() + ); + Some(Documentation::new(docs)) + }) + } Definition::BuiltinType(it) => { famous_defs.and_then(|fd| { // std exposes prim_{} modules with docstrings on the root to document the builtins @@ -318,7 +330,8 @@ impl IdentClass { .map(IdentClass::NameClass) .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)) }, - ast::RangeExpr(range_expr) => OperatorClass::classify_range(sema, &range_expr).map(IdentClass::Operator), + ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator), + ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator), ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator), ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator), ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator), @@ -558,7 +571,14 @@ pub enum OperatorClass { } impl OperatorClass { - pub fn classify_range( + pub fn classify_range_pat( + sema: &Semantics<'_, RootDatabase>, + range_pat: &ast::RangePat, + ) -> Option<OperatorClass> { + sema.resolve_range_pat(range_pat).map(OperatorClass::Range) + } + + pub fn classify_range_expr( sema: &Semantics<'_, RootDatabase>, range_expr: &ast::RangeExpr, ) -> Option<OperatorClass> { diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index ae3ef3e4437..1d42a66995b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -98,6 +98,7 @@ pub(crate) fn goto_definition( return Some(vec![x]); } } + Some( IdentClass::classify_node(sema, &parent)? .definitions() @@ -460,7 +461,87 @@ mod tests { } #[test] - fn goto_def_range() { + fn goto_def_pat_range_to_inclusive() { + check_name( + "RangeToInclusive", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + ..$0='z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range_to() { + check_name( + "RangeTo", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + .$0.'z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range() { + check_name( + "Range", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + 'a'.$0.'z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range_inclusive() { + check_name( + "RangeInclusive", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + 'a'..$0='z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range_from() { + check_name( + "RangeFrom", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + 'a'..$0 => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_expr_range() { check_name( "Range", r#" @@ -471,7 +552,7 @@ let x = 0.$0.1; } #[test] - fn goto_def_range_from() { + fn goto_def_expr_range_from() { check_name( "RangeFrom", r#" @@ -484,7 +565,7 @@ fn f(arr: &[i32]) -> &[i32] { } #[test] - fn goto_def_range_inclusive() { + fn goto_def_expr_range_inclusive() { check_name( "RangeInclusive", r#" @@ -495,7 +576,7 @@ let x = 0.$0.=1; } #[test] - fn goto_def_range_full() { + fn goto_def_expr_range_full() { check_name( "RangeFull", r#" @@ -508,7 +589,7 @@ fn f(arr: &[i32]) -> &[i32] { } #[test] - fn goto_def_range_to() { + fn goto_def_expr_range_to() { check_name( "RangeTo", r#" @@ -521,7 +602,7 @@ fn f(arr: &[i32]) -> &[i32] { } #[test] - fn goto_def_range_to_inclusive() { + fn goto_def_expr_range_to_inclusive() { check_name( "RangeToInclusive", r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 81397b07855..ef835f5bef8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -9018,3 +9018,156 @@ foo!(BAR_$0); "#]], ); } + +#[test] +fn type_alias_without_docs() { + // Simple. + check( + r#" +/// Docs for B +struct B; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + + --- + + *This is the documentation for* `struct B` + + Docs for B + "#]], + ); + + // Nested. + check( + r#" +/// Docs for C +struct C; + +type B = C; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + + --- + + *This is the documentation for* `struct C` + + Docs for C + "#]], + ); + + // Showing the docs for aliased struct instead of intermediate type. + check( + r#" +/// Docs for C +struct C; + +/// Docs for B +type B = C; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + + --- + + *This is the documentation for* `struct C` + + Docs for C + "#]], + ); + + // No docs found. + check( + r#" +struct C; + +type B = C; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + "#]], + ); + + // Multiple nested crate. + check( + r#" +//- /lib.rs crate:c +/// Docs for C +pub struct C; + +//- /lib.rs crate:b deps:c +pub use c::C; +pub type B = C; + +//- /lib.rs crate:a deps:b +pub use b::B; +pub type A = B; + +//- /main.rs crate:main deps:a +use a::A$0; +"#, + expect![[r#" + *A* + + ```rust + a + ``` + + ```rust + // size = 0, align = 1 + pub type A = B + ``` + + --- + + *This is the documentation for* `pub struct C` + + Docs for C + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index ecc8333503e..e872585c571 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -85,7 +85,9 @@ fn actual_main() -> anyhow::Result<ExitCode> { flags::RustAnalyzerCmd::UnresolvedReferences(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?, + flags::RustAnalyzerCmd::Lsif(cmd) => { + cmd.run(&mut std::io::stdout(), Some(project_model::RustLibSource::Discover))? + } flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?, flags::RustAnalyzerCmd::RunTests(cmd) => cmd.run()?, flags::RustAnalyzerCmd::RustcTests(cmd) => cmd.run()?, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index ca8acf57bff..33c4f31fbee 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -12,6 +12,7 @@ use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use lsp_types::lsif; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use rustc_hash::FxHashMap; +use stdx::format_to; use vfs::{AbsPathBuf, Vfs}; use crate::{ @@ -21,7 +22,7 @@ use crate::{ version::version, }; -struct LsifManager<'a> { +struct LsifManager<'a, 'w> { count: i32, token_map: FxHashMap<TokenId, Id>, range_map: FxHashMap<FileRange, Id>, @@ -30,6 +31,7 @@ struct LsifManager<'a> { analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs, + out: &'w mut dyn std::io::Write, } #[derive(Clone, Copy)] @@ -41,8 +43,13 @@ impl From<Id> for lsp_types::NumberOrString { } } -impl LsifManager<'_> { - fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> { +impl LsifManager<'_, '_> { + fn new<'a, 'w>( + analysis: &'a Analysis, + db: &'a RootDatabase, + vfs: &'a Vfs, + out: &'w mut dyn std::io::Write, + ) -> LsifManager<'a, 'w> { LsifManager { count: 0, token_map: FxHashMap::default(), @@ -52,6 +59,7 @@ impl LsifManager<'_> { analysis, db, vfs, + out, } } @@ -70,9 +78,8 @@ impl LsifManager<'_> { self.add(lsif::Element::Edge(edge)) } - // FIXME: support file in addition to stdout here - fn emit(&self, data: &str) { - println!("{data}"); + fn emit(&mut self, data: &str) { + format_to!(self.out, "{data}\n"); } fn get_token_id(&mut self, id: TokenId) -> Id { @@ -272,14 +279,14 @@ impl LsifManager<'_> { } impl flags::Lsif { - pub fn run(self) -> anyhow::Result<()> { + pub fn run( + self, + out: &mut dyn std::io::Write, + sysroot: Option<RustLibSource>, + ) -> anyhow::Result<()> { let now = Instant::now(); - let cargo_config = &CargoConfig { - sysroot: Some(RustLibSource::Discover), - all_targets: true, - set_test: true, - ..Default::default() - }; + let cargo_config = + &CargoConfig { sysroot, all_targets: true, set_test: true, ..Default::default() }; let no_progress = &|_| (); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, @@ -308,7 +315,7 @@ impl flags::Lsif { let si = StaticIndex::compute(&analysis, vendored_libs_config); - let mut lsif = LsifManager::new(&analysis, db, &vfs); + let mut lsif = LsifManager::new(&analysis, db, &vfs, out); lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData { version: String::from("0.5.0"), project_root: lsp_types::Url::from_file_path(path).unwrap(), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs new file mode 100644 index 00000000000..fba54666912 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs @@ -0,0 +1,131 @@ +use expect_test::expect; +use test_utils::skip_slow_tests; + +use crate::support::Project; + +// If you choose to change the test fixture here, please inform the ferrocene/needy maintainers by +// opening an issue at https://github.com/ferrocene/needy as the tool relies on specific token +// mapping behavior. +#[test] +fn lsif_contains_generated_constant() { + if skip_slow_tests() { + return; + } + + let stdout = Project::with_fixture( + r#" +//- /Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- /src/lib.rs +#![allow(unused)] + +macro_rules! generate_const_from_identifier( + ($id:ident) => ( + const _: () = { const $id: &str = "encoded_data"; }; + ) +); + +generate_const_from_identifier!(REQ_001); +mod tests { + use super::*; + generate_const_from_identifier!(REQ_002); +} +"#, + ) + .root("foo") + .run_lsif(); + let n = stdout.find(r#"{"id":2,"#).unwrap(); + // the first 2 entries contain paths that are not stable + let stdout = &stdout[n..]; + expect![[r#" + {"id":2,"type":"vertex","label":"foldingRangeResult","result":[{"startLine":2,"startCharacter":43,"endLine":6,"endCharacter":1},{"startLine":3,"startCharacter":19,"endLine":5,"endCharacter":5},{"startLine":9,"startCharacter":10,"endLine":12,"endCharacter":1}]} + {"id":3,"type":"edge","label":"textDocument/foldingRange","inV":2,"outV":1} + {"id":4,"type":"vertex","label":"range","start":{"line":0,"character":3},"end":{"line":0,"character":8}} + {"id":5,"type":"vertex","label":"resultSet"} + {"id":6,"type":"edge","label":"next","inV":5,"outV":4} + {"id":7,"type":"vertex","label":"range","start":{"line":2,"character":13},"end":{"line":2,"character":43}} + {"id":8,"type":"vertex","label":"resultSet"} + {"id":9,"type":"edge","label":"next","inV":8,"outV":7} + {"id":10,"type":"vertex","label":"range","start":{"line":8,"character":0},"end":{"line":8,"character":30}} + {"id":11,"type":"edge","label":"next","inV":8,"outV":10} + {"id":12,"type":"vertex","label":"range","start":{"line":8,"character":32},"end":{"line":8,"character":39}} + {"id":13,"type":"vertex","label":"resultSet"} + {"id":14,"type":"edge","label":"next","inV":13,"outV":12} + {"id":15,"type":"vertex","label":"range","start":{"line":9,"character":4},"end":{"line":9,"character":9}} + {"id":16,"type":"vertex","label":"resultSet"} + {"id":17,"type":"edge","label":"next","inV":16,"outV":15} + {"id":18,"type":"vertex","label":"range","start":{"line":10,"character":8},"end":{"line":10,"character":13}} + {"id":19,"type":"vertex","label":"resultSet"} + {"id":20,"type":"edge","label":"next","inV":19,"outV":18} + {"id":21,"type":"vertex","label":"range","start":{"line":11,"character":4},"end":{"line":11,"character":34}} + {"id":22,"type":"edge","label":"next","inV":8,"outV":21} + {"id":23,"type":"vertex","label":"range","start":{"line":11,"character":36},"end":{"line":11,"character":43}} + {"id":24,"type":"vertex","label":"resultSet"} + {"id":25,"type":"edge","label":"next","inV":24,"outV":23} + {"id":26,"type":"edge","label":"contains","inVs":[4,7,10,12,15,18,21,23],"outV":1} + {"id":27,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\n#[allow]\n```\n\n---\n\nValid forms are:\n\n* \\#\\[allow(lint1, lint2, ..., /\\*opt\\*/ reason = \"...\")\\]"}}} + {"id":28,"type":"edge","label":"textDocument/hover","inV":27,"outV":5} + {"id":29,"type":"vertex","label":"referenceResult"} + {"id":30,"type":"edge","label":"textDocument/references","inV":29,"outV":5} + {"id":31,"type":"edge","label":"item","document":1,"property":"references","inVs":[4],"outV":29} + {"id":32,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmacro_rules! generate_const_from_identifier\n```"}}} + {"id":33,"type":"edge","label":"textDocument/hover","inV":32,"outV":8} + {"id":34,"type":"vertex","label":"packageInformation","name":"foo","manager":"cargo","version":"0.0.0"} + {"id":35,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::generate_const_from_identifier","unique":"scheme","kind":"export"} + {"id":36,"type":"edge","label":"packageInformation","inV":34,"outV":35} + {"id":37,"type":"edge","label":"moniker","inV":35,"outV":8} + {"id":38,"type":"vertex","label":"definitionResult"} + {"id":39,"type":"edge","label":"item","document":1,"inVs":[7],"outV":38} + {"id":40,"type":"edge","label":"textDocument/definition","inV":38,"outV":8} + {"id":41,"type":"vertex","label":"referenceResult"} + {"id":42,"type":"edge","label":"textDocument/references","inV":41,"outV":8} + {"id":43,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[7],"outV":41} + {"id":44,"type":"edge","label":"item","document":1,"property":"references","inVs":[10,21],"outV":41} + {"id":45,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nconst REQ_001: &str = \"encoded_data\"\n```"}}} + {"id":46,"type":"edge","label":"textDocument/hover","inV":45,"outV":13} + {"id":47,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::REQ_001","unique":"scheme","kind":"export"} + {"id":48,"type":"edge","label":"packageInformation","inV":34,"outV":47} + {"id":49,"type":"edge","label":"moniker","inV":47,"outV":13} + {"id":50,"type":"vertex","label":"definitionResult"} + {"id":51,"type":"edge","label":"item","document":1,"inVs":[12],"outV":50} + {"id":52,"type":"edge","label":"textDocument/definition","inV":50,"outV":13} + {"id":53,"type":"vertex","label":"referenceResult"} + {"id":54,"type":"edge","label":"textDocument/references","inV":53,"outV":13} + {"id":55,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[12],"outV":53} + {"id":56,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmod tests\n```"}}} + {"id":57,"type":"edge","label":"textDocument/hover","inV":56,"outV":16} + {"id":58,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests","unique":"scheme","kind":"export"} + {"id":59,"type":"edge","label":"packageInformation","inV":34,"outV":58} + {"id":60,"type":"edge","label":"moniker","inV":58,"outV":16} + {"id":61,"type":"vertex","label":"definitionResult"} + {"id":62,"type":"edge","label":"item","document":1,"inVs":[15],"outV":61} + {"id":63,"type":"edge","label":"textDocument/definition","inV":61,"outV":16} + {"id":64,"type":"vertex","label":"referenceResult"} + {"id":65,"type":"edge","label":"textDocument/references","inV":64,"outV":16} + {"id":66,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[15],"outV":64} + {"id":67,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nextern crate foo\n```"}}} + {"id":68,"type":"edge","label":"textDocument/hover","inV":67,"outV":19} + {"id":69,"type":"vertex","label":"definitionResult"} + {"id":70,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":13,"character":0}} + {"id":71,"type":"edge","label":"contains","inVs":[70],"outV":1} + {"id":72,"type":"edge","label":"item","document":1,"inVs":[70],"outV":69} + {"id":73,"type":"edge","label":"textDocument/definition","inV":69,"outV":19} + {"id":74,"type":"vertex","label":"referenceResult"} + {"id":75,"type":"edge","label":"textDocument/references","inV":74,"outV":19} + {"id":76,"type":"edge","label":"item","document":1,"property":"references","inVs":[18],"outV":74} + {"id":77,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo::tests\n```\n\n```rust\nconst REQ_002: &str = \"encoded_data\"\n```"}}} + {"id":78,"type":"edge","label":"textDocument/hover","inV":77,"outV":24} + {"id":79,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests::REQ_002","unique":"scheme","kind":"export"} + {"id":80,"type":"edge","label":"packageInformation","inV":34,"outV":79} + {"id":81,"type":"edge","label":"moniker","inV":79,"outV":24} + {"id":82,"type":"vertex","label":"definitionResult"} + {"id":83,"type":"edge","label":"item","document":1,"inVs":[23],"outV":82} + {"id":84,"type":"edge","label":"textDocument/definition","inV":82,"outV":24} + {"id":85,"type":"vertex","label":"referenceResult"} + {"id":86,"type":"edge","label":"textDocument/references","inV":85,"outV":24} + {"id":87,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[23],"outV":85} + "#]].assert_eq(stdout); +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 54cd27f4b3b..97c76bf8d17 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -10,6 +10,7 @@ #![allow(clippy::disallowed_types)] +mod cli; mod ratoml; mod support; mod testdir; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 18aface632d..78572e37a9b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -6,11 +6,13 @@ use std::{ }; use crossbeam_channel::{after, select, Receiver}; +use itertools::Itertools; use lsp_server::{Connection, Message, Notification, Request}; use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url}; use parking_lot::{Mutex, MutexGuard}; use paths::{Utf8Path, Utf8PathBuf}; use rust_analyzer::{ + cli::flags, config::{Config, ConfigChange, ConfigErrors}, lsp, main_loop, }; @@ -84,6 +86,46 @@ impl Project<'_> { self } + pub(crate) fn run_lsif(self) -> String { + let tmp_dir = self.tmp_dir.unwrap_or_else(|| { + if self.root_dir_contains_symlink { + TestDir::new_symlink() + } else { + TestDir::new() + } + }); + + let FixtureWithProjectMeta { + fixture, + mini_core, + proc_macro_names, + toolchain, + target_data_layout: _, + } = FixtureWithProjectMeta::parse(self.fixture); + assert!(proc_macro_names.is_empty()); + assert!(mini_core.is_none()); + assert!(toolchain.is_none()); + + for entry in fixture { + let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); + } + + let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf()); + let mut buf = Vec::new(); + flags::Lsif::run( + flags::Lsif { + path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(), + exclude_vendored_libraries: false, + }, + &mut buf, + None, + ) + .unwrap(); + String::from_utf8(buf).unwrap() + } + pub(crate) fn server(self) -> Server { static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(()); let tmp_dir = self.tmp_dir.unwrap_or_else(|| { |
