From beb79ed104c686d8704eb7042318eefea78770df Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Fri, 8 May 2020 16:59:52 -0700 Subject: Begin transition to new fields for JsonProject crate cfgs This starts the transition to a new method of documenting the cfgs that are enabled for a given crate in the json file. This is changing from a list of atoms and a dict of key:value pairs, to a list of strings that is equivalent to that returned by `rustc --print cfg ..`, and parsed in the same manner by rust-analyzer. This is the first of two changes, which adds the new field that contains the list of strings. Next change will complete the transition and remove the previous fields. --- crates/ra_project_model/src/json_project.rs | 79 ++++++++++++++++++++++++++ crates/ra_project_model/src/lib.rs | 10 ++++ crates/rust-analyzer/tests/heavy_tests/main.rs | 5 +- 3 files changed, 92 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs index b030c8a6a..bd2bae15e 100644 --- a/crates/ra_project_model/src/json_project.rs +++ b/crates/ra_project_model/src/json_project.rs @@ -20,8 +20,17 @@ pub struct Crate { pub(crate) root_module: PathBuf, pub(crate) edition: Edition, pub(crate) deps: Vec, + + // This is the preferred method of providing cfg options. + #[serde(default)] + pub(crate) cfg: FxHashSet, + + // These two are here for transition only. + #[serde(default)] pub(crate) atom_cfgs: FxHashSet, + #[serde(default)] pub(crate) key_value_cfgs: FxHashMap, + pub(crate) out_dir: Option, pub(crate) proc_macro_dylib_path: Option, } @@ -54,3 +63,73 @@ pub struct JsonProject { pub(crate) roots: Vec, pub(crate) crates: Vec, } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test_crate_deserialization() { + let raw_json = json!( { + "crate_id": 2, + "root_module": "this/is/a/file/path.rs", + "deps": [ + { + "crate": 1, + "name": "some_dep_crate" + }, + ], + "edition": "2015", + "cfg": [ + "atom_1", + "atom_2", + "feature=feature_1", + "feature=feature_2", + "other=value", + ], + + }); + + let krate: Crate = serde_json::from_value(raw_json).unwrap(); + + assert!(krate.cfg.contains(&"atom_1".to_string())); + assert!(krate.cfg.contains(&"atom_2".to_string())); + assert!(krate.cfg.contains(&"feature=feature_1".to_string())); + assert!(krate.cfg.contains(&"feature=feature_2".to_string())); + assert!(krate.cfg.contains(&"other=value".to_string())); + } + + #[test] + fn test_crate_deserialization_old_json() { + let raw_json = json!( { + "crate_id": 2, + "root_module": "this/is/a/file/path.rs", + "deps": [ + { + "crate": 1, + "name": "some_dep_crate" + }, + ], + "edition": "2015", + "atom_cfgs": [ + "atom_1", + "atom_2", + ], + "key_value_cfgs": { + "feature": "feature_1", + "feature": "feature_2", + "other": "value", + }, + }); + + let krate: Crate = serde_json::from_value(raw_json).unwrap(); + + assert!(krate.atom_cfgs.contains(&"atom_1".to_string())); + assert!(krate.atom_cfgs.contains(&"atom_2".to_string())); + assert!(krate.key_value_cfgs.contains_key(&"feature".to_string())); + assert_eq!(krate.key_value_cfgs.get("feature"), Some(&"feature_2".to_string())); + assert!(krate.key_value_cfgs.contains_key(&"other".to_string())); + assert_eq!(krate.key_value_cfgs.get("other"), Some(&"value".to_string())); + } +} diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 731cbd291..e7da683d6 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -273,6 +273,16 @@ impl ProjectWorkspace { }; let cfg_options = { let mut opts = default_cfg_options.clone(); + for cfg in &krate.cfg { + match cfg.find('=') { + None => opts.insert_atom(cfg.into()), + Some(pos) => { + let key = &cfg[..pos]; + let value = cfg[pos + 1..].trim_matches('"'); + opts.insert_key_value(key.into(), value.into()); + } + } + } for name in &krate.atom_cfgs { opts.insert_atom(name.into()); } diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 07b8114c6..3d5574c7f 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -384,8 +384,9 @@ fn test_missing_module_code_action_in_json_project() { "root_module": path.join("src/lib.rs"), "deps": [], "edition": "2015", - "atom_cfgs": [], - "key_value_cfgs": {} + "cfg": [ "cfg_atom_1", "feature=cfg_1"], + "atom_cfgs": ["atom_2"], + "key_value_cfgs": { "feature": "key_value_feature", "other": "value"} } ] }); -- cgit v1.2.3 From 5cd4eb6dd6d8c733077a6aeea5d2cc0812ded096 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Fri, 22 May 2020 22:28:30 +0200 Subject: Add preliminary implementation of extract struct from enum variant --- crates/ra_assists/Cargo.toml | 1 + crates/ra_assists/src/assist_context.rs | 62 +++- .../handlers/extract_struct_from_enum_variant.rs | 338 +++++++++++++++++++++ crates/ra_assists/src/lib.rs | 2 + 4 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs (limited to 'crates') diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index 3bcf58ba4..f3481bdeb 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml @@ -20,5 +20,6 @@ ra_fmt = { path = "../ra_fmt" } ra_prof = { path = "../ra_prof" } ra_db = { path = "../ra_db" } ra_ide_db = { path = "../ra_ide_db" } +hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } hir = { path = "../ra_hir", package = "ra_hir" } test_utils = { path = "../test_utils" } diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 5b1a4680b..6291c68de 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -2,7 +2,7 @@ use algo::find_covering_element; use hir::Semantics; -use ra_db::{FileId, FileRange}; +use ra_db::{FileId, FileRange, FilePosition}; use ra_fmt::{leading_indent, reindent}; use ra_ide_db::{ source_change::{SourceChange, SourceFileEdit}, @@ -19,6 +19,7 @@ use crate::{ assist_config::{AssistConfig, SnippetCap}, Assist, AssistId, GroupLabel, ResolvedAssist, }; +use rustc_hash::FxHashMap; /// `AssistContext` allows to apply an assist or check if it could be applied. /// @@ -138,6 +139,16 @@ impl Assists { let label = Assist::new(id, label.into(), None, target); self.add_impl(label, f) } + pub(crate) fn add_in_multiple_files( + &mut self, + id: AssistId, + label: impl Into, + target: TextRange, + f: impl FnOnce(&mut AssistDirector), + ) -> Option<()> { + let label = Assist::new(id, label.into(), None, target); + self.add_impl_multiple_files(label, f) + } pub(crate) fn add_group( &mut self, group: &GroupLabel, @@ -162,6 +173,27 @@ impl Assists { Some(()) } + fn add_impl_multiple_files(&mut self, label: Assist, f: impl FnOnce(&mut AssistDirector)) -> Option<()> { + let change_label = label.label.clone(); + if !self.resolve { + return None + } + let mut director = AssistDirector::new(change_label.clone()); + f(&mut director); + let changes = director.finish(); + let file_edits: Vec = changes.into_iter() + .map(|mut change| change.source_file_edits.pop().unwrap()).collect(); + + let source_change = SourceChange { + source_file_edits: file_edits, + file_system_edits: vec![], + is_snippet: false, + }; + + self.buf.push((label, Some(source_change))); + Some(()) + } + fn finish(mut self) -> Vec<(Assist, Option)> { self.buf.sort_by_key(|(label, _edit)| label.target.len()); self.buf @@ -255,3 +287,31 @@ impl AssistBuilder { res } } + +pub(crate) struct AssistDirector { + source_changes: Vec, + builders: FxHashMap, + change_label: String +} + +impl AssistDirector { + fn new(change_label: String) -> AssistDirector { + AssistDirector { + source_changes: vec![], + builders: FxHashMap::default(), + change_label + } + } + + pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { + let mut builder = self.builders.entry(file_id).or_insert(AssistBuilder::new(file_id)); + f(&mut builder); + } + + fn finish(mut self) -> Vec { + for (file_id, builder) in self.builders.into_iter().collect::>() { + self.source_changes.push(builder.finish()); + } + self.source_changes + } +} diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs new file mode 100644 index 000000000..6e19a6feb --- /dev/null +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -0,0 +1,338 @@ +use hir_expand::name::AsName; +use ra_ide_db::{ + defs::Definition, imports_locator::ImportsLocator, search::Reference, RootDatabase, +}; +use ra_syntax::{ + algo::find_node_at_offset, + ast::{self, AstNode, NameOwner}, + SourceFile, SyntaxNode, TextRange, TextSize, +}; +use stdx::format_to; + +use crate::{ + assist_context::{AssistBuilder, AssistDirector}, + utils::insert_use_statement, + AssistContext, AssistId, Assists, +}; +use ast::{ArgListOwner, VisibilityOwner}; +use hir::{EnumVariant, Module, ModuleDef}; +use ra_fmt::leading_indent; +use rustc_hash::FxHashSet; +use ra_db::FileId; + +// Assist extract_struct_from_enum +// +// Extracts a from struct from enum variant +// +// ``` +// enum A { <|>One(u32, u32) } +// ``` +// -> +// ``` +// struct One(pub u32, pub u32); +// +// enum A { One(One) }" +// ``` +pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let variant = ctx.find_node_at_offset::()?; + let field_list = match variant.kind() { + ast::StructKind::Tuple(field_list) => field_list, + _ => return None, + }; + let variant_name = variant.name()?.to_string(); + let enum_ast = variant.parent_enum(); + let enum_name = enum_ast.name().unwrap().to_string(); + let visibility = enum_ast.visibility(); + let variant_hir = ctx.sema.to_def(&variant)?; + + if existing_struct_def(ctx.db, &variant_name, &variant_hir) { + return None; + } + + let target = variant.syntax().text_range(); + return acc.add_in_multiple_files( + AssistId("extract_struct_from_enum_variant"), + "Extract struct from enum variant", + target, + |edit| { + let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); + let res = definition.find_usages(&ctx.db, None); + let module_def = mod_def_for_target_module(ctx, &enum_name); + let start_offset = variant.parent_enum().syntax().text_range().start(); + let mut seen_files_map: FxHashSet = FxHashSet::default(); + seen_files_map.insert(module_def.module(ctx.db).unwrap()); + for reference in res { + let source_file = ctx.sema.parse(reference.file_range.file_id); + update_reference( + ctx, + edit, + reference, + &source_file, + &module_def, + &mut seen_files_map, + ); + } + extract_struct_def( + edit, + enum_ast.syntax(), + &variant_name, + &field_list.to_string(), + start_offset, + ctx.frange.file_id, + &visibility, + ); + let list_range = field_list.syntax().text_range(); + update_variant(edit, &variant_name, ctx.frange.file_id, list_range); + }, + ); +} + +fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool { + let module_defs = variant.parent_enum(db).module(db).scope(db, None); + for (name, _) in module_defs { + if name.to_string() == variant_name.to_string() { + return true; + } + } + false +} + +fn mod_def_for_target_module(ctx: &AssistContext, enum_name: &str) -> ModuleDef { + ImportsLocator::new(ctx.db).find_imports(enum_name).first().unwrap().left().unwrap() +} + +fn insert_use_import( + ctx: &AssistContext, + builder: &mut AssistBuilder, + path: &ast::PathExpr, + module: &Module, + module_def: &ModuleDef, + path_segment: ast::NameRef, +) -> Option<()> { + let db = ctx.db; + let mod_path = module.find_use_path(db, module_def.clone()); + if let Some(mut mod_path) = mod_path { + mod_path.segments.pop(); + mod_path.segments.push(path_segment.as_name()); + insert_use_statement(path.syntax(), &mod_path, ctx, builder.text_edit_builder()); + } + Some(()) +} + +fn extract_struct_def( + edit: &mut AssistDirector, + enum_ast: &SyntaxNode, + variant_name: &str, + variant_list: &str, + start_offset: TextSize, + file_id: FileId, + visibility: &Option, +) -> Option<()> { + let visibility_string = if let Some(visibility) = visibility { + format!("{} ", visibility.to_string()) + } else { + "".to_string() + }; + let mut buf = String::new(); + let indent = if let Some(indent) = leading_indent(enum_ast) { + indent.to_string() + } else { + "".to_string() + }; + + format_to!( + buf, + r#"{}struct {}{}; + +{}"#, + visibility_string, + variant_name, + list_with_visibility(variant_list), + indent + ); + edit.perform(file_id, |builder| { + builder.insert(start_offset, buf); + }); + Some(()) +} + +fn update_variant( + edit: &mut AssistDirector, + variant_name: &str, + file_id: FileId, + list_range: TextRange, +) -> Option<()> { + let inside_variant_range = TextRange::new( + list_range.start().checked_add(TextSize::from(1))?, + list_range.end().checked_sub(TextSize::from(1))?, + ); + edit.perform(file_id, |builder| { + builder.set_file(file_id); + builder.replace(inside_variant_range, variant_name); + }); + Some(()) +} + +fn update_reference( + ctx: &AssistContext, + edit: &mut AssistDirector, + reference: Reference, + source_file: &SourceFile, + module_def: &ModuleDef, + seen_files_map: &mut FxHashSet, +) -> Option<()> { + let path_expr: ast::PathExpr = find_node_at_offset::( + source_file.syntax(), + reference.file_range.range.start(), + )?; + let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; + let list = call.arg_list()?; + let segment = path_expr.path()?.segment()?; + let list_range = list.syntax().text_range(); + let inside_list_range = TextRange::new( + list_range.start().checked_add(TextSize::from(1))?, + list_range.end().checked_sub(TextSize::from(1))?, + ); + edit.perform(reference.file_range.file_id, |builder| { + let module = ctx.sema.scope(&path_expr.syntax()).module().unwrap(); + if !seen_files_map.contains(&module) { + if insert_use_import( + ctx, + builder, + &path_expr, + &module, + module_def, + segment.name_ref().unwrap(), + ) + .is_some() + { + seen_files_map.insert(module); + } + } + builder.replace(inside_list_range, format!("{}{}", segment, list)); + }); + Some(()) +} + +fn list_with_visibility(list: &str) -> String { + list.split(',') + .map(|part| { + let index = if part.chars().next().unwrap() == '(' { 1usize } else { 0 }; + let mut mod_part = part.trim().to_string(); + mod_part.insert_str(index, "pub "); + mod_part + }) + .collect::>() + .join(", ") +} + +#[cfg(test)] +mod tests { + + use crate::{utils::FamousDefs, tests::{check_assist, check_assist_not_applicable}}; + + use super::*; + + #[test] + fn test_extract_struct_several_fields() { + check_assist( + extract_struct_from_enum, + "enum A { <|>One(u32, u32) }", + r#"struct One(pub u32, pub u32); + +enum A { One(One) }"#, + ); + } + + #[test] + fn test_extract_struct_one_field() { + check_assist( + extract_struct_from_enum, + "enum A { <|>One(u32) }", + r#"struct One(pub u32); + +enum A { One(One) }"#, + ); + } + + #[test] + fn test_extract_struct_pub_visibility() { + check_assist( + extract_struct_from_enum, + "pub enum A { <|>One(u32, u32) }", + r#"pub struct One(pub u32, pub u32); + +pub enum A { One(One) }"#, + ); + } + + #[test] + fn test_extract_struct_with_complex_imports() { + check_assist( + extract_struct_from_enum, + r#"mod my_mod { + fn another_fn() { + let m = my_other_mod::MyEnum::MyField(1, 1); + } + + pub mod my_other_mod { + fn another_fn() { + let m = MyEnum::MyField(1, 1); + } + + pub enum MyEnum { + <|>MyField(u8, u8), + } + } +} + +fn another_fn() { + let m = my_mod::my_other_mod::MyEnum::MyField(1, 1); +}"#, + r#"use my_mod::my_other_mod::MyField; + +mod my_mod { + use my_other_mod::MyField; + + fn another_fn() { + let m = my_other_mod::MyEnum::MyField(MyField(1, 1)); + } + + pub mod my_other_mod { + fn another_fn() { + let m = MyEnum::MyField(MyField(1, 1)); + } + + pub struct MyField(pub u8, pub u8); + + pub enum MyEnum { + MyField(MyField), + } + } +} + +fn another_fn() { + let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1)); +}"#, + ); + } + + fn check_not_applicable(ra_fixture: &str) { + let fixture = + format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); + check_assist_not_applicable(extract_struct_from_enum, &fixture) + } + + #[test] + fn test_extract_enum_not_applicable_for_element_with_no_fields() { + check_not_applicable("enum A { <|>One }"); + } + + #[test] + fn test_extract_enum_not_applicable_if_struct_exists() { + check_not_applicable( + r#"struct One; + enum A { <|>One(u8) }"#, + ); + } +} diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 464bc03dd..9933f7a50 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -115,6 +115,7 @@ mod handlers { mod change_return_type_to_result; mod change_visibility; mod early_return; + mod extract_struct_from_enum_variant; mod fill_match_arms; mod fix_visibility; mod flip_binexpr; @@ -154,6 +155,7 @@ mod handlers { change_return_type_to_result::change_return_type_to_result, change_visibility::change_visibility, early_return::convert_to_guarded_return, + extract_struct_from_enum_variant::extract_struct_from_enum, fill_match_arms::fill_match_arms, fix_visibility::fix_visibility, flip_binexpr::flip_binexpr, -- cgit v1.2.3 From 04a35784df4cf267a8bbce6d5542869ed1a52fcb Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Fri, 22 May 2020 22:43:52 +0200 Subject: Formatting and remove unused imports --- crates/ra_assists/src/assist_context.rs | 30 ++++++++++++---------- .../handlers/extract_struct_from_enum_variant.rs | 7 +++-- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 6291c68de..52bc7820e 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -2,7 +2,7 @@ use algo::find_covering_element; use hir::Semantics; -use ra_db::{FileId, FileRange, FilePosition}; +use ra_db::{FileId, FileRange}; use ra_fmt::{leading_indent, reindent}; use ra_ide_db::{ source_change::{SourceChange, SourceFileEdit}, @@ -173,16 +173,20 @@ impl Assists { Some(()) } - fn add_impl_multiple_files(&mut self, label: Assist, f: impl FnOnce(&mut AssistDirector)) -> Option<()> { + fn add_impl_multiple_files( + &mut self, + label: Assist, + f: impl FnOnce(&mut AssistDirector), + ) -> Option<()> { let change_label = label.label.clone(); if !self.resolve { - return None + return None; } let mut director = AssistDirector::new(change_label.clone()); f(&mut director); let changes = director.finish(); - let file_edits: Vec = changes.into_iter() - .map(|mut change| change.source_file_edits.pop().unwrap()).collect(); + let file_edits: Vec = + changes.into_iter().map(|mut change| change.source_file_edits.pop().unwrap()).collect(); let source_change = SourceChange { source_file_edits: file_edits, @@ -291,16 +295,12 @@ impl AssistBuilder { pub(crate) struct AssistDirector { source_changes: Vec, builders: FxHashMap, - change_label: String -} + change_label: String, +} impl AssistDirector { fn new(change_label: String) -> AssistDirector { - AssistDirector { - source_changes: vec![], - builders: FxHashMap::default(), - change_label - } + AssistDirector { source_changes: vec![], builders: FxHashMap::default(), change_label } } pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { @@ -309,8 +309,10 @@ impl AssistDirector { } fn finish(mut self) -> Vec { - for (file_id, builder) in self.builders.into_iter().collect::>() { - self.source_changes.push(builder.finish()); + for (file_id, builder) in + self.builders.into_iter().collect::>() + { + self.source_changes.push(builder.finish()); } self.source_changes } diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 6e19a6feb..57907a503 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -16,9 +16,9 @@ use crate::{ }; use ast::{ArgListOwner, VisibilityOwner}; use hir::{EnumVariant, Module, ModuleDef}; +use ra_db::FileId; use ra_fmt::leading_indent; use rustc_hash::FxHashSet; -use ra_db::FileId; // Assist extract_struct_from_enum // @@ -229,7 +229,10 @@ fn list_with_visibility(list: &str) -> String { #[cfg(test)] mod tests { - use crate::{utils::FamousDefs, tests::{check_assist, check_assist_not_applicable}}; + use crate::{ + tests::{check_assist, check_assist_not_applicable}, + utils::FamousDefs, + }; use super::*; -- cgit v1.2.3 From 97ffe3c6e8289553e3b3bd22392a22eaa8d61f42 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Fri, 22 May 2020 22:47:25 +0200 Subject: Refactor AssistDirector --- crates/ra_assists/src/assist_context.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 52bc7820e..37de4f590 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -178,11 +178,10 @@ impl Assists { label: Assist, f: impl FnOnce(&mut AssistDirector), ) -> Option<()> { - let change_label = label.label.clone(); if !self.resolve { return None; } - let mut director = AssistDirector::new(change_label.clone()); + let mut director = AssistDirector::new(); f(&mut director); let changes = director.finish(); let file_edits: Vec = @@ -295,12 +294,11 @@ impl AssistBuilder { pub(crate) struct AssistDirector { source_changes: Vec, builders: FxHashMap, - change_label: String, } impl AssistDirector { - fn new(change_label: String) -> AssistDirector { - AssistDirector { source_changes: vec![], builders: FxHashMap::default(), change_label } + fn new() -> AssistDirector { + AssistDirector { source_changes: vec![], builders: FxHashMap::default() } } pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { @@ -309,7 +307,7 @@ impl AssistDirector { } fn finish(mut self) -> Vec { - for (file_id, builder) in + for (_, builder) in self.builders.into_iter().collect::>() { self.source_changes.push(builder.finish()); -- cgit v1.2.3 From ef1aaeb59516b16f1b83eb7cdb22f1bcdcc46446 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Fri, 22 May 2020 22:59:17 +0200 Subject: More formatting --- crates/ra_assists/src/assist_context.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 37de4f590..e7220eea9 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -307,9 +307,7 @@ impl AssistDirector { } fn finish(mut self) -> Vec { - for (_, builder) in - self.builders.into_iter().collect::>() - { + for (_, builder) in self.builders.into_iter().collect::>() { self.source_changes.push(builder.finish()); } self.source_changes -- cgit v1.2.3 From fce10200a0d666fbd2e2faa84b0526f586485bb3 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sat, 23 May 2020 01:23:40 +0200 Subject: Better naming and fix some review comments --- crates/ra_assists/src/assist_context.rs | 13 ++++++------- .../src/handlers/extract_struct_from_enum_variant.rs | 16 ++++++++-------- 2 files changed, 14 insertions(+), 15 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index e7220eea9..94286b497 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -292,13 +292,12 @@ impl AssistBuilder { } pub(crate) struct AssistDirector { - source_changes: Vec, builders: FxHashMap, } impl AssistDirector { fn new() -> AssistDirector { - AssistDirector { source_changes: vec![], builders: FxHashMap::default() } + AssistDirector { builders: FxHashMap::default() } } pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { @@ -306,10 +305,10 @@ impl AssistDirector { f(&mut builder); } - fn finish(mut self) -> Vec { - for (_, builder) in self.builders.into_iter().collect::>() { - self.source_changes.push(builder.finish()); - } - self.source_changes + fn finish(self) -> Vec { + self.builders + .into_iter() + .map(|(_, builder)| builder.finish()) + .collect::>() } } diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 57907a503..3250eed5b 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -59,8 +59,8 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - let res = definition.find_usages(&ctx.db, None); let module_def = mod_def_for_target_module(ctx, &enum_name); let start_offset = variant.parent_enum().syntax().text_range().start(); - let mut seen_files_map: FxHashSet = FxHashSet::default(); - seen_files_map.insert(module_def.module(ctx.db).unwrap()); + let mut visited_modules_set: FxHashSet = FxHashSet::default(); + visited_modules_set.insert(module_def.module(ctx.db).unwrap()); for reference in res { let source_file = ctx.sema.parse(reference.file_range.file_id); update_reference( @@ -69,7 +69,7 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - reference, &source_file, &module_def, - &mut seen_files_map, + &mut visited_modules_set, ); } extract_struct_def( @@ -101,7 +101,7 @@ fn mod_def_for_target_module(ctx: &AssistContext, enum_name: &str) -> ModuleDef ImportsLocator::new(ctx.db).find_imports(enum_name).first().unwrap().left().unwrap() } -fn insert_use_import( +fn insert_import( ctx: &AssistContext, builder: &mut AssistBuilder, path: &ast::PathExpr, @@ -179,7 +179,7 @@ fn update_reference( reference: Reference, source_file: &SourceFile, module_def: &ModuleDef, - seen_files_map: &mut FxHashSet, + visited_modules_set: &mut FxHashSet, ) -> Option<()> { let path_expr: ast::PathExpr = find_node_at_offset::( source_file.syntax(), @@ -195,8 +195,8 @@ fn update_reference( ); edit.perform(reference.file_range.file_id, |builder| { let module = ctx.sema.scope(&path_expr.syntax()).module().unwrap(); - if !seen_files_map.contains(&module) { - if insert_use_import( + if !visited_modules_set.contains(&module) { + if insert_import( ctx, builder, &path_expr, @@ -206,7 +206,7 @@ fn update_reference( ) .is_some() { - seen_files_map.insert(module); + visited_modules_set.insert(module); } } builder.replace(inside_list_range, format!("{}{}", segment, list)); -- cgit v1.2.3 From 4984520ef565e926ba08c6512715ed631e4527e4 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sat, 23 May 2020 01:27:11 +0200 Subject: Use default instead of new in AssistDirector --- crates/ra_assists/src/assist_context.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 94286b497..bc5481494 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -181,7 +181,7 @@ impl Assists { if !self.resolve { return None; } - let mut director = AssistDirector::new(); + let mut director = AssistDirector::default(); f(&mut director); let changes = director.finish(); let file_edits: Vec = @@ -296,10 +296,6 @@ pub(crate) struct AssistDirector { } impl AssistDirector { - fn new() -> AssistDirector { - AssistDirector { builders: FxHashMap::default() } - } - pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { let mut builder = self.builders.entry(file_id).or_insert(AssistBuilder::new(file_id)); f(&mut builder); @@ -312,3 +308,9 @@ impl AssistDirector { .collect::>() } } + +impl Default for AssistDirector { + fn default() -> Self { + AssistDirector { builders: FxHashMap::default() } + } +} -- cgit v1.2.3 From 6ee1c60c9cff781e10d6379f68fc951378403f6b Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sat, 23 May 2020 01:41:08 +0200 Subject: Further review fixes --- crates/ra_assists/Cargo.toml | 1 - .../src/handlers/extract_struct_from_enum_variant.rs | 20 +++++++++----------- crates/ra_hir/src/lib.rs | 5 +++-- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index f3481bdeb..3bcf58ba4 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml @@ -20,6 +20,5 @@ ra_fmt = { path = "../ra_fmt" } ra_prof = { path = "../ra_prof" } ra_db = { path = "../ra_db" } ra_ide_db = { path = "../ra_ide_db" } -hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } hir = { path = "../ra_hir", package = "ra_hir" } test_utils = { path = "../test_utils" } diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 3250eed5b..359283802 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -1,4 +1,3 @@ -use hir_expand::name::AsName; use ra_ide_db::{ defs::Definition, imports_locator::ImportsLocator, search::Reference, RootDatabase, }; @@ -15,14 +14,14 @@ use crate::{ AssistContext, AssistId, Assists, }; use ast::{ArgListOwner, VisibilityOwner}; -use hir::{EnumVariant, Module, ModuleDef}; +use hir::{AsName, EnumVariant, Module, ModuleDef}; use ra_db::FileId; use ra_fmt::leading_indent; use rustc_hash::FxHashSet; // Assist extract_struct_from_enum // -// Extracts a from struct from enum variant +// Extracts a struct from enum variant // // ``` // enum A { <|>One(u32, u32) } @@ -41,7 +40,7 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - }; let variant_name = variant.name()?.to_string(); let enum_ast = variant.parent_enum(); - let enum_name = enum_ast.name().unwrap().to_string(); + let enum_name = enum_ast.name()?.to_string(); let visibility = enum_ast.visibility(); let variant_hir = ctx.sema.to_def(&variant)?; @@ -88,13 +87,12 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - } fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool { - let module_defs = variant.parent_enum(db).module(db).scope(db, None); - for (name, _) in module_defs { - if name.to_string() == variant_name.to_string() { - return true; - } - } - false + variant + .parent_enum(db) + .module(db) + .scope(db, None) + .into_iter() + .any(|(name, _)| name.to_string() == variant_name.to_string()) } fn mod_def_for_target_module(ctx: &AssistContext, enum_name: &str) -> ModuleDef { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index c5df4ac24..4af0f046a 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -70,7 +70,8 @@ pub use hir_def::{ type_ref::Mutability, }; pub use hir_expand::{ - hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, - MacroFile, Origin, + hygiene::Hygiene, + name::{AsName, Name}, + HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, }; pub use hir_ty::{display::HirDisplay, CallableDef}; -- cgit v1.2.3 From 3a244e02b53687161d4cc39254cb9a432756017f Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sat, 23 May 2020 11:53:02 +0200 Subject: Remove unwraps where possible --- .../handlers/extract_struct_from_enum_variant.rs | 33 ++++++++-------------- 1 file changed, 11 insertions(+), 22 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 359283802..d5397bf21 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -39,15 +39,16 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - _ => return None, }; let variant_name = variant.name()?.to_string(); - let enum_ast = variant.parent_enum(); - let enum_name = enum_ast.name()?.to_string(); - let visibility = enum_ast.visibility(); let variant_hir = ctx.sema.to_def(&variant)?; - if existing_struct_def(ctx.db, &variant_name, &variant_hir) { return None; } - + let enum_ast = variant.parent_enum(); + let enum_name = enum_ast.name()?.to_string(); + let visibility = enum_ast.visibility(); + let current_module_def = + ImportsLocator::new(ctx.db).find_imports(&enum_name).first()?.left()?; + let current_module = current_module_def.module(ctx.db)?; let target = variant.syntax().text_range(); return acc.add_in_multiple_files( AssistId("extract_struct_from_enum_variant"), @@ -56,10 +57,9 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - |edit| { let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); let res = definition.find_usages(&ctx.db, None); - let module_def = mod_def_for_target_module(ctx, &enum_name); let start_offset = variant.parent_enum().syntax().text_range().start(); let mut visited_modules_set: FxHashSet = FxHashSet::default(); - visited_modules_set.insert(module_def.module(ctx.db).unwrap()); + visited_modules_set.insert(current_module); for reference in res { let source_file = ctx.sema.parse(reference.file_range.file_id); update_reference( @@ -67,7 +67,7 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - edit, reference, &source_file, - &module_def, + ¤t_module_def, &mut visited_modules_set, ); } @@ -95,10 +95,6 @@ fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVari .any(|(name, _)| name.to_string() == variant_name.to_string()) } -fn mod_def_for_target_module(ctx: &AssistContext, enum_name: &str) -> ModuleDef { - ImportsLocator::new(ctx.db).find_imports(enum_name).first().unwrap().left().unwrap() -} - fn insert_import( ctx: &AssistContext, builder: &mut AssistBuilder, @@ -186,23 +182,16 @@ fn update_reference( let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; let list = call.arg_list()?; let segment = path_expr.path()?.segment()?; + let segment_name = segment.name_ref()?; + let module = ctx.sema.scope(&path_expr.syntax()).module()?; let list_range = list.syntax().text_range(); let inside_list_range = TextRange::new( list_range.start().checked_add(TextSize::from(1))?, list_range.end().checked_sub(TextSize::from(1))?, ); edit.perform(reference.file_range.file_id, |builder| { - let module = ctx.sema.scope(&path_expr.syntax()).module().unwrap(); if !visited_modules_set.contains(&module) { - if insert_import( - ctx, - builder, - &path_expr, - &module, - module_def, - segment.name_ref().unwrap(), - ) - .is_some() + if insert_import(ctx, builder, &path_expr, &module, module_def, segment_name).is_some() { visited_modules_set.insert(module); } -- cgit v1.2.3 From e2974ba8f7d862eac084ada2fdf327bbde803bed Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sat, 23 May 2020 11:57:12 +0200 Subject: Remove unnecessary set_file and change variable positions for better readability --- crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index d5397bf21..dd2fd57a7 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -127,12 +127,12 @@ fn extract_struct_def( } else { "".to_string() }; - let mut buf = String::new(); let indent = if let Some(indent) = leading_indent(enum_ast) { indent.to_string() } else { "".to_string() }; + let mut buf = String::new(); format_to!( buf, @@ -161,7 +161,6 @@ fn update_variant( list_range.end().checked_sub(TextSize::from(1))?, ); edit.perform(file_id, |builder| { - builder.set_file(file_id); builder.replace(inside_variant_range, variant_name); }); Some(()) -- cgit v1.2.3 From 08aa8e1de717425ebf49796df1515d9fbd8b2e3e Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sun, 24 May 2020 14:53:12 +0200 Subject: Further refactoring under review comments --- .../src/handlers/extract_struct_from_enum_variant.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index dd2fd57a7..a36587633 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -6,7 +6,6 @@ use ra_syntax::{ ast::{self, AstNode, NameOwner}, SourceFile, SyntaxNode, TextRange, TextSize, }; -use stdx::format_to; use crate::{ assist_context::{AssistBuilder, AssistDirector}, @@ -58,7 +57,7 @@ pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) - let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); let res = definition.find_usages(&ctx.db, None); let start_offset = variant.parent_enum().syntax().text_range().start(); - let mut visited_modules_set: FxHashSet = FxHashSet::default(); + let mut visited_modules_set = FxHashSet::default(); visited_modules_set.insert(current_module); for reference in res { let source_file = ctx.sema.parse(reference.file_range.file_id); @@ -132,10 +131,7 @@ fn extract_struct_def( } else { "".to_string() }; - let mut buf = String::new(); - - format_to!( - buf, + let struct_def = format!( r#"{}struct {}{}; {}"#, @@ -145,7 +141,7 @@ fn extract_struct_def( indent ); edit.perform(file_id, |builder| { - builder.insert(start_offset, buf); + builder.insert(start_offset, struct_def); }); Some(()) } -- cgit v1.2.3 From a27ede88a3a9063a3a2265b668b1c41b589852f5 Mon Sep 17 00:00:00 2001 From: Roland Ruckerbauer Date: Sat, 30 May 2020 14:09:10 +0200 Subject: Fix problem with format string tokenization Fixed by just not handling closing curlybrace escaping. --- crates/ra_syntax/src/ast/tokens.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 3cd6d99c3..04b0a4480 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs @@ -418,14 +418,9 @@ pub trait HasFormatSpecifier: AstToken { let mut cloned = chars.clone().take(2); let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); - let second = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); if first != Some('}') { continue; } - if second == Some('}') { - // Escaped format end specifier, `}}` - continue; - } skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); } _ => { -- cgit v1.2.3 From 780c89959a2f7362eb51508d83863eeff9a49e4c Mon Sep 17 00:00:00 2001 From: Roland Ruckerbauer Date: Sat, 30 May 2020 18:35:11 +0200 Subject: Test case for format string highlighting of closing curlybrace --- crates/ra_ide/src/snapshots/highlight_strings.html | 1 + crates/ra_ide/src/syntax_highlighting/tests.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 326744361..41cddd0ff 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html @@ -52,6 +52,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd println!("{argument}", argument = "test"); // => "test" println!("{name} {}", 1, name = 2); // => "2 1" println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" + println!("{{{}}}", 2); // => "{2}" println!("Hello {:5}!", "x"); println!("Hello {:1$}!", "x", 5); println!("Hello {1:0$}!", 5, "x"); diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index eb43a23da..7dc229cab 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -218,6 +218,7 @@ fn main() { println!("{argument}", argument = "test"); // => "test" println!("{name} {}", 1, name = 2); // => "2 1" println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" + println!("{{{}}}", 2); // => "{2}" println!("Hello {:5}!", "x"); println!("Hello {:1$}!", "x", 5); println!("Hello {1:0$}!", 5, "x"); -- cgit v1.2.3 From 030d78345fa79af07f8ebd89a9d244576fac992b Mon Sep 17 00:00:00 2001 From: veetaha Date: Sat, 23 May 2020 04:58:22 +0300 Subject: Fix invoking cargo without consulting CARGO or standard installation paths --- crates/rust-analyzer/Cargo.toml | 1 + crates/rust-analyzer/src/main_loop/handlers.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 65b487db3..2e49448cc 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -48,6 +48,7 @@ hir = { path = "../ra_hir", package = "ra_hir" } hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } ra_proc_macro_srv = { path = "../ra_proc_macro_srv" } +ra_toolchain = { path = "../ra_toolchain" } [target.'cfg(windows)'.dependencies] winapi = "0.3.8" diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 1f910ff82..1b5b3325c 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -40,6 +40,7 @@ use crate::{ world::WorldSnapshot, LspError, Result, }; +use anyhow::Context; pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { let _p = profile("handle_analyzer_status"); @@ -982,10 +983,15 @@ fn to_lsp_runnable( target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) } }; + let cargo_path = ra_toolchain::cargo() + .to_str() + .context("Path to cargo executable contains invalid UTF8 characters")? + .to_owned(); + Ok(lsp_ext::Runnable { range: to_proto::range(&line_index, runnable.range), label, - bin: "cargo".to_string(), + bin: cargo_path, args, extra_args, env: { -- cgit v1.2.3 From a419cedb1cc661349a022262c8b03993e063252f Mon Sep 17 00:00:00 2001 From: veetaha Date: Sat, 23 May 2020 16:31:56 +0300 Subject: Fix tests, apply code review proposals --- crates/ra_proc_macro_srv/Cargo.toml | 1 + crates/ra_proc_macro_srv/src/tests/utils.rs | 3 +-- crates/rust-analyzer/src/main_loop/handlers.rs | 17 ++++++++++------- crates/rust-analyzer/tests/heavy_tests/main.rs | 14 +++++++++----- 4 files changed, 21 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml index bb3003278..582102945 100644 --- a/crates/ra_proc_macro_srv/Cargo.toml +++ b/crates/ra_proc_macro_srv/Cargo.toml @@ -22,3 +22,4 @@ cargo_metadata = "0.10.0" difference = "2.0.0" # used as proc macro test target serde_derive = "1.0.106" +ra_toolchain = { path = "../ra_toolchain" } diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs index 84348b5de..8d85f2d8a 100644 --- a/crates/ra_proc_macro_srv/src/tests/utils.rs +++ b/crates/ra_proc_macro_srv/src/tests/utils.rs @@ -2,7 +2,6 @@ use crate::dylib; use crate::ProcMacroSrv; -pub use difference::Changeset as __Changeset; use ra_proc_macro::ListMacrosTask; use std::str::FromStr; use test_utils::assert_eq_text; @@ -13,7 +12,7 @@ mod fixtures { // Use current project metadata to get the proc-macro dylib path pub fn dylib_path(crate_name: &str, version: &str) -> std::path::PathBuf { - let command = Command::new("cargo") + let command = Command::new(ra_toolchain::cargo()) .args(&["check", "--message-format", "json"]) .output() .unwrap() diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 1b5b3325c..d42cfa300 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -427,7 +427,7 @@ pub fn handle_runnables( res.push(lsp_ext::Runnable { range: Default::default(), label: format!("cargo {} -p {}", cmd, spec.package), - bin: "cargo".to_string(), + bin: cargo_path()?, args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], extra_args: Vec::new(), env: FxHashMap::default(), @@ -439,7 +439,7 @@ pub fn handle_runnables( res.push(lsp_ext::Runnable { range: Default::default(), label: "cargo check --workspace".to_string(), - bin: "cargo".to_string(), + bin: cargo_path()?, args: vec!["check".to_string(), "--workspace".to_string()], extra_args: Vec::new(), env: FxHashMap::default(), @@ -450,6 +450,13 @@ pub fn handle_runnables( Ok(res) } +fn cargo_path() -> Result { + Ok(ra_toolchain::cargo() + .to_str() + .context("Path to `cargo` executable contains invalid UTF8 characters")? + .to_owned()) +} + pub fn handle_completion( world: WorldSnapshot, params: lsp_types::CompletionParams, @@ -983,15 +990,11 @@ fn to_lsp_runnable( target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) } }; - let cargo_path = ra_toolchain::cargo() - .to_str() - .context("Path to cargo executable contains invalid UTF8 characters")? - .to_owned(); Ok(lsp_ext::Runnable { range: to_proto::range(&line_index, runnable.range), label, - bin: cargo_path, + bin: cargo_path()?, args, extra_args, env: { diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 405ddb362..a31580c86 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -58,6 +58,10 @@ use std::collections::Spam; eprintln!("completion took {:?}", completion_start.elapsed()); } +fn cargo_path() -> String { + ra_toolchain::cargo().to_str().unwrap().to_owned() +} + #[test] fn test_runnables_no_project() { if skip_slow_tests() { @@ -79,7 +83,7 @@ fn foo() { { "args": [ "test" ], "extraArgs": [ "foo", "--nocapture" ], - "bin": "cargo", + "bin": cargo_path(), "env": { "RUST_BACKTRACE": "short" }, "cwd": null, "label": "test foo", @@ -91,7 +95,7 @@ fn foo() { { "args": ["check", "--workspace"], "extraArgs": [], - "bin": "cargo", + "bin": cargo_path(), "env": {}, "cwd": null, "label": "cargo check --workspace", @@ -141,7 +145,7 @@ fn main() {} { "args": [ "test", "--package", "foo", "--test", "spam" ], "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], - "bin": "cargo", + "bin": cargo_path(), "env": { "RUST_BACKTRACE": "short" }, "label": "test test_eggs", "range": { @@ -153,7 +157,7 @@ fn main() {} { "args": [ "check", "--package", "foo" ], "extraArgs": [], - "bin": "cargo", + "bin": cargo_path(), "env": {}, "label": "cargo check -p foo", "range": { @@ -165,7 +169,7 @@ fn main() {} { "args": [ "test", "--package", "foo" ], "extraArgs": [], - "bin": "cargo", + "bin": cargo_path(), "env": {}, "label": "cargo test -p foo", "range": { -- cgit v1.2.3 From d605ec9c321392d9c7ee4b440c560e1e405d92e6 Mon Sep 17 00:00:00 2001 From: veetaha Date: Sun, 31 May 2020 05:13:08 +0300 Subject: Change Runnable.bin -> Runnable.kind As per matklad, we now pass the responsibility for finding the binary to the frontend. Also, added caching for finding the binary path to reduce the amount of filesystem interactions. --- crates/rust-analyzer/Cargo.toml | 1 - crates/rust-analyzer/src/lsp_ext.rs | 11 ++++++++++- crates/rust-analyzer/src/main_loop/handlers.rs | 14 +++----------- crates/rust-analyzer/tests/heavy_tests/main.rs | 14 +++++--------- 4 files changed, 18 insertions(+), 22 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 2e49448cc..65b487db3 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -48,7 +48,6 @@ hir = { path = "../ra_hir", package = "ra_hir" } hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } ra_proc_macro_srv = { path = "../ra_proc_macro_srv" } -ra_toolchain = { path = "../ra_toolchain" } [target.'cfg(windows)'.dependencies] winapi = "0.3.8" diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index acb1dacb6..173c23b9e 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -121,12 +121,21 @@ pub struct RunnablesParams { pub position: Option, } +// Must strictly correspond to the executable name +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "lowercase")] +pub enum RunnableKind { + Cargo, + Rustc, + Rustup, +} + #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Runnable { pub range: Range, pub label: String, - pub bin: String, + pub kind: RunnableKind, pub args: Vec, pub extra_args: Vec, pub env: FxHashMap, diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index d42cfa300..bc7c7f1ef 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -40,7 +40,6 @@ use crate::{ world::WorldSnapshot, LspError, Result, }; -use anyhow::Context; pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { let _p = profile("handle_analyzer_status"); @@ -427,7 +426,7 @@ pub fn handle_runnables( res.push(lsp_ext::Runnable { range: Default::default(), label: format!("cargo {} -p {}", cmd, spec.package), - bin: cargo_path()?, + kind: lsp_ext::RunnableKind::Cargo, args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], extra_args: Vec::new(), env: FxHashMap::default(), @@ -439,7 +438,7 @@ pub fn handle_runnables( res.push(lsp_ext::Runnable { range: Default::default(), label: "cargo check --workspace".to_string(), - bin: cargo_path()?, + kind: lsp_ext::RunnableKind::Cargo, args: vec!["check".to_string(), "--workspace".to_string()], extra_args: Vec::new(), env: FxHashMap::default(), @@ -450,13 +449,6 @@ pub fn handle_runnables( Ok(res) } -fn cargo_path() -> Result { - Ok(ra_toolchain::cargo() - .to_str() - .context("Path to `cargo` executable contains invalid UTF8 characters")? - .to_owned()) -} - pub fn handle_completion( world: WorldSnapshot, params: lsp_types::CompletionParams, @@ -994,7 +986,7 @@ fn to_lsp_runnable( Ok(lsp_ext::Runnable { range: to_proto::range(&line_index, runnable.range), label, - bin: cargo_path()?, + kind: lsp_ext::RunnableKind::Cargo, args, extra_args, env: { diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index a31580c86..8b473ff74 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -58,10 +58,6 @@ use std::collections::Spam; eprintln!("completion took {:?}", completion_start.elapsed()); } -fn cargo_path() -> String { - ra_toolchain::cargo().to_str().unwrap().to_owned() -} - #[test] fn test_runnables_no_project() { if skip_slow_tests() { @@ -83,7 +79,7 @@ fn foo() { { "args": [ "test" ], "extraArgs": [ "foo", "--nocapture" ], - "bin": cargo_path(), + "kind": "cargo", "env": { "RUST_BACKTRACE": "short" }, "cwd": null, "label": "test foo", @@ -95,7 +91,7 @@ fn foo() { { "args": ["check", "--workspace"], "extraArgs": [], - "bin": cargo_path(), + "kind": "cargo", "env": {}, "cwd": null, "label": "cargo check --workspace", @@ -145,7 +141,7 @@ fn main() {} { "args": [ "test", "--package", "foo", "--test", "spam" ], "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], - "bin": cargo_path(), + "kind": "cargo", "env": { "RUST_BACKTRACE": "short" }, "label": "test test_eggs", "range": { @@ -157,7 +153,7 @@ fn main() {} { "args": [ "check", "--package", "foo" ], "extraArgs": [], - "bin": cargo_path(), + "kind": "cargo", "env": {}, "label": "cargo check -p foo", "range": { @@ -169,7 +165,7 @@ fn main() {} { "args": [ "test", "--package", "foo" ], "extraArgs": [], - "bin": cargo_path(), + "kind": "cargo", "env": {}, "label": "cargo test -p foo", "range": { -- cgit v1.2.3 From 1211a46826ee8a08683e4cfe151649efd6fd90fa Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 31 May 2020 18:58:54 -0400 Subject: Unsquish parameter types in tooltips for macro-generated functions --- crates/ra_ide/src/display/function_signature.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index 9572debd8..b081ecaad 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs @@ -207,7 +207,18 @@ impl From<&'_ ast::FnDef> for FunctionSignature { res.push(raw_param); } - res.extend(param_list.params().map(|param| param.syntax().text().to_string())); + // macro-generated functions are missing whitespace + fn fmt_param(param: ast::Param) -> String { + let text = param.syntax().text().to_string(); + match text.find(':') { + Some(pos) if 1 + pos < text.len() => { + format!("{} {}", &text[0..1 + pos].trim(), &text[1 + pos..].trim()) + } + _ => text, + } + } + + res.extend(param_list.params().map(fmt_param)); res_types.extend(param_list.params().map(|param| { let param_text = param.syntax().text().to_string(); match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { -- cgit v1.2.3 From 8101ea0fdc9d2be2d3926b22af8167f7155ff0c7 Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Sun, 31 May 2020 16:04:52 -0700 Subject: Update a comment for the new source organization --- crates/ra_parser/src/grammar.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index be0cd5661..293baecf6 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs @@ -18,9 +18,10 @@ //! // fn foo() {} //! ``` //! -//! After adding a new inline-test, run `cargo collect-tests` to extract -//! it as a standalone text-fixture into `tests/data/parser/inline`, and -//! run `cargo test` once to create the "gold" value. +//! After adding a new inline-test, run `cargo xtask codegen` to +//! extract it as a standalone text-fixture into +//! `crates/ra_syntax/test_data/parser/`, and run `cargo test` once to +//! create the "gold" value. //! //! Coding convention: rules like `where_clause` always produce either a //! node or an error, rules like `opt_where_clause` may produce nothing. -- cgit v1.2.3 From fb971c3bce710df234feb313528da81ccd5e26f9 Mon Sep 17 00:00:00 2001 From: veetaha Date: Tue, 2 Jun 2020 02:50:05 +0300 Subject: Simplify --- crates/ra_syntax/src/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 1876afe95..eddc807d5 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -75,7 +75,7 @@ impl AstChildren { impl Iterator for AstChildren { type Item = N; fn next(&mut self) -> Option { - self.inner.by_ref().find_map(N::cast) + self.inner.find_map(N::cast) } } -- cgit v1.2.3 From 31f282636bb1b1d701d41f7c7fedb11a5511cabd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Jun 2020 16:30:26 +0200 Subject: Minor --- crates/rust-analyzer/src/cargo_target_spec.rs | 85 ++++++++++++++++-- crates/rust-analyzer/src/main_loop/handlers.rs | 120 +------------------------ crates/rust-analyzer/src/to_proto.rs | 44 ++++++++- 3 files changed, 125 insertions(+), 124 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 441fb61df..008518a08 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -1,10 +1,10 @@ //! See `CargoTargetSpec` +use ra_cfg::CfgExpr; use ra_ide::{FileId, RunnableKind, TestId}; use ra_project_model::{self, ProjectWorkspace, TargetKind}; use crate::{world::WorldSnapshot, Result}; -use ra_syntax::SmolStr; /// Abstract representation of Cargo target. /// @@ -21,7 +21,7 @@ impl CargoTargetSpec { pub(crate) fn runnable_args( spec: Option, kind: &RunnableKind, - features_needed: &Vec, + cfgs: &[CfgExpr], ) -> Result<(Vec, Vec)> { let mut args = Vec::new(); let mut extra_args = Vec::new(); @@ -76,10 +76,14 @@ impl CargoTargetSpec { } } - features_needed.iter().for_each(|feature| { + let mut features = Vec::new(); + for cfg in cfgs { + required_features(cfg, &mut features); + } + for feature in features { args.push("--features".to_string()); - args.push(feature.to_string()); - }); + args.push(feature); + } Ok((args, extra_args)) } @@ -140,3 +144,74 @@ impl CargoTargetSpec { } } } + +/// Fill minimal features needed +fn required_features(cfg_expr: &CfgExpr, features: &mut Vec) { + match cfg_expr { + CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.to_string()), + CfgExpr::All(preds) => { + preds.iter().for_each(|cfg| required_features(cfg, features)); + } + CfgExpr::Any(preds) => { + for cfg in preds { + let len_features = features.len(); + required_features(cfg, features); + if len_features != features.len() { + break; + } + } + } + _ => {} + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use mbe::{ast_to_token_tree, TokenMap}; + use ra_cfg::parse_cfg; + use ra_syntax::{ + ast::{self, AstNode}, + SmolStr, + }; + + fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + ast_to_token_tree(&tt).unwrap() + } + + #[test] + fn test_cfg_expr_minimal_features_needed() { + let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); + let cfg_expr = parse_cfg(&subtree); + let mut min_features = vec![]; + required_features(&cfg_expr, &mut min_features); + + assert_eq!(min_features, vec![SmolStr::new("baz")]); + + let (subtree, _) = + get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); + let cfg_expr = parse_cfg(&subtree); + + let mut min_features = vec![]; + required_features(&cfg_expr, &mut min_features); + assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); + + let (subtree, _) = + get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); + let cfg_expr = parse_cfg(&subtree); + + let mut min_features = vec![]; + required_features(&cfg_expr, &mut min_features); + assert_eq!(min_features, vec![SmolStr::new("baz")]); + + let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); + let cfg_expr = parse_cfg(&subtree); + + let mut min_features = vec![]; + required_features(&cfg_expr, &mut min_features); + assert!(min_features.is_empty()); + } +} diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index bc7c7f1ef..410c654ab 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -17,14 +17,12 @@ use lsp_types::{ SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, }; -use ra_cfg::CfgExpr; use ra_ide::{ - FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, - TextEdit, + FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit, }; use ra_prof::profile; use ra_project_model::TargetKind; -use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize}; +use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use serde_json::to_value; @@ -416,7 +414,7 @@ pub fn handle_runnables( } } } - res.push(to_lsp_runnable(&world, file_id, runnable)?); + res.push(to_proto::runnable(&world, file_id, runnable)?); } // Add `cargo check` and `cargo test` for the whole package @@ -784,7 +782,7 @@ pub fn handle_code_lens( } }; - let mut r = to_lsp_runnable(&world, file_id, runnable)?; + let mut r = to_proto::runnable(&world, file_id, runnable)?; if world.config.lens.run { let lens = CodeLens { range: r.range, @@ -959,65 +957,6 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result Result { - let spec = CargoTargetSpec::for_file(world, file_id)?; - let target = spec.as_ref().map(|s| s.target.clone()); - let mut features_needed = vec![]; - for cfg_expr in &runnable.cfg_exprs { - collect_minimal_features_needed(cfg_expr, &mut features_needed); - } - let (args, extra_args) = - CargoTargetSpec::runnable_args(spec, &runnable.kind, &features_needed)?; - let line_index = world.analysis().file_line_index(file_id)?; - let label = match &runnable.kind { - RunnableKind::Test { test_id, .. } => format!("test {}", test_id), - RunnableKind::TestMod { path } => format!("test-mod {}", path), - RunnableKind::Bench { test_id } => format!("bench {}", test_id), - RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), - RunnableKind::Bin => { - target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) - } - }; - - Ok(lsp_ext::Runnable { - range: to_proto::range(&line_index, runnable.range), - label, - kind: lsp_ext::RunnableKind::Cargo, - args, - extra_args, - env: { - let mut m = FxHashMap::default(); - m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); - m - }, - cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), - }) -} - -/// Fill minimal features needed -fn collect_minimal_features_needed(cfg_expr: &CfgExpr, features: &mut Vec) { - match cfg_expr { - CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()), - CfgExpr::All(preds) => { - preds.iter().for_each(|cfg| collect_minimal_features_needed(cfg, features)); - } - CfgExpr::Any(preds) => { - for cfg in preds { - let len_features = features.len(); - collect_minimal_features_needed(cfg, features); - if len_features != features.len() { - break; - } - } - } - _ => {} - } -} - pub fn handle_inlay_hints( world: WorldSnapshot, params: InlayHintsParams, @@ -1154,54 +1093,3 @@ pub fn handle_semantic_tokens_range( let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); Ok(Some(semantic_tokens.into())) } - -#[cfg(test)] -mod tests { - use super::*; - - use mbe::{ast_to_token_tree, TokenMap}; - use ra_cfg::parse_cfg; - use ra_syntax::{ - ast::{self, AstNode}, - SmolStr, - }; - - fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { - let source_file = ast::SourceFile::parse(input).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - ast_to_token_tree(&tt).unwrap() - } - - #[test] - fn test_cfg_expr_minimal_features_needed() { - let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); - let cfg_expr = parse_cfg(&subtree); - let mut min_features = vec![]; - collect_minimal_features_needed(&cfg_expr, &mut min_features); - - assert_eq!(min_features, vec![SmolStr::new("baz")]); - - let (subtree, _) = - get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); - let cfg_expr = parse_cfg(&subtree); - - let mut min_features = vec![]; - collect_minimal_features_needed(&cfg_expr, &mut min_features); - assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); - - let (subtree, _) = - get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); - let cfg_expr = parse_cfg(&subtree); - - let mut min_features = vec![]; - collect_minimal_features_needed(&cfg_expr, &mut min_features); - assert_eq!(min_features, vec![SmolStr::new("baz")]); - - let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); - let cfg_expr = parse_cfg(&subtree); - - let mut min_features = vec![]; - collect_minimal_features_needed(&cfg_expr, &mut min_features); - assert!(min_features.is_empty()); - } -} diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 2fbbb4e63..66144fe24 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -3,13 +3,16 @@ use ra_db::{FileId, FileRange}; use ra_ide::{ Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, - InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, - SourceChange, SourceFileEdit, TextEdit, + InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Runnable, + RunnableKind, Severity, SourceChange, SourceFileEdit, TextEdit, }; use ra_syntax::{SyntaxKind, TextRange, TextSize}; use ra_vfs::LineEndings; +use rustc_hash::FxHashMap; -use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; +use crate::{ + cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, +}; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { let line_col = line_index.line_col(offset); @@ -627,3 +630,38 @@ pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result Result { + let spec = CargoTargetSpec::for_file(world, file_id)?; + let target = spec.as_ref().map(|s| s.target.clone()); + let (args, extra_args) = + CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; + let line_index = world.analysis().file_line_index(file_id)?; + let label = match &runnable.kind { + RunnableKind::Test { test_id, .. } => format!("test {}", test_id), + RunnableKind::TestMod { path } => format!("test-mod {}", path), + RunnableKind::Bench { test_id } => format!("bench {}", test_id), + RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), + RunnableKind::Bin => { + target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) + } + }; + + Ok(lsp_ext::Runnable { + range: range(&line_index, runnable.range), + label, + kind: lsp_ext::RunnableKind::Cargo, + args, + extra_args, + env: { + let mut m = FxHashMap::default(); + m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); + m + }, + cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), + }) +} -- cgit v1.2.3 From 03039821195c9d9c4bbc1e4cbddb6378c43a6c52 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Jun 2020 17:22:23 +0200 Subject: New runnables API --- crates/ra_ide/src/display/navigation_target.rs | 66 +++++++++----------------- crates/ra_ide/src/runnables.rs | 25 +++++----- crates/rust-analyzer/src/lsp_ext.rs | 28 ++++++----- crates/rust-analyzer/src/main_loop/handlers.rs | 41 ++++++++-------- crates/rust-analyzer/src/to_proto.rs | 18 +++---- 5 files changed, 80 insertions(+), 98 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 5da28edd2..c7bb1e69f 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs @@ -92,15 +92,16 @@ impl NavigationTarget { let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); if let Some(src) = module.declaration_source(db) { let frange = original_range(db, src.as_ref().map(|it| it.syntax())); - return NavigationTarget::from_syntax( + let mut res = NavigationTarget::from_syntax( frange.file_id, name, None, frange.range, src.value.syntax().kind(), - src.value.doc_comment_text(), - src.value.short_label(), ); + res.docs = src.value.doc_comment_text(); + res.description = src.value.short_label(); + return res; } module.to_nav(db) } @@ -130,11 +131,9 @@ impl NavigationTarget { } /// Allows `NavigationTarget` to be created from a `NameOwner` - fn from_named( + pub(crate) fn from_named( db: &RootDatabase, node: InFile<&dyn ast::NameOwner>, - docs: Option, - description: Option, ) -> NavigationTarget { //FIXME: use `_` instead of empty string let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); @@ -148,8 +147,6 @@ impl NavigationTarget { focus_range, frange.range, node.value.syntax().kind(), - docs, - description, ) } @@ -159,8 +156,6 @@ impl NavigationTarget { focus_range: Option, full_range: TextRange, kind: SyntaxKind, - docs: Option, - description: Option, ) -> NavigationTarget { NavigationTarget { file_id, @@ -169,8 +164,8 @@ impl NavigationTarget { full_range, focus_range, container_name: None, - description, - docs, + description: None, + docs: None, } } } @@ -238,12 +233,11 @@ where { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { let src = self.source(db); - NavigationTarget::from_named( - db, - src.as_ref().map(|it| it as &dyn ast::NameOwner), - src.value.doc_comment_text(), - src.value.short_label(), - ) + let mut res = + NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); + res.docs = src.value.doc_comment_text(); + res.description = src.value.short_label(); + res } } @@ -258,15 +252,7 @@ impl ToNav for hir::Module { } }; let frange = original_range(db, src.with_value(syntax)); - NavigationTarget::from_syntax( - frange.file_id, - name, - focus, - frange.range, - syntax.kind(), - None, - None, - ) + NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind()) } } @@ -285,8 +271,6 @@ impl ToNav for hir::ImplDef { None, frange.range, src.value.syntax().kind(), - None, - None, ) } } @@ -296,12 +280,12 @@ impl ToNav for hir::Field { let src = self.source(db); match &src.value { - FieldSource::Named(it) => NavigationTarget::from_named( - db, - src.with_value(it), - it.doc_comment_text(), - it.short_label(), - ), + FieldSource::Named(it) => { + let mut res = NavigationTarget::from_named(db, src.with_value(it)); + res.docs = it.doc_comment_text(); + res.description = it.short_label(); + res + } FieldSource::Pos(it) => { let frange = original_range(db, src.with_value(it.syntax())); NavigationTarget::from_syntax( @@ -310,8 +294,6 @@ impl ToNav for hir::Field { None, frange.range, it.syntax().kind(), - None, - None, ) } } @@ -322,12 +304,10 @@ impl ToNav for hir::MacroDef { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { let src = self.source(db); log::debug!("nav target {:#?}", src.value.syntax()); - NavigationTarget::from_named( - db, - src.as_ref().map(|it| it as &dyn ast::NameOwner), - src.value.doc_comment_text(), - None, - ) + let mut res = + NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); + res.docs = src.value.doc_comment_text(); + res } } diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 286d45eee..9239ca61b 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs @@ -1,19 +1,19 @@ +use std::fmt; + use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; use itertools::Itertools; +use ra_cfg::CfgExpr; use ra_ide_db::RootDatabase; use ra_syntax::{ - ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, - match_ast, SyntaxNode, TextRange, + ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, + match_ast, SyntaxNode, }; -use crate::FileId; -use ast::DocCommentsOwner; -use ra_cfg::CfgExpr; -use std::fmt::Display; +use crate::{display::ToNav, FileId, NavigationTarget}; #[derive(Debug)] pub struct Runnable { - pub range: TextRange, + pub nav: NavigationTarget, pub kind: RunnableKind, pub cfg_exprs: Vec, } @@ -24,8 +24,8 @@ pub enum TestId { Path(String), } -impl Display for TestId { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Display for TestId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { TestId::Name(name) => write!(f, "{}", name), TestId::Path(path) => write!(f, "{}", path), @@ -131,7 +131,8 @@ fn runnable_fn( let cfg_exprs = attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); - Some(Runnable { range: fn_def.syntax().text_range(), kind, cfg_exprs }) + let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); + Some(Runnable { nav, kind, cfg_exprs }) } #[derive(Debug)] @@ -183,7 +184,6 @@ fn runnable_mod( if !has_test_function { return None; } - let range = module.syntax().text_range(); let module_def = sema.to_def(&module)?; let path = module_def @@ -197,7 +197,8 @@ fn runnable_mod( let cfg_exprs = attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); - Some(Runnable { range, kind: RunnableKind::TestMod { path }, cfg_exprs }) + let nav = module_def.to_nav(sema.db); + Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) } #[cfg(test)] diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 173c23b9e..9381f75d3 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -4,7 +4,6 @@ use std::{collections::HashMap, path::PathBuf}; use lsp_types::request::Request; use lsp_types::{Position, Range, TextDocumentIdentifier}; -use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; pub enum AnalyzerStatus {} @@ -121,25 +120,30 @@ pub struct RunnablesParams { pub position: Option, } -// Must strictly correspond to the executable name +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Runnable { + pub label: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub location: Option, + pub kind: RunnableKind, + pub args: CargoRunnable, +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "lowercase")] pub enum RunnableKind { Cargo, - Rustc, - Rustup, } #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct Runnable { - pub range: Range, - pub label: String, - pub kind: RunnableKind, - pub args: Vec, - pub extra_args: Vec, - pub env: FxHashMap, - pub cwd: Option, +pub struct CargoRunnable { + pub workspace_root: Option, + // command, --package and --lib stuff + pub cargo_args: Vec, + // stuff after -- + pub executable_args: Vec, } pub enum InlayHints {} diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 410c654ab..7fd691764 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -23,7 +23,6 @@ use ra_ide::{ use ra_prof::profile; use ra_project_model::TargetKind; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; -use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use serde_json::to_value; use stdx::format_to; @@ -401,7 +400,7 @@ pub fn handle_runnables( let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; for runnable in world.analysis().runnables(file_id)? { if let Some(offset) = offset { - if !runnable.range.contains_inclusive(offset) { + if !runnable.nav.full_range().contains_inclusive(offset) { continue; } } @@ -422,25 +421,31 @@ pub fn handle_runnables( Some(spec) => { for &cmd in ["check", "test"].iter() { res.push(lsp_ext::Runnable { - range: Default::default(), label: format!("cargo {} -p {}", cmd, spec.package), + location: None, kind: lsp_ext::RunnableKind::Cargo, - args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], - extra_args: Vec::new(), - env: FxHashMap::default(), - cwd: workspace_root.map(|root| root.to_owned()), + args: lsp_ext::CargoRunnable { + workspace_root: workspace_root.map(|root| root.to_owned()), + cargo_args: vec![ + cmd.to_string(), + "--package".to_string(), + spec.package.clone(), + ], + executable_args: Vec::new(), + }, }) } } None => { res.push(lsp_ext::Runnable { - range: Default::default(), label: "cargo check --workspace".to_string(), + location: None, kind: lsp_ext::RunnableKind::Cargo, - args: vec!["check".to_string(), "--workspace".to_string()], - extra_args: Vec::new(), - env: FxHashMap::default(), - cwd: workspace_root.map(|root| root.to_owned()), + args: lsp_ext::CargoRunnable { + workspace_root: workspace_root.map(|root| root.to_owned()), + cargo_args: vec!["check".to_string(), "--workspace".to_string()], + executable_args: Vec::new(), + }, }); } } @@ -782,10 +787,11 @@ pub fn handle_code_lens( } }; - let mut r = to_proto::runnable(&world, file_id, runnable)?; + let range = to_proto::range(&line_index, runnable.nav.range()); + let r = to_proto::runnable(&world, file_id, runnable)?; if world.config.lens.run { let lens = CodeLens { - range: r.range, + range, command: Some(Command { title: run_title.to_string(), command: "rust-analyzer.runSingle".into(), @@ -797,13 +803,8 @@ pub fn handle_code_lens( } if debugee && world.config.lens.debug { - if r.args[0] == "run" { - r.args[0] = "build".into(); - } else { - r.args.push("--no-run".into()); - } let debug_lens = CodeLens { - range: r.range, + range, command: Some(Command { title: "Debug".into(), command: "rust-analyzer.debugSingle".into(), diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 66144fe24..85304aa87 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -8,7 +8,6 @@ use ra_ide::{ }; use ra_syntax::{SyntaxKind, TextRange, TextSize}; use ra_vfs::LineEndings; -use rustc_hash::FxHashMap; use crate::{ cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, @@ -638,9 +637,8 @@ pub(crate) fn runnable( ) -> Result { let spec = CargoTargetSpec::for_file(world, file_id)?; let target = spec.as_ref().map(|s| s.target.clone()); - let (args, extra_args) = + let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; - let line_index = world.analysis().file_line_index(file_id)?; let label = match &runnable.kind { RunnableKind::Test { test_id, .. } => format!("test {}", test_id), RunnableKind::TestMod { path } => format!("test-mod {}", path), @@ -650,18 +648,16 @@ pub(crate) fn runnable( target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) } }; + let location = location_link(world, None, runnable.nav)?; Ok(lsp_ext::Runnable { - range: range(&line_index, runnable.range), label, + location: Some(location), kind: lsp_ext::RunnableKind::Cargo, - args, - extra_args, - env: { - let mut m = FxHashMap::default(); - m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); - m + args: lsp_ext::CargoRunnable { + workspace_root: world.workspace_root_for(file_id).map(|root| root.to_owned()), + cargo_args, + executable_args, }, - cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), }) } -- cgit v1.2.3 From a83ab820a4633bac718ee0fd11f06d1b3142be6b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Jun 2020 17:34:18 +0200 Subject: Spec better runnables --- crates/rust-analyzer/src/caps.rs | 3 +++ crates/rust-analyzer/src/lsp_ext.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 345693524..673795e78 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs @@ -87,6 +87,9 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti "ssr": true, "onEnter": true, "parentModule": true, + "runnables": { + "kinds": [ "cargo" ], + }, })), } } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 9381f75d3..5fa1eba1c 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -110,7 +110,7 @@ pub enum Runnables {} impl Request for Runnables { type Params = RunnablesParams; type Result = Vec; - const METHOD: &'static str = "rust-analyzer/runnables"; + const METHOD: &'static str = "experimental/runnables"; } #[derive(Serialize, Deserialize, Debug)] -- cgit v1.2.3 From bc3db7c1ded0db2d3804b5ac3e5c35dd53350228 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Jun 2020 18:02:58 +0200 Subject: Fix tests --- crates/ra_ide/src/runnables.rs | 225 +++++++++++++++++++++++-- crates/rust-analyzer/src/lsp_ext.rs | 1 + crates/rust-analyzer/tests/heavy_tests/main.rs | 113 +++++++------ 3 files changed, 270 insertions(+), 69 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 9239ca61b..f32ce0d22 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs @@ -228,12 +228,38 @@ mod tests { @r###" [ Runnable { - range: 1..21, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 1..21, + name: "main", + kind: FN_DEF, + focus_range: Some( + 12..16, + ), + container_name: None, + description: None, + docs: None, + }, kind: Bin, cfg_exprs: [], }, Runnable { - range: 22..46, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 22..46, + name: "test_foo", + kind: FN_DEF, + focus_range: Some( + 33..41, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "test_foo", @@ -245,7 +271,20 @@ mod tests { cfg_exprs: [], }, Runnable { - range: 47..81, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 47..81, + name: "test_foo", + kind: FN_DEF, + focus_range: Some( + 68..76, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "test_foo", @@ -280,12 +319,38 @@ mod tests { @r###" [ Runnable { - range: 1..21, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 1..21, + name: "main", + kind: FN_DEF, + focus_range: Some( + 12..16, + ), + container_name: None, + description: None, + docs: None, + }, kind: Bin, cfg_exprs: [], }, Runnable { - range: 22..64, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 22..64, + name: "foo", + kind: FN_DEF, + focus_range: Some( + 56..59, + ), + container_name: None, + description: None, + docs: None, + }, kind: DocTest { test_id: Path( "foo", @@ -320,12 +385,38 @@ mod tests { @r###" [ Runnable { - range: 1..21, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 1..21, + name: "main", + kind: FN_DEF, + focus_range: Some( + 12..16, + ), + container_name: None, + description: None, + docs: None, + }, kind: Bin, cfg_exprs: [], }, Runnable { - range: 51..105, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 51..105, + name: "foo", + kind: FN_DEF, + focus_range: Some( + 97..100, + ), + container_name: None, + description: None, + docs: None, + }, kind: DocTest { test_id: Path( "Data::foo", @@ -355,14 +446,40 @@ mod tests { @r###" [ Runnable { - range: 1..59, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 1..59, + name: "test_mod", + kind: MODULE, + focus_range: Some( + 13..21, + ), + container_name: None, + description: None, + docs: None, + }, kind: TestMod { path: "test_mod", }, cfg_exprs: [], }, Runnable { - range: 28..57, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 28..57, + name: "test_foo1", + kind: FN_DEF, + focus_range: Some( + 43..52, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "test_mod::test_foo1", @@ -397,14 +514,40 @@ mod tests { @r###" [ Runnable { - range: 23..85, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 23..85, + name: "test_mod", + kind: MODULE, + focus_range: Some( + 27..35, + ), + container_name: None, + description: None, + docs: None, + }, kind: TestMod { path: "foo::test_mod", }, cfg_exprs: [], }, Runnable { - range: 46..79, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 46..79, + name: "test_foo1", + kind: FN_DEF, + focus_range: Some( + 65..74, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "foo::test_mod::test_foo1", @@ -441,14 +584,40 @@ mod tests { @r###" [ Runnable { - range: 41..115, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 41..115, + name: "test_mod", + kind: MODULE, + focus_range: Some( + 45..53, + ), + container_name: None, + description: None, + docs: None, + }, kind: TestMod { path: "foo::bar::test_mod", }, cfg_exprs: [], }, Runnable { - range: 68..105, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 68..105, + name: "test_foo1", + kind: FN_DEF, + focus_range: Some( + 91..100, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "foo::bar::test_mod::test_foo1", @@ -480,7 +649,20 @@ mod tests { @r###" [ Runnable { - range: 1..58, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 1..58, + name: "test_foo1", + kind: FN_DEF, + focus_range: Some( + 44..53, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "test_foo1", @@ -517,7 +699,20 @@ mod tests { @r###" [ Runnable { - range: 1..80, + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 1..80, + name: "test_foo1", + kind: FN_DEF, + focus_range: Some( + 66..75, + ), + container_name: None, + description: None, + docs: None, + }, kind: Test { test_id: Path( "test_foo1", diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 5fa1eba1c..ec24ce5e0 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -139,6 +139,7 @@ pub enum RunnableKind { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct CargoRunnable { + #[serde(skip_serializing_if = "Option::is_none")] pub workspace_root: Option, // command, --package and --lib stuff pub cargo_args: Vec, diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 8b473ff74..e18f973b8 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -76,30 +76,33 @@ fn foo() { server.request::( RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, json!([ - { - "args": [ "test" ], - "extraArgs": [ "foo", "--nocapture" ], - "kind": "cargo", - "env": { "RUST_BACKTRACE": "short" }, - "cwd": null, - "label": "test foo", - "range": { - "end": { "character": 1, "line": 2 }, - "start": { "character": 0, "line": 0 } - } - }, - { - "args": ["check", "--workspace"], - "extraArgs": [], - "kind": "cargo", - "env": {}, - "cwd": null, - "label": "cargo check --workspace", - "range": { - "end": { "character": 0, "line": 0 }, - "start": { "character": 0, "line": 0 } + { + "args": { + "cargoArgs": ["test"], + "executableArgs": ["foo", "--nocapture"], + }, + "kind": "cargo", + "label": "test foo", + "location": { + "targetRange": { + "end": { "character": 1, "line": 2 }, + "start": { "character": 0, "line": 0 } + }, + "targetSelectionRange": { + "end": { "character": 6, "line": 1 }, + "start": { "character": 3, "line": 1 } + }, + "targetUri": "file:///[..]/lib.rs" + } + }, + { + "args": { + "cargoArgs": ["check", "--workspace"], + "executableArgs": [], + }, + "kind": "cargo", + "label": "cargo check --workspace" } - } ]), ); } @@ -138,42 +141,44 @@ fn main() {} server.request::( RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, json!([ - { - "args": [ "test", "--package", "foo", "--test", "spam" ], - "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], - "kind": "cargo", - "env": { "RUST_BACKTRACE": "short" }, - "label": "test test_eggs", - "range": { - "end": { "character": 17, "line": 1 }, - "start": { "character": 0, "line": 0 } - }, - "cwd": server.path().join("foo") + { + "args": { + "cargoArgs": ["test", "--package", "foo", "--test", "spam"], + "executableArgs": ["test_eggs", "--exact", "--nocapture"], + "workspaceRoot": server.path().join("foo") }, - { - "args": [ "check", "--package", "foo" ], - "extraArgs": [], - "kind": "cargo", - "env": {}, - "label": "cargo check -p foo", - "range": { - "end": { "character": 0, "line": 0 }, + "kind": "cargo", + "label": "test test_eggs", + "location": { + "targetRange": { + "end": { "character": 17, "line": 1 }, "start": { "character": 0, "line": 0 } }, - "cwd": server.path().join("foo") - }, - { - "args": [ "test", "--package", "foo" ], - "extraArgs": [], - "kind": "cargo", - "env": {}, - "label": "cargo test -p foo", - "range": { - "end": { "character": 0, "line": 0 }, - "start": { "character": 0, "line": 0 } + "targetSelectionRange": { + "end": { "character": 12, "line": 1 }, + "start": { "character": 3, "line": 1 } }, - "cwd": server.path().join("foo") + "targetUri": "file:///[..]/tests/spam.rs" } + }, + { + "args": { + "cargoArgs": ["check", "--package", "foo"], + "executableArgs": [], + "workspaceRoot": server.path().join("foo") + }, + "kind": "cargo", + "label": "cargo check -p foo" + }, + { + "args": { + "cargoArgs": ["test", "--package", "foo"], + "executableArgs": [], + "workspaceRoot": server.path().join("foo") + }, + "kind": "cargo", + "label": "cargo test -p foo" + } ]), ); } -- cgit v1.2.3 From 7a66d9989713475a10eb20b8c772287b435fecd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 2 Jun 2020 12:24:33 +0300 Subject: Disable rust-analyzer.{cargo,checkOnSave}.allFeatures by default --- crates/ra_project_model/src/cargo_workspace.rs | 2 +- crates/rust-analyzer/src/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index a306ce95f..4b7444039 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -64,7 +64,7 @@ impl Default for CargoConfig { fn default() -> Self { CargoConfig { no_default_features: false, - all_features: true, + all_features: false, features: Vec::new(), load_out_dirs_from_check: false, target: None, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c0f7c2c0c..9c6e369d2 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -122,7 +122,7 @@ impl Default for Config { check: Some(FlycheckConfig::CargoCommand { command: "check".to_string(), all_targets: true, - all_features: true, + all_features: false, extra_args: Vec::new(), }), -- cgit v1.2.3 From 57cd936c5262c3b43626618be42d7a72f71c3539 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Tue, 2 Jun 2020 22:21:48 +0200 Subject: Preliminary implementation of lazy CodeAssits --- crates/ra_ide/src/lib.rs | 39 +++++----- crates/rust-analyzer/src/config.rs | 7 +- ...tics__to_proto__tests__snap_multi_line_fix.snap | 1 + ...o_proto__tests__snap_rustc_unused_variable.snap | 1 + crates/rust-analyzer/src/diagnostics/to_proto.rs | 1 + crates/rust-analyzer/src/lsp_ext.rs | 19 +++++ crates/rust-analyzer/src/main_loop.rs | 1 + crates/rust-analyzer/src/main_loop/handlers.rs | 89 +++++++++++++++++----- crates/rust-analyzer/src/to_proto.rs | 39 +++++++++- 9 files changed, 150 insertions(+), 47 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 12d5716e8..34c2d75fe 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -77,7 +77,7 @@ pub use crate::{ }; pub use hir::Documentation; -pub use ra_assists::{AssistConfig, AssistId}; +pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist}; pub use ra_db::{ Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, }; @@ -142,14 +142,6 @@ pub struct AnalysisHost { db: RootDatabase, } -#[derive(Debug)] -pub struct Assist { - pub id: AssistId, - pub label: String, - pub group_label: Option, - pub source_change: SourceChange, -} - impl AnalysisHost { pub fn new(lru_capacity: Option) -> AnalysisHost { AnalysisHost { db: RootDatabase::new(lru_capacity) } @@ -470,20 +462,23 @@ impl Analysis { self.with_db(|db| completion::completions(db, config, position).map(Into::into)) } - /// Computes assists (aka code actions aka intentions) for the given + /// Computes resolved assists with source changes for the given position. + pub fn resolved_assists( + &self, + config: &AssistConfig, + frange: FileRange, + ) -> Cancelable> { + self.with_db(|db| ra_assists::Assist::resolved(db, config, frange)) + } + + /// Computes unresolved assists (aka code actions aka intentions) for the given /// position. - pub fn assists(&self, config: &AssistConfig, frange: FileRange) -> Cancelable> { - self.with_db(|db| { - ra_assists::Assist::resolved(db, config, frange) - .into_iter() - .map(|assist| Assist { - id: assist.assist.id, - label: assist.assist.label, - group_label: assist.assist.group.map(|it| it.0), - source_change: assist.source_change, - }) - .collect() - }) + pub fn unresolved_assists( + &self, + config: &AssistConfig, + frange: FileRange, + ) -> Cancelable> { + self.with_db(|db| Assist::unresolved(db, config, frange)) } /// Computes the set of diagnostics for the given file. diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c0f7c2c0c..9e8e7ab82 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -103,6 +103,7 @@ pub struct ClientCapsConfig { pub code_action_literals: bool, pub work_done_progress: bool, pub code_action_group: bool, + pub resolve_code_action: bool, } impl Default for Config { @@ -299,7 +300,11 @@ impl Config { let code_action_group = experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true); - self.client_caps.code_action_group = code_action_group + self.client_caps.code_action_group = code_action_group; + + let resolve_code_action = + experimental.get("resolveCodeAction").and_then(|it| it.as_bool()) == Some(true); + self.client_caps.resolve_code_action = resolve_code_action; } } } diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap index c40cfdcdc..272057b47 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap @@ -65,6 +65,7 @@ expression: diag fixes: [ CodeAction { title: "return the expression directly", + id: None, group: None, kind: Some( "quickfix", diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap index 6dd3fcb2e..9a7972ff5 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap @@ -50,6 +50,7 @@ expression: diag fixes: [ CodeAction { title: "consider prefixing with an underscore", + id: None, group: None, kind: Some( "quickfix", diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index a500d670a..257910e09 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -145,6 +145,7 @@ fn map_rust_child_diagnostic( } else { MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { title: rd.message.clone(), + id: None, group: None, kind: Some("quickfix".to_string()), edit: Some(lsp_ext::SnippetWorkspaceEdit { diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 173c23b9e..05b76e7c8 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -98,6 +98,23 @@ pub struct JoinLinesParams { pub ranges: Vec, } +pub enum ResolveCodeActionRequest {} + +impl Request for ResolveCodeActionRequest { + type Params = ResolveCodeActionParams; + type Result = Option; + const METHOD: &'static str = "experimental/resolveCodeAction"; +} + +/// Params for the ResolveCodeActionRequest +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ResolveCodeActionParams { + pub code_action_params: lsp_types::CodeActionParams, + pub id: String, + pub label: String, +} + pub enum OnEnter {} impl Request for OnEnter { @@ -197,6 +214,8 @@ impl Request for CodeActionRequest { pub struct CodeAction { pub title: String, #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub group: Option, #[serde(skip_serializing_if = "Option::is_none")] pub kind: Option, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f1287d52c..ad9dd4c59 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -517,6 +517,7 @@ fn on_request( .on::(handlers::handle_runnables)? .on::(handlers::handle_inlay_hints)? .on::(handlers::handle_code_action)? + .on::(handlers::handle_resolve_code_action)? .on::(handlers::handle_on_type_formatting)? .on::(handlers::handle_document_symbol)? .on::(handlers::handle_workspace_symbol)? diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index bc7c7f1ef..b342f4bb7 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -693,40 +693,35 @@ pub fn handle_formatting( }])) } -pub fn handle_code_action( - world: WorldSnapshot, - params: lsp_types::CodeActionParams, -) -> Result>> { - let _p = profile("handle_code_action"); - // We intentionally don't support command-based actions, as those either - // requires custom client-code anyway, or requires server-initiated edits. - // Server initiated edits break causality, so we avoid those as well. - if !world.config.client_caps.code_action_literals { - return Ok(None); - } - +fn handle_fixes( + world: &WorldSnapshot, + params: &lsp_types::CodeActionParams, + res: &mut Vec, +) -> Result<()> { let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; let line_index = world.analysis().file_line_index(file_id)?; let range = from_proto::text_range(&line_index, params.range); - let frange = FileRange { file_id, range }; let diagnostics = world.analysis().diagnostics(file_id)?; - let mut res: Vec = Vec::new(); let fixes_from_diagnostics = diagnostics .into_iter() .filter_map(|d| Some((d.range, d.fix?))) .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) .map(|(_range, fix)| fix); - for fix in fixes_from_diagnostics { let title = fix.label; let edit = to_proto::snippet_workspace_edit(&world, fix.source_change)?; - let action = - lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; + let action = lsp_ext::CodeAction { + title, + id: None, + group: None, + kind: None, + edit: Some(edit), + command: None, + }; res.push(action); } - for fix in world.check_fixes.get(&file_id).into_iter().flatten() { let fix_range = from_proto::text_range(&line_index, fix.range); if fix_range.intersect(range).is_none() { @@ -734,13 +729,67 @@ pub fn handle_code_action( } res.push(fix.action.clone()); } + Ok(()) +} + +pub fn handle_code_action( + world: WorldSnapshot, + params: lsp_types::CodeActionParams, +) -> Result>> { + let _p = profile("handle_code_action"); + // We intentionally don't support command-based actions, as those either + // requires custom client-code anyway, or requires server-initiated edits. + // Server initiated edits break causality, so we avoid those as well. + if !world.config.client_caps.code_action_literals { + return Ok(None); + } + + let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; + let line_index = world.analysis().file_line_index(file_id)?; + let range = from_proto::text_range(&line_index, params.range); + let frange = FileRange { file_id, range }; + let mut res: Vec = Vec::new(); + + handle_fixes(&world, ¶ms, &mut res)?; - for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() { - res.push(to_proto::code_action(&world, assist)?.into()); + if world.config.client_caps.resolve_code_action { + for assist in world.analysis().unresolved_assists(&world.config.assist, frange)?.into_iter() + { + res.push(to_proto::unresolved_code_action(&world, assist)?.into()); + } + } else { + for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { + res.push(to_proto::resolved_code_action(&world, assist)?.into()); + } } + Ok(Some(res)) } +pub fn handle_resolve_code_action( + world: WorldSnapshot, + params: lsp_ext::ResolveCodeActionParams, +) -> Result> { + if !world.config.client_caps.resolve_code_action { + return Ok(None); + } + + let _p = profile("handle_resolve_code_action"); + let file_id = from_proto::file_id(&world, ¶ms.code_action_params.text_document.uri)?; + let line_index = world.analysis().file_line_index(file_id)?; + let range = from_proto::text_range(&line_index, params.code_action_params.range); + let frange = FileRange { file_id, range }; + let mut res: Vec = Vec::new(); + + for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { + res.push(to_proto::resolved_code_action(&world, assist)?.into()); + } + Ok(res + .into_iter() + .find(|action| action.id.clone().unwrap() == params.id && action.title == params.label) + .and_then(|action| action.edit)) +} + pub fn handle_code_lens( world: WorldSnapshot, params: lsp_types::CodeLensParams, diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 2fbbb4e63..db78c4b5c 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -3,8 +3,8 @@ use ra_db::{FileId, FileRange}; use ra_ide::{ Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, - InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, - SourceChange, SourceFileEdit, TextEdit, + InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, + ResolvedAssist, Severity, SourceChange, SourceFileEdit, TextEdit, }; use ra_syntax::{SyntaxKind, TextRange, TextSize}; use ra_vfs::LineEndings; @@ -617,10 +617,41 @@ fn main() { } } -pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result { +pub(crate) fn unresolved_code_action( + world: &WorldSnapshot, + assist: Assist, +) -> Result { let res = lsp_ext::CodeAction { title: assist.label, - group: if world.config.client_caps.code_action_group { assist.group_label } else { None }, + id: Some(assist.id.0.to_owned()), + group: assist.group.and_then(|it| { + if world.config.client_caps.code_action_group { + None + } else { + Some(it.0) + } + }), + kind: Some(String::new()), + edit: None, + command: None, + }; + Ok(res) +} + +pub(crate) fn resolved_code_action( + world: &WorldSnapshot, + assist: ResolvedAssist, +) -> Result { + let res = lsp_ext::CodeAction { + title: assist.assist.label, + id: Some(assist.assist.id.0.to_owned()), + group: assist.assist.group.and_then(|it| { + if world.config.client_caps.code_action_group { + None + } else { + Some(it.0) + } + }), kind: Some(String::new()), edit: Some(snippet_workspace_edit(world, assist.source_change)?), command: None, -- cgit v1.2.3 From a9cb2933fbeddef4ed70bde77ded4f9bb185548e Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Tue, 2 Jun 2020 18:49:09 -0400 Subject: Add highlight support for unsafe fn calls and raw ptr deref --- crates/ra_hir/src/code_model.rs | 8 ++++ crates/ra_hir_def/src/data.rs | 6 ++- .../ra_ide/src/snapshots/highlight_injection.html | 1 + crates/ra_ide/src/snapshots/highlight_strings.html | 1 + crates/ra_ide/src/snapshots/highlight_unsafe.html | 48 ++++++++++++++++++++++ crates/ra_ide/src/snapshots/highlighting.html | 1 + .../ra_ide/src/snapshots/rainbow_highlighting.html | 1 + crates/ra_ide/src/syntax_highlighting.rs | 25 ++++++++++- crates/ra_ide/src/syntax_highlighting/html.rs | 1 + crates/ra_ide/src/syntax_highlighting/tags.rs | 8 ++-- crates/ra_ide/src/syntax_highlighting/tests.rs | 31 ++++++++++++++ 11 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 crates/ra_ide/src/snapshots/highlight_unsafe.html (limited to 'crates') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e40aeffbc..4a06f3bcd 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -637,6 +637,10 @@ impl Function { db.function_data(self.id).params.clone() } + pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { + db.function_data(self.id).is_unsafe + } + pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { let _p = profile("Function::diagnostics"); let infer = db.infer(self.id.into()); @@ -1190,6 +1194,10 @@ impl Type { ) } + pub fn is_raw_ptr(&self) -> bool { + matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) + } + pub fn contains_unknown(&self) -> bool { return go(&self.ty.value); diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index e2130d931..807195d25 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -34,6 +34,7 @@ pub struct FunctionData { /// True if the first param is `self`. This is relevant to decide whether this /// can be called as a method. pub has_self_param: bool, + pub is_unsafe: bool, pub visibility: RawVisibility, } @@ -85,11 +86,14 @@ impl FunctionData { ret_type }; + let is_unsafe = src.value.unsafe_token().is_some(); + let vis_default = RawVisibility::default_for_container(loc.container); let visibility = RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); - let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs }; + let sig = + FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; Arc::new(sig) } } diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html index 68fc589bc..fcdc98201 100644 --- a/crates/ra_ide/src/snapshots/highlight_injection.html +++ b/crates/ra_ide/src/snapshots/highlight_injection.html @@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 41cddd0ff..e97192b61 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html @@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/src/snapshots/highlight_unsafe.html new file mode 100644 index 000000000..17ffc727c --- /dev/null +++ b/crates/ra_ide/src/snapshots/highlight_unsafe.html @@ -0,0 +1,48 @@ + + +
unsafe fn unsafe_fn() {}
+
+struct HasUnsafeFn;
+
+impl HasUnsafeFn {
+    unsafe fn unsafe_method(&self) {}
+}
+
+fn main() {
+    let x = &5 as *const usize;
+    unsafe {
+        unsafe_fn();
+        HasUnsafeFn.unsafe_method();
+        let y = *x;
+        let z = -x;
+    }
+}
\ No newline at end of file diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 352e35095..42c5f3e55 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html @@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 2a0294f71..2dd61d20d 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html @@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 0b53ebe69..19ecd54d6 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -406,6 +406,23 @@ fn highlight_element( _ => h, } } + PREFIX_EXPR => { + let prefix_expr = element.into_node().and_then(ast::PrefixExpr::cast)?; + match prefix_expr.op_kind() { + Some(ast::PrefixOp::Deref) => {} + _ => return None, + } + + let expr = prefix_expr.expr()?; + let ty = sema.type_of_expr(&expr)?; + if !ty.is_raw_ptr() { + return None; + } + + let mut h = Highlight::new(HighlightTag::Operator); + h |= HighlightModifier::Unsafe; + h + } k if k.is_keyword() => { let h = Highlight::new(HighlightTag::Keyword); @@ -458,7 +475,13 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { Definition::Field(_) => HighlightTag::Field, Definition::ModuleDef(def) => match def { hir::ModuleDef::Module(_) => HighlightTag::Module, - hir::ModuleDef::Function(_) => HighlightTag::Function, + hir::ModuleDef::Function(func) => { + let mut h = HighlightTag::Function.into(); + if func.is_unsafe(db) { + h |= HighlightModifier::Unsafe; + } + return h; + } hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union, diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index edfe61f39..7d946c98d 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs @@ -69,6 +69,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs index 1514531de..94f466966 100644 --- a/crates/ra_ide/src/syntax_highlighting/tags.rs +++ b/crates/ra_ide/src/syntax_highlighting/tags.rs @@ -24,12 +24,14 @@ pub enum HighlightTag { Enum, EnumVariant, Field, + FormatSpecifier, Function, Keyword, Lifetime, Macro, Module, NumericLiteral, + Operator, SelfKeyword, SelfType, Static, @@ -41,8 +43,6 @@ pub enum HighlightTag { Union, Local, UnresolvedReference, - FormatSpecifier, - Operator, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -72,12 +72,14 @@ impl HighlightTag { HighlightTag::Enum => "enum", HighlightTag::EnumVariant => "enum_variant", HighlightTag::Field => "field", + HighlightTag::FormatSpecifier => "format_specifier", HighlightTag::Function => "function", HighlightTag::Keyword => "keyword", HighlightTag::Lifetime => "lifetime", HighlightTag::Macro => "macro", HighlightTag::Module => "module", HighlightTag::NumericLiteral => "numeric_literal", + HighlightTag::Operator => "operator", HighlightTag::SelfKeyword => "self_keyword", HighlightTag::SelfType => "self_type", HighlightTag::Static => "static", @@ -89,8 +91,6 @@ impl HighlightTag { HighlightTag::Union => "union", HighlightTag::Local => "variable", HighlightTag::UnresolvedReference => "unresolved_reference", - HighlightTag::FormatSpecifier => "format_specifier", - HighlightTag::Operator => "operator", } } } diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 7dc229cab..36a1aa419 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -258,3 +258,34 @@ fn main() { fs::write(dst_file, &actual_html).unwrap(); assert_eq_text!(expected_html, actual_html); } + +#[test] +fn test_unsafe_highlighting() { + let (analysis, file_id) = single_file( + r#" +unsafe fn unsafe_fn() {} + +struct HasUnsafeFn; + +impl HasUnsafeFn { + unsafe fn unsafe_method(&self) {} +} + +fn main() { + let x = &5 as *const usize; + unsafe { + unsafe_fn(); + HasUnsafeFn.unsafe_method(); + let y = *x; + let z = -x; + } +} +"# + .trim(), + ); + let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html"); + let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); + let expected_html = &read_text(&dst_file); + fs::write(dst_file, &actual_html).unwrap(); + assert_eq_text!(expected_html, actual_html); +} -- cgit v1.2.3 From 599c105e6fabb2b81c2d0a11b86c0c96f6ab1b88 Mon Sep 17 00:00:00 2001 From: Gabriel Valfridsson Date: Wed, 3 Jun 2020 00:51:23 +0200 Subject: Hide squiggly for unused and unnecessary --- ...yzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap | 2 +- crates/rust-analyzer/src/diagnostics/to_proto.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap index 6dd3fcb2e..33b516e26 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap @@ -29,7 +29,7 @@ expression: diag }, }, severity: Some( - Warning, + Hint, ), code: Some( String( diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index a500d670a..6a6e7b457 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -183,7 +183,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( return Vec::new(); } - let severity = map_level_to_severity(rd.level); + let mut severity = map_level_to_severity(rd.level); let mut source = String::from("rustc"); let mut code = rd.code.as_ref().map(|c| c.code.clone()); @@ -225,6 +225,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( } if is_unused_or_unnecessary(rd) { + severity = Some(DiagnosticSeverity::Hint); tags.push(DiagnosticTag::Unnecessary); } -- cgit v1.2.3 From ca80544f4baef69f3bb80e6b069291fbc89a927c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 10:33:01 +0200 Subject: Put important things on top --- crates/ra_project_model/src/json_project.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs index bd2bae15e..09c06fef9 100644 --- a/crates/ra_project_model/src/json_project.rs +++ b/crates/ra_project_model/src/json_project.rs @@ -5,6 +5,13 @@ use std::path::PathBuf; use rustc_hash::{FxHashMap, FxHashSet}; use serde::Deserialize; +/// Roots and crates that compose this Rust project. +#[derive(Clone, Debug, Deserialize)] +pub struct JsonProject { + pub(crate) roots: Vec, + pub(crate) crates: Vec, +} + /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in /// all roots. Roots might be nested. #[derive(Clone, Debug, Deserialize)] @@ -57,13 +64,6 @@ pub struct Dep { pub(crate) name: String, } -/// Roots and crates that compose this Rust project. -#[derive(Clone, Debug, Deserialize)] -pub struct JsonProject { - pub(crate) roots: Vec, - pub(crate) crates: Vec, -} - #[cfg(test)] mod tests { use super::*; -- cgit v1.2.3 From d4b21476a8f8dc882e2ace78e156da6fcb70a8ff Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 10:52:35 +0200 Subject: Derive local roots from Workspaces --- crates/rust-analyzer/src/main_loop.rs | 1 - crates/rust-analyzer/src/world.rs | 24 ++++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f1287d52c..2e5499485 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -164,7 +164,6 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) } WorldState::new( - ws_roots, workspaces, config.lru_capacity, &globs, diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 367272925..c1010e86a 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -58,7 +58,7 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> #[derive(Debug)] pub struct WorldState { pub config: Config, - pub roots: Vec, + pub local_roots: Vec, pub workspaces: Arc>, pub analysis_host: AnalysisHost, pub vfs: Arc>, @@ -81,7 +81,6 @@ pub struct WorldSnapshot { impl WorldState { pub fn new( - folder_roots: Vec, workspaces: Vec, lru_capacity: Option, exclude_globs: &[Glob], @@ -93,6 +92,7 @@ impl WorldState { let extern_dirs: FxHashSet<_> = workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); + let mut local_roots = Vec::new(); let roots: Vec<_> = { let create_filter = |is_member| { RustPackageFilterBuilder::default() @@ -100,12 +100,16 @@ impl WorldState { .exclude(exclude_globs.iter().cloned()) .into_vfs_filter() }; - folder_roots + workspaces .iter() - .map(|path| RootEntry::new(path.clone(), create_filter(true))) - .chain(workspaces.iter().flat_map(ProjectWorkspace::to_roots).map(|pkg_root| { - RootEntry::new(pkg_root.path().to_owned(), create_filter(pkg_root.is_member())) - })) + .flat_map(ProjectWorkspace::to_roots) + .map(|pkg_root| { + let path = pkg_root.path().to_owned(); + if pkg_root.is_member() { + local_roots.push(path.clone()); + } + RootEntry::new(path, create_filter(pkg_root.is_member())) + }) .chain( extern_dirs .iter() @@ -121,7 +125,7 @@ impl WorldState { let mut extern_source_roots = FxHashMap::default(); for r in vfs_roots { let vfs_root_path = vfs.root2path(r); - let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it)); + let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); change.add_root(SourceRootId(r.0), is_local); change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); @@ -178,7 +182,7 @@ impl WorldState { analysis_host.apply_change(change); WorldState { config, - roots: folder_roots, + local_roots, workspaces: Arc::new(workspaces), analysis_host, vfs: Arc::new(RwLock::new(vfs)), @@ -216,7 +220,7 @@ impl WorldState { match c { VfsChange::AddRoot { root, files } => { let root_path = self.vfs.read().root2path(root); - let is_local = self.roots.iter().any(|r| root_path.starts_with(r)); + let is_local = self.local_roots.iter().any(|r| root_path.starts_with(r)); if is_local { *roots_scanned += 1; for (file, path, text) in files { -- cgit v1.2.3 From ee181cf6833f338869f878eff11e026abe4e984e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 11:07:04 +0200 Subject: Drop no-project test Eventually, we should support "just open random rust file" use case, we don't really do this now, so let's avoid spending time on it until we fix it properly. --- crates/rust-analyzer/tests/heavy_tests/main.rs | 49 -------------------------- 1 file changed, 49 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index c80745945..69dc719c5 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -58,55 +58,6 @@ use std::collections::Spam; eprintln!("completion took {:?}", completion_start.elapsed()); } -#[test] -fn test_runnables_no_project() { - if skip_slow_tests() { - return; - } - - let server = project( - r" -//- lib.rs -#[test] -fn foo() { -} -", - ); - server.wait_until_workspace_is_loaded(); - server.request::( - RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, - json!([ - { - "args": { - "cargoArgs": ["test"], - "executableArgs": ["foo", "--nocapture"], - }, - "kind": "cargo", - "label": "test foo", - "location": { - "targetRange": { - "end": { "character": 1, "line": 2 }, - "start": { "character": 0, "line": 0 } - }, - "targetSelectionRange": { - "end": { "character": 6, "line": 1 }, - "start": { "character": 3, "line": 1 } - }, - "targetUri": "file:///[..]/lib.rs" - } - }, - { - "args": { - "cargoArgs": ["check", "--workspace"], - "executableArgs": [], - }, - "kind": "cargo", - "label": "cargo check --workspace" - } - ]), - ); -} - #[test] fn test_runnables_project() { if skip_slow_tests() { -- cgit v1.2.3 From a87cd8ecc66f1b644e4b11b8438fde1d5575b73c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 11:16:08 +0200 Subject: Rename WorldState -> GlobalState --- crates/rust-analyzer/src/cargo_target_spec.rs | 4 +- crates/rust-analyzer/src/from_proto.rs | 8 +- crates/rust-analyzer/src/global_state.rs | 347 ++++++++++++++++++++++++ crates/rust-analyzer/src/lib.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 88 +++--- crates/rust-analyzer/src/main_loop/handlers.rs | 357 +++++++++++++------------ crates/rust-analyzer/src/to_proto.rs | 87 +++--- crates/rust-analyzer/src/world.rs | 347 ------------------------ 8 files changed, 629 insertions(+), 611 deletions(-) create mode 100644 crates/rust-analyzer/src/global_state.rs delete mode 100644 crates/rust-analyzer/src/world.rs (limited to 'crates') diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 008518a08..44f856f6b 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -4,7 +4,7 @@ use ra_cfg::CfgExpr; use ra_ide::{FileId, RunnableKind, TestId}; use ra_project_model::{self, ProjectWorkspace, TargetKind}; -use crate::{world::WorldSnapshot, Result}; +use crate::{global_state::GlobalStateSnapshot, Result}; /// Abstract representation of Cargo target. /// @@ -89,7 +89,7 @@ impl CargoTargetSpec { } pub(crate) fn for_file( - world: &WorldSnapshot, + world: &GlobalStateSnapshot, file_id: FileId, ) -> Result> { let &crate_id = match world.analysis().crate_for(file_id)?.first() { diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 4bb16a496..206673829 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -3,7 +3,7 @@ use ra_db::{FileId, FilePosition, FileRange}; use ra_ide::{LineCol, LineIndex}; use ra_syntax::{TextRange, TextSize}; -use crate::{world::WorldSnapshot, Result}; +use crate::{global_state::GlobalStateSnapshot, Result}; pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 }; @@ -16,12 +16,12 @@ pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Tex TextRange::new(start, end) } -pub(crate) fn file_id(world: &WorldSnapshot, url: &lsp_types::Url) -> Result { +pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result { world.uri_to_file_id(url) } pub(crate) fn file_position( - world: &WorldSnapshot, + world: &GlobalStateSnapshot, tdpp: lsp_types::TextDocumentPositionParams, ) -> Result { let file_id = file_id(world, &tdpp.text_document.uri)?; @@ -31,7 +31,7 @@ pub(crate) fn file_position( } pub(crate) fn file_range( - world: &WorldSnapshot, + world: &GlobalStateSnapshot, text_document_identifier: lsp_types::TextDocumentIdentifier, range: lsp_types::Range, ) -> Result { diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs new file mode 100644 index 000000000..0bebb5bf6 --- /dev/null +++ b/crates/rust-analyzer/src/global_state.rs @@ -0,0 +1,347 @@ +//! The context or environment in which the language server functions. In our +//! server implementation this is know as the `WorldState`. +//! +//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. + +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; + +use crossbeam_channel::{unbounded, Receiver}; +use lsp_types::Url; +use parking_lot::RwLock; +use ra_flycheck::{Flycheck, FlycheckConfig}; +use ra_ide::{ + Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, +}; +use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace}; +use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; +use relative_path::RelativePathBuf; +use stdx::format_to; + +use crate::{ + config::Config, + diagnostics::{ + to_proto::url_from_path_with_drive_lowercasing, CheckFixes, DiagnosticCollection, + }, + main_loop::pending_requests::{CompletedRequest, LatestRequests}, + vfs_glob::{Glob, RustPackageFilterBuilder}, + LspError, Result, +}; +use ra_db::ExternSourceId; +use rustc_hash::{FxHashMap, FxHashSet}; + +fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option { + // FIXME: Figure out the multi-workspace situation + workspaces + .iter() + .find_map(|w| match w { + ProjectWorkspace::Cargo { cargo, .. } => Some(cargo), + ProjectWorkspace::Json { .. } => None, + }) + .map(|cargo| { + let cargo_project_root = cargo.workspace_root().to_path_buf(); + Some(Flycheck::new(config.clone(), cargo_project_root)) + }) + .unwrap_or_else(|| { + log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); + None + }) +} + +/// `GlobalState` is the primary mutable state of the language server +/// +/// The most interesting components are `vfs`, which stores a consistent +/// snapshot of the file systems, and `analysis_host`, which stores our +/// incremental salsa database. +#[derive(Debug)] +pub struct GlobalState { + pub config: Config, + pub local_roots: Vec, + pub workspaces: Arc>, + pub analysis_host: AnalysisHost, + pub vfs: Arc>, + pub task_receiver: Receiver, + pub latest_requests: Arc>, + pub flycheck: Option, + pub diagnostics: DiagnosticCollection, + pub proc_macro_client: ProcMacroClient, +} + +/// An immutable snapshot of the world's state at a point in time. +pub struct GlobalStateSnapshot { + pub config: Config, + pub workspaces: Arc>, + pub analysis: Analysis, + pub latest_requests: Arc>, + pub check_fixes: CheckFixes, + vfs: Arc>, +} + +impl GlobalState { + pub fn new( + workspaces: Vec, + lru_capacity: Option, + exclude_globs: &[Glob], + watch: Watch, + config: Config, + ) -> GlobalState { + let mut change = AnalysisChange::new(); + + let extern_dirs: FxHashSet<_> = + workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); + + let mut local_roots = Vec::new(); + let roots: Vec<_> = { + let create_filter = |is_member| { + RustPackageFilterBuilder::default() + .set_member(is_member) + .exclude(exclude_globs.iter().cloned()) + .into_vfs_filter() + }; + workspaces + .iter() + .flat_map(ProjectWorkspace::to_roots) + .map(|pkg_root| { + let path = pkg_root.path().to_owned(); + if pkg_root.is_member() { + local_roots.push(path.clone()); + } + RootEntry::new(path, create_filter(pkg_root.is_member())) + }) + .chain( + extern_dirs + .iter() + .map(|path| RootEntry::new(path.to_owned(), create_filter(false))), + ) + .collect() + }; + + let (task_sender, task_receiver) = unbounded(); + let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); + let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); + + let mut extern_source_roots = FxHashMap::default(); + for r in vfs_roots { + let vfs_root_path = vfs.root2path(r); + let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); + change.add_root(SourceRootId(r.0), is_local); + change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); + + // FIXME: add path2root in vfs to simpily this logic + if extern_dirs.contains(&vfs_root_path) { + extern_source_roots.insert(vfs_root_path, ExternSourceId(r.0)); + } + } + + // FIXME: Read default cfgs from config + let default_cfg_options = { + let mut opts = get_rustc_cfg_options(config.cargo.target.as_ref()); + opts.insert_atom("test".into()); + opts.insert_atom("debug_assertion".into()); + opts + }; + + let proc_macro_client = match &config.proc_macro_srv { + None => ProcMacroClient::dummy(), + Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { + Ok(it) => it, + Err(err) => { + log::error!( + "Failed to run ra_proc_macro_srv from path {}, error: {:?}", + path.display(), + err + ); + ProcMacroClient::dummy() + } + }, + }; + + // Create crate graph from all the workspaces + let mut crate_graph = CrateGraph::default(); + let mut load = |path: &Path| { + // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs + let path = path.canonicalize().ok()?; + let vfs_file = vfs.load(&path); + vfs_file.map(|f| FileId(f.0)) + }; + for ws in workspaces.iter() { + crate_graph.extend(ws.to_crate_graph( + &default_cfg_options, + &extern_source_roots, + &proc_macro_client, + &mut load, + )); + } + change.set_crate_graph(crate_graph); + + let flycheck = config.check.as_ref().and_then(|c| create_flycheck(&workspaces, c)); + + let mut analysis_host = AnalysisHost::new(lru_capacity); + analysis_host.apply_change(change); + GlobalState { + config, + local_roots, + workspaces: Arc::new(workspaces), + analysis_host, + vfs: Arc::new(RwLock::new(vfs)), + task_receiver, + latest_requests: Default::default(), + flycheck, + diagnostics: Default::default(), + proc_macro_client, + } + } + + pub fn update_configuration(&mut self, config: Config) { + self.analysis_host.update_lru_capacity(config.lru_capacity); + if config.check != self.config.check { + self.flycheck = + config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it)); + } + + self.config = config; + } + + /// Returns a vec of libraries + /// FIXME: better API here + pub fn process_changes( + &mut self, + roots_scanned: &mut usize, + ) -> Option)>)>> { + let changes = self.vfs.write().commit_changes(); + if changes.is_empty() { + return None; + } + let mut libs = Vec::new(); + let mut change = AnalysisChange::new(); + for c in changes { + match c { + VfsChange::AddRoot { root, files } => { + let root_path = self.vfs.read().root2path(root); + let is_local = self.local_roots.iter().any(|r| root_path.starts_with(r)); + if is_local { + *roots_scanned += 1; + for (file, path, text) in files { + change.add_file(SourceRootId(root.0), FileId(file.0), path, text); + } + } else { + let files = files + .into_iter() + .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) + .collect(); + libs.push((SourceRootId(root.0), files)); + } + } + VfsChange::AddFile { root, file, path, text } => { + change.add_file(SourceRootId(root.0), FileId(file.0), path, text); + } + VfsChange::RemoveFile { root, file, path } => { + change.remove_file(SourceRootId(root.0), FileId(file.0), path) + } + VfsChange::ChangeFile { file, text } => { + change.change_file(FileId(file.0), text); + } + } + } + self.analysis_host.apply_change(change); + Some(libs) + } + + pub fn add_lib(&mut self, data: LibraryData) { + let mut change = AnalysisChange::new(); + change.add_library(data); + self.analysis_host.apply_change(change); + } + + pub fn snapshot(&self) -> GlobalStateSnapshot { + GlobalStateSnapshot { + config: self.config.clone(), + workspaces: Arc::clone(&self.workspaces), + analysis: self.analysis_host.analysis(), + vfs: Arc::clone(&self.vfs), + latest_requests: Arc::clone(&self.latest_requests), + check_fixes: Arc::clone(&self.diagnostics.check_fixes), + } + } + + pub fn maybe_collect_garbage(&mut self) { + self.analysis_host.maybe_collect_garbage() + } + + pub fn collect_garbage(&mut self) { + self.analysis_host.collect_garbage() + } + + pub fn complete_request(&mut self, request: CompletedRequest) { + self.latest_requests.write().record(request) + } +} + +impl GlobalStateSnapshot { + pub fn analysis(&self) -> &Analysis { + &self.analysis + } + + pub fn uri_to_file_id(&self, uri: &Url) -> Result { + let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; + let file = self.vfs.read().path2file(&path).ok_or_else(|| { + // Show warning as this file is outside current workspace + // FIXME: just handle such files, and remove `LspError::UNKNOWN_FILE`. + LspError { + code: LspError::UNKNOWN_FILE, + message: "Rust file outside current workspace is not supported yet.".to_string(), + } + })?; + Ok(FileId(file.0)) + } + + pub fn file_id_to_uri(&self, id: FileId) -> Result { + let path = self.vfs.read().file2path(VfsFile(id.0)); + let url = url_from_path_with_drive_lowercasing(path)?; + + Ok(url) + } + + pub fn file_id_to_path(&self, id: FileId) -> PathBuf { + self.vfs.read().file2path(VfsFile(id.0)) + } + + pub fn file_line_endings(&self, id: FileId) -> LineEndings { + self.vfs.read().file_line_endings(VfsFile(id.0)) + } + + pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result { + let base = self.vfs.read().root2path(VfsRoot(root.0)); + let path = path.to_path(base); + let url = Url::from_file_path(&path) + .map_err(|_| format!("can't convert path to url: {}", path.display()))?; + Ok(url) + } + + pub fn status(&self) -> String { + let mut buf = String::new(); + if self.workspaces.is_empty() { + buf.push_str("no workspaces\n") + } else { + buf.push_str("workspaces:\n"); + for w in self.workspaces.iter() { + format_to!(buf, "{} packages loaded\n", w.n_packages()); + } + } + buf.push_str("\nanalysis:\n"); + buf.push_str( + &self + .analysis + .status() + .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()), + ); + buf + } + + pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> { + let path = self.vfs.read().file2path(VfsFile(file_id.0)); + self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) + } +} diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 57d0e9218..609cb69d3 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -26,7 +26,7 @@ mod main_loop; mod markdown; pub mod lsp_ext; pub mod config; -mod world; +mod global_state; mod diagnostics; mod semantic_tokens; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 2e5499485..35f2d7001 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -38,12 +38,13 @@ use threadpool::ThreadPool; use crate::{ config::{Config, FilesWatcher}, diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, - from_proto, lsp_ext, + from_proto, + global_state::{GlobalState, GlobalStateSnapshot}, + lsp_ext, main_loop::{ pending_requests::{PendingRequest, PendingRequests}, subscriptions::Subscriptions, }, - world::{WorldSnapshot, WorldState}, Result, }; @@ -92,7 +93,7 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) } let mut loop_state = LoopState::default(); - let mut world_state = { + let mut global_state = { let workspaces = { // FIXME: support dynamic workspace loading. let project_roots: FxHashSet<_> = ws_roots @@ -163,7 +164,7 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) connection.sender.send(request.into()).unwrap(); } - WorldState::new( + GlobalState::new( workspaces, config.lru_capacity, &globs, @@ -172,7 +173,7 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) ) }; - loop_state.roots_total = world_state.vfs.read().n_roots(); + loop_state.roots_total = global_state.vfs.read().n_roots(); let pool = ThreadPool::default(); let (task_sender, task_receiver) = unbounded::(); @@ -190,12 +191,12 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) Err(RecvError) => return Err("client exited without shutdown".into()), }, recv(task_receiver) -> task => Event::Task(task.unwrap()), - recv(world_state.task_receiver) -> task => match task { + recv(global_state.task_receiver) -> task => match task { Ok(task) => Event::Vfs(task), Err(RecvError) => return Err("vfs died".into()), }, recv(libdata_receiver) -> data => Event::Lib(data.unwrap()), - recv(world_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { + recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { Ok(task) => Event::CheckWatcher(task), Err(RecvError) => return Err("check watcher died".into()), } @@ -210,16 +211,16 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) &task_sender, &libdata_sender, &connection, - &mut world_state, + &mut global_state, &mut loop_state, event, )?; } } - world_state.analysis_host.request_cancellation(); + global_state.analysis_host.request_cancellation(); log::info!("waiting for tasks to finish..."); task_receiver.into_iter().for_each(|task| { - on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) + on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state) }); libdata_receiver.into_iter().for_each(drop); log::info!("...tasks have finished"); @@ -228,7 +229,7 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) drop(pool); log::info!("...threadpool has finished"); - let vfs = Arc::try_unwrap(world_state.vfs).expect("all snapshots should be dead"); + let vfs = Arc::try_unwrap(global_state.vfs).expect("all snapshots should be dead"); drop(vfs); Ok(()) @@ -319,7 +320,7 @@ fn loop_turn( task_sender: &Sender, libdata_sender: &Sender, connection: &Connection, - world_state: &mut WorldState, + global_state: &mut GlobalState, loop_state: &mut LoopState, event: Event, ) -> Result<()> { @@ -335,22 +336,22 @@ fn loop_turn( match event { Event::Task(task) => { - on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); - world_state.maybe_collect_garbage(); + on_task(task, &connection.sender, &mut loop_state.pending_requests, global_state); + global_state.maybe_collect_garbage(); } Event::Vfs(task) => { - world_state.vfs.write().handle_task(task); + global_state.vfs.write().handle_task(task); } Event::Lib(lib) => { - world_state.add_lib(lib); - world_state.maybe_collect_garbage(); + global_state.add_lib(lib); + global_state.maybe_collect_garbage(); loop_state.in_flight_libraries -= 1; loop_state.roots_scanned += 1; } - Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, + Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?, Event::Msg(msg) => match msg { Message::Request(req) => on_request( - world_state, + global_state, &mut loop_state.pending_requests, pool, task_sender, @@ -359,7 +360,7 @@ fn loop_turn( req, )?, Message::Notification(not) => { - on_notification(&connection.sender, world_state, loop_state, not)?; + on_notification(&connection.sender, global_state, loop_state, not)?; } Message::Response(resp) => { let removed = loop_state.pending_responses.remove(&resp.id); @@ -378,9 +379,9 @@ fn loop_turn( } (None, Some(configs)) => { if let Some(new_config) = configs.get(0) { - let mut config = world_state.config.clone(); + let mut config = global_state.config.clone(); config.update(&new_config); - world_state.update_configuration(config); + global_state.update_configuration(config); } } (None, None) => { @@ -393,7 +394,7 @@ fn loop_turn( }; let mut state_changed = false; - if let Some(changes) = world_state.process_changes(&mut loop_state.roots_scanned) { + if let Some(changes) = global_state.process_changes(&mut loop_state.roots_scanned) { state_changed = true; loop_state.pending_libraries.extend(changes); } @@ -415,7 +416,7 @@ fn loop_turn( } let show_progress = - !loop_state.workspace_loaded && world_state.config.client_caps.work_done_progress; + !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress; if !loop_state.workspace_loaded && loop_state.roots_scanned == loop_state.roots_total @@ -424,7 +425,7 @@ fn loop_turn( { state_changed = true; loop_state.workspace_loaded = true; - if let Some(flycheck) = &world_state.flycheck { + if let Some(flycheck) = &global_state.flycheck { flycheck.update(); } } @@ -436,13 +437,13 @@ fn loop_turn( if state_changed && loop_state.workspace_loaded { update_file_notifications_on_threadpool( pool, - world_state.snapshot(), + global_state.snapshot(), task_sender.clone(), loop_state.subscriptions.subscriptions(), ); pool.execute({ let subs = loop_state.subscriptions.subscriptions(); - let snap = world_state.snapshot(); + let snap = global_state.snapshot(); move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) }); } @@ -466,7 +467,7 @@ fn on_task( task: Task, msg_sender: &Sender, pending_requests: &mut PendingRequests, - state: &mut WorldState, + state: &mut GlobalState, ) { match task { Task::Respond(response) => { @@ -484,7 +485,7 @@ fn on_task( } fn on_request( - world: &mut WorldState, + global_state: &mut GlobalState, pending_requests: &mut PendingRequests, pool: &ThreadPool, task_sender: &Sender, @@ -495,7 +496,7 @@ fn on_request( let mut pool_dispatcher = PoolDispatcher { req: Some(req), pool, - world, + global_state, task_sender, msg_sender, pending_requests, @@ -551,7 +552,7 @@ fn on_request( fn on_notification( msg_sender: &Sender, - state: &mut WorldState, + state: &mut GlobalState, loop_state: &mut LoopState, not: Notification, ) -> Result<()> { @@ -725,7 +726,7 @@ fn apply_document_changes( fn on_check_task( task: CheckTask, - world_state: &mut WorldState, + global_state: &mut GlobalState, task_sender: &Sender, ) -> Result<()> { match task { @@ -744,7 +745,7 @@ fn on_check_task( .uri .to_file_path() .map_err(|()| format!("invalid uri: {}", diag.location.uri))?; - let file_id = match world_state.vfs.read().path2file(&path) { + let file_id = match global_state.vfs.read().path2file(&path) { Some(file) => FileId(file.0), None => { log::error!( @@ -764,7 +765,7 @@ fn on_check_task( } CheckTask::Status(status) => { - if world_state.config.client_caps.work_done_progress { + if global_state.config.client_caps.work_done_progress { let progress = match status { Status::Being => { lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { @@ -803,7 +804,7 @@ fn on_check_task( Ok(()) } -fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender, state: &mut WorldState) { +fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender, state: &mut GlobalState) { let subscriptions = state.diagnostics.handle_task(task); for file_id in subscriptions { @@ -878,7 +879,7 @@ fn send_startup_progress(sender: &Sender, loop_state: &mut LoopState) { struct PoolDispatcher<'a> { req: Option, pool: &'a ThreadPool, - world: &'a mut WorldState, + global_state: &'a mut GlobalState, pending_requests: &'a mut PendingRequests, msg_sender: &'a Sender, task_sender: &'a Sender, @@ -889,7 +890,7 @@ impl<'a> PoolDispatcher<'a> { /// Dispatches the request onto the current thread fn on_sync( &mut self, - f: fn(&mut WorldState, R::Params) -> Result, + f: fn(&mut GlobalState, R::Params) -> Result, ) -> Result<&mut Self> where R: lsp_types::request::Request + 'static, @@ -902,18 +903,21 @@ impl<'a> PoolDispatcher<'a> { return Ok(self); } }; - let world = panic::AssertUnwindSafe(&mut *self.world); + let world = panic::AssertUnwindSafe(&mut *self.global_state); let task = panic::catch_unwind(move || { let result = f(world.0, params); result_to_task::(id, result) }) .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?; - on_task(task, self.msg_sender, self.pending_requests, self.world); + on_task(task, self.msg_sender, self.pending_requests, self.global_state); Ok(self) } /// Dispatches the request onto thread pool - fn on(&mut self, f: fn(WorldSnapshot, R::Params) -> Result) -> Result<&mut Self> + fn on( + &mut self, + f: fn(GlobalStateSnapshot, R::Params) -> Result, + ) -> Result<&mut Self> where R: lsp_types::request::Request + 'static, R::Params: DeserializeOwned + Send + 'static, @@ -927,7 +931,7 @@ impl<'a> PoolDispatcher<'a> { }; self.pool.execute({ - let world = self.world.snapshot(); + let world = self.global_state.snapshot(); let sender = self.task_sender.clone(); move || { let result = f(world, params); @@ -1011,7 +1015,7 @@ where fn update_file_notifications_on_threadpool( pool: &ThreadPool, - world: WorldSnapshot, + world: GlobalStateSnapshot, task_sender: Sender, subscriptions: Vec, ) { diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 7fd691764..1bb8e4473 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -32,17 +32,16 @@ use crate::{ config::RustfmtConfig, diagnostics::DiagnosticTask, from_json, from_proto, + global_state::GlobalStateSnapshot, lsp_ext::{self, InlayHint, InlayHintsParams}, - to_proto, - world::WorldSnapshot, - LspError, Result, + to_proto, LspError, Result, }; -pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { +pub fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result { let _p = profile("handle_analyzer_status"); - let mut buf = world.status(); + let mut buf = snap.status(); format_to!(buf, "\n\nrequests:\n"); - let requests = world.latest_requests.read(); + let requests = snap.latest_requests.read(); for (is_last, r) in requests.iter() { let mark = if is_last { "*" } else { " " }; format_to!(buf, "{}{:4} {:<36}{}ms\n", mark, r.id, r.method, r.duration.as_millis()); @@ -51,37 +50,37 @@ pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { } pub fn handle_syntax_tree( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_ext::SyntaxTreeParams, ) -> Result { let _p = profile("handle_syntax_tree"); - let id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(id)?; + let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(id)?; let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); - let res = world.analysis().syntax_tree(id, text_range)?; + let res = snap.analysis().syntax_tree(id, text_range)?; Ok(res) } pub fn handle_expand_macro( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_ext::ExpandMacroParams, ) -> Result> { let _p = profile("handle_expand_macro"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position); - let res = world.analysis().expand_macro(FilePosition { file_id, offset })?; + let res = snap.analysis().expand_macro(FilePosition { file_id, offset })?; Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) } pub fn handle_selection_range( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::SelectionRangeParams, ) -> Result>> { let _p = profile("handle_selection_range"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; let res: Result> = params .positions .into_iter() @@ -93,7 +92,7 @@ pub fn handle_selection_range( loop { ranges.push(range); let frange = FileRange { file_id, range }; - let next = world.analysis().extend_selection(frange)?; + let next = snap.analysis().extend_selection(frange)?; if next == range { break; } else { @@ -119,18 +118,18 @@ pub fn handle_selection_range( } pub fn handle_matching_brace( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_ext::MatchingBraceParams, ) -> Result> { let _p = profile("handle_matching_brace"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; let res = params .positions .into_iter() .map(|position| { let offset = from_proto::offset(&line_index, position); - let offset = match world.analysis().matching_brace(FilePosition { file_id, offset }) { + let offset = match snap.analysis().matching_brace(FilePosition { file_id, offset }) { Ok(Some(matching_brace_offset)) => matching_brace_offset, Err(_) | Ok(None) => offset, }; @@ -141,17 +140,17 @@ pub fn handle_matching_brace( } pub fn handle_join_lines( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_ext::JoinLinesParams, ) -> Result> { let _p = profile("handle_join_lines"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; - let line_endings = world.file_line_endings(file_id); + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; + let line_endings = snap.file_line_endings(file_id); let mut res = TextEdit::default(); for range in params.ranges { let range = from_proto::text_range(&line_index, range); - let edit = world.analysis().join_lines(FileRange { file_id, range })?; + let edit = snap.analysis().join_lines(FileRange { file_id, range })?; match res.union(edit) { Ok(()) => (), Err(_edit) => { @@ -164,37 +163,37 @@ pub fn handle_join_lines( } pub fn handle_on_enter( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> Result>> { let _p = profile("handle_on_enter"); - let position = from_proto::file_position(&world, params)?; - let edit = match world.analysis().on_enter(position)? { + let position = from_proto::file_position(&snap, params)?; + let edit = match snap.analysis().on_enter(position)? { None => return Ok(None), Some(it) => it, }; - let line_index = world.analysis().file_line_index(position.file_id)?; - let line_endings = world.file_line_endings(position.file_id); + let line_index = snap.analysis().file_line_index(position.file_id)?; + let line_endings = snap.file_line_endings(position.file_id); let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit); Ok(Some(edit)) } // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. pub fn handle_on_type_formatting( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::DocumentOnTypeFormattingParams, ) -> Result>> { let _p = profile("handle_on_type_formatting"); - let mut position = from_proto::file_position(&world, params.text_document_position)?; - let line_index = world.analysis().file_line_index(position.file_id)?; - let line_endings = world.file_line_endings(position.file_id); + let mut position = from_proto::file_position(&snap, params.text_document_position)?; + let line_index = snap.analysis().file_line_index(position.file_id)?; + let line_endings = snap.file_line_endings(position.file_id); // in `ra_ide`, the `on_type` invariant is that // `text.char_at(position) == typed_char`. position.offset -= TextSize::of('.'); let char_typed = params.ch.chars().next().unwrap_or('\0'); assert!({ - let text = world.analysis().file_text(position.file_id)?; + let text = snap.analysis().file_text(position.file_id)?; text[usize::from(position.offset)..].starts_with(char_typed) }); @@ -206,7 +205,7 @@ pub fn handle_on_type_formatting( return Ok(None); } - let edit = world.analysis().on_char_typed(position, char_typed)?; + let edit = snap.analysis().on_char_typed(position, char_typed)?; let mut edit = match edit { Some(it) => it, None => return Ok(None), @@ -220,16 +219,16 @@ pub fn handle_on_type_formatting( } pub fn handle_document_symbol( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::DocumentSymbolParams, ) -> Result> { let _p = profile("handle_document_symbol"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; let mut parents: Vec<(DocumentSymbol, Option)> = Vec::new(); - for symbol in world.analysis().file_structure(file_id)? { + for symbol in snap.analysis().file_structure(file_id)? { let doc_symbol = DocumentSymbol { name: symbol.label, detail: symbol.detail, @@ -255,10 +254,10 @@ pub fn handle_document_symbol( } } - let res = if world.config.client_caps.hierarchical_symbols { + let res = if snap.config.client_caps.hierarchical_symbols { document_symbols.into() } else { - let url = to_proto::url(&world, file_id)?; + let url = to_proto::url(&snap, file_id)?; let mut symbol_information = Vec::::new(); for symbol in document_symbols { flatten_document_symbol(&symbol, None, &url, &mut symbol_information); @@ -288,7 +287,7 @@ pub fn handle_document_symbol( } pub fn handle_workspace_symbol( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::WorkspaceSymbolParams, ) -> Result>> { let _p = profile("handle_workspace_symbol"); @@ -306,22 +305,22 @@ pub fn handle_workspace_symbol( q.limit(128); q }; - let mut res = exec_query(&world, query)?; + let mut res = exec_query(&snap, query)?; if res.is_empty() && !all_symbols { let mut query = Query::new(params.query); query.limit(128); - res = exec_query(&world, query)?; + res = exec_query(&snap, query)?; } return Ok(Some(res)); - fn exec_query(world: &WorldSnapshot, query: Query) -> Result> { + fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result> { let mut res = Vec::new(); - for nav in world.analysis().symbol_search(query)? { + for nav in snap.analysis().symbol_search(query)? { let info = SymbolInformation { name: nav.name().to_string(), kind: to_proto::symbol_kind(nav.kind()), - location: to_proto::location(world, nav.file_range())?, + location: to_proto::location(snap, nav.file_range())?, container_name: nav.container_name().map(|v| v.to_string()), deprecated: None, }; @@ -332,73 +331,73 @@ pub fn handle_workspace_symbol( } pub fn handle_goto_definition( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::GotoDefinitionParams, ) -> Result> { let _p = profile("handle_goto_definition"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; - let nav_info = match world.analysis().goto_definition(position)? { + let position = from_proto::file_position(&snap, params.text_document_position_params)?; + let nav_info = match snap.analysis().goto_definition(position)? { None => return Ok(None), Some(it) => it, }; let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; + let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } pub fn handle_goto_implementation( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::request::GotoImplementationParams, ) -> Result> { let _p = profile("handle_goto_implementation"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; - let nav_info = match world.analysis().goto_implementation(position)? { + let position = from_proto::file_position(&snap, params.text_document_position_params)?; + let nav_info = match snap.analysis().goto_implementation(position)? { None => return Ok(None), Some(it) => it, }; let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; + let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } pub fn handle_goto_type_definition( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::request::GotoTypeDefinitionParams, ) -> Result> { let _p = profile("handle_goto_type_definition"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; - let nav_info = match world.analysis().goto_type_definition(position)? { + let position = from_proto::file_position(&snap, params.text_document_position_params)?; + let nav_info = match snap.analysis().goto_type_definition(position)? { None => return Ok(None), Some(it) => it, }; let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; + let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } pub fn handle_parent_module( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> Result> { let _p = profile("handle_parent_module"); - let position = from_proto::file_position(&world, params)?; - let navs = world.analysis().parent_module(position)?; - let res = to_proto::goto_definition_response(&world, None, navs)?; + let position = from_proto::file_position(&snap, params)?; + let navs = snap.analysis().parent_module(position)?; + let res = to_proto::goto_definition_response(&snap, None, navs)?; Ok(Some(res)) } pub fn handle_runnables( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_ext::RunnablesParams, ) -> Result> { let _p = profile("handle_runnables"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; let offset = params.position.map(|it| from_proto::offset(&line_index, it)); let mut res = Vec::new(); - let workspace_root = world.workspace_root_for(file_id); - let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; - for runnable in world.analysis().runnables(file_id)? { + let workspace_root = snap.workspace_root_for(file_id); + let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; + for runnable in snap.analysis().runnables(file_id)? { if let Some(offset) = offset { if !runnable.nav.full_range().contains_inclusive(offset) { continue; @@ -413,7 +412,7 @@ pub fn handle_runnables( } } } - res.push(to_proto::runnable(&world, file_id, runnable)?); + res.push(to_proto::runnable(&snap, file_id, runnable)?); } // Add `cargo check` and `cargo test` for the whole package @@ -453,16 +452,16 @@ pub fn handle_runnables( } pub fn handle_completion( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::CompletionParams, ) -> Result> { let _p = profile("handle_completion"); - let position = from_proto::file_position(&world, params.text_document_position)?; + let position = from_proto::file_position(&snap, params.text_document_position)?; let completion_triggered_after_single_colon = { let mut res = false; if let Some(ctx) = params.context { if ctx.trigger_character.unwrap_or_default() == ":" { - let source_file = world.analysis().parse(position.file_id)?; + let source_file = snap.analysis().parse(position.file_id)?; let syntax = source_file.syntax(); let text = syntax.text(); if let Some(next_char) = text.char_at(position.offset) { @@ -480,12 +479,12 @@ pub fn handle_completion( return Ok(None); } - let items = match world.analysis().completions(&world.config.completion, position)? { + let items = match snap.analysis().completions(&snap.config.completion, position)? { None => return Ok(None), Some(items) => items, }; - let line_index = world.analysis().file_line_index(position.file_id)?; - let line_endings = world.file_line_endings(position.file_id); + let line_index = snap.analysis().file_line_index(position.file_id)?; + let line_endings = snap.file_line_endings(position.file_id); let items: Vec = items .into_iter() .map(|item| to_proto::completion_item(&line_index, line_endings, item)) @@ -495,15 +494,15 @@ pub fn handle_completion( } pub fn handle_folding_range( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: FoldingRangeParams, ) -> Result>> { let _p = profile("handle_folding_range"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let folds = world.analysis().folding_ranges(file_id)?; - let text = world.analysis().file_text(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; - let line_folding_only = world.config.client_caps.line_folding_only; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let folds = snap.analysis().folding_ranges(file_id)?; + let text = snap.analysis().file_text(file_id)?; + let line_index = snap.analysis().file_line_index(file_id)?; + let line_folding_only = snap.config.client_caps.line_folding_only; let res = folds .into_iter() .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) @@ -512,16 +511,16 @@ pub fn handle_folding_range( } pub fn handle_signature_help( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::SignatureHelpParams, ) -> Result> { let _p = profile("handle_signature_help"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; - let call_info = match world.analysis().call_info(position)? { + let position = from_proto::file_position(&snap, params.text_document_position_params)?; + let call_info = match snap.analysis().call_info(position)? { None => return Ok(None), Some(it) => it, }; - let concise = !world.config.call_info_full; + let concise = !snap.config.call_info_full; let mut active_parameter = call_info.active_parameter.map(|it| it as i64); if concise && call_info.signature.has_self_param { active_parameter = active_parameter.map(|it| it.saturating_sub(1)); @@ -535,14 +534,17 @@ pub fn handle_signature_help( })) } -pub fn handle_hover(world: WorldSnapshot, params: lsp_types::HoverParams) -> Result> { +pub fn handle_hover( + snap: GlobalStateSnapshot, + params: lsp_types::HoverParams, +) -> Result> { let _p = profile("handle_hover"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; - let info = match world.analysis().hover(position)? { + let position = from_proto::file_position(&snap, params.text_document_position_params)?; + let info = match snap.analysis().hover(position)? { None => return Ok(None), Some(info) => info, }; - let line_index = world.analysis.file_line_index(position.file_id)?; + let line_index = snap.analysis.file_line_index(position.file_id)?; let range = to_proto::range(&line_index, info.range); let res = Hover { contents: HoverContents::Markup(MarkupContent { @@ -555,26 +557,29 @@ pub fn handle_hover(world: WorldSnapshot, params: lsp_types::HoverParams) -> Res } pub fn handle_prepare_rename( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> Result> { let _p = profile("handle_prepare_rename"); - let position = from_proto::file_position(&world, params)?; + let position = from_proto::file_position(&snap, params)?; - let optional_change = world.analysis().rename(position, "dummy")?; + let optional_change = snap.analysis().rename(position, "dummy")?; let range = match optional_change { None => return Ok(None), Some(it) => it.range, }; - let line_index = world.analysis().file_line_index(position.file_id)?; + let line_index = snap.analysis().file_line_index(position.file_id)?; let range = to_proto::range(&line_index, range); Ok(Some(PrepareRenameResponse::Range(range))) } -pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result> { +pub fn handle_rename( + snap: GlobalStateSnapshot, + params: RenameParams, +) -> Result> { let _p = profile("handle_rename"); - let position = from_proto::file_position(&world, params.text_document_position)?; + let position = from_proto::file_position(&snap, params.text_document_position)?; if params.new_name.is_empty() { return Err(LspError::new( @@ -584,36 +589,36 @@ pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result return Ok(None), Some(it) => it.info, }; - let workspace_edit = to_proto::workspace_edit(&world, source_change)?; + let workspace_edit = to_proto::workspace_edit(&snap, source_change)?; Ok(Some(workspace_edit)) } pub fn handle_references( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::ReferenceParams, ) -> Result>> { let _p = profile("handle_references"); - let position = from_proto::file_position(&world, params.text_document_position)?; + let position = from_proto::file_position(&snap, params.text_document_position)?; - let refs = match world.analysis().find_all_refs(position, None)? { + let refs = match snap.analysis().find_all_refs(position, None)? { None => return Ok(None), Some(refs) => refs, }; let locations = if params.context.include_declaration { refs.into_iter() - .filter_map(|reference| to_proto::location(&world, reference.file_range).ok()) + .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) .collect() } else { // Only iterate over the references if include_declaration was false refs.references() .iter() - .filter_map(|reference| to_proto::location(&world, reference.file_range).ok()) + .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) .collect() }; @@ -621,24 +626,24 @@ pub fn handle_references( } pub fn handle_formatting( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: DocumentFormattingParams, ) -> Result>> { let _p = profile("handle_formatting"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let file = world.analysis().file_text(file_id)?; - let crate_ids = world.analysis().crate_for(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let file = snap.analysis().file_text(file_id)?; + let crate_ids = snap.analysis().crate_for(file_id)?; - let file_line_index = world.analysis().file_line_index(file_id)?; + let file_line_index = snap.analysis().file_line_index(file_id)?; let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); - let mut rustfmt = match &world.config.rustfmt { + let mut rustfmt = match &snap.config.rustfmt { RustfmtConfig::Rustfmt { extra_args } => { let mut cmd = process::Command::new("rustfmt"); cmd.args(extra_args); if let Some(&crate_id) = crate_ids.first() { // Assume all crates are in the same edition - let edition = world.analysis().crate_edition(crate_id)?; + let edition = snap.analysis().crate_edition(crate_id)?; cmd.arg("--edition"); cmd.arg(edition.to_string()); } @@ -697,23 +702,23 @@ pub fn handle_formatting( } pub fn handle_code_action( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::CodeActionParams, ) -> Result>> { let _p = profile("handle_code_action"); // We intentionally don't support command-based actions, as those either // requires custom client-code anyway, or requires server-initiated edits. // Server initiated edits break causality, so we avoid those as well. - if !world.config.client_caps.code_action_literals { + if !snap.config.client_caps.code_action_literals { return Ok(None); } - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; let range = from_proto::text_range(&line_index, params.range); let frange = FileRange { file_id, range }; - let diagnostics = world.analysis().diagnostics(file_id)?; + let diagnostics = snap.analysis().diagnostics(file_id)?; let mut res: Vec = Vec::new(); let fixes_from_diagnostics = diagnostics @@ -724,13 +729,13 @@ pub fn handle_code_action( for fix in fixes_from_diagnostics { let title = fix.label; - let edit = to_proto::snippet_workspace_edit(&world, fix.source_change)?; + let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; let action = lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; res.push(action); } - for fix in world.check_fixes.get(&file_id).into_iter().flatten() { + for fix in snap.check_fixes.get(&file_id).into_iter().flatten() { let fix_range = from_proto::text_range(&line_index, fix.range); if fix_range.intersect(range).is_none() { continue; @@ -738,31 +743,31 @@ pub fn handle_code_action( res.push(fix.action.clone()); } - for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() { - res.push(to_proto::code_action(&world, assist)?.into()); + for assist in snap.analysis().assists(&snap.config.assist, frange)?.into_iter() { + res.push(to_proto::code_action(&snap, assist)?.into()); } Ok(Some(res)) } pub fn handle_code_lens( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::CodeLensParams, ) -> Result>> { let _p = profile("handle_code_lens"); let mut lenses: Vec = Default::default(); - if world.config.lens.none() { + if snap.config.lens.none() { // early return before any db query! return Ok(Some(lenses)); } - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; - let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.analysis().file_line_index(file_id)?; + let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; - if world.config.lens.runnable() { + if snap.config.lens.runnable() { // Gather runnables - for runnable in world.analysis().runnables(file_id)? { + for runnable in snap.analysis().runnables(file_id)? { let (run_title, debugee) = match &runnable.kind { RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { ("▶\u{fe0e} Run Test", true) @@ -788,8 +793,8 @@ pub fn handle_code_lens( }; let range = to_proto::range(&line_index, runnable.nav.range()); - let r = to_proto::runnable(&world, file_id, runnable)?; - if world.config.lens.run { + let r = to_proto::runnable(&snap, file_id, runnable)?; + if snap.config.lens.run { let lens = CodeLens { range, command: Some(Command { @@ -802,7 +807,7 @@ pub fn handle_code_lens( lenses.push(lens); } - if debugee && world.config.lens.debug { + if debugee && snap.config.lens.debug { let debug_lens = CodeLens { range, command: Some(Command { @@ -817,11 +822,10 @@ pub fn handle_code_lens( } } - if world.config.lens.impementations { + if snap.config.lens.impementations { // Handle impls lenses.extend( - world - .analysis() + snap.analysis() .file_structure(file_id)? .into_iter() .filter(|it| match it.kind { @@ -856,14 +860,17 @@ enum CodeLensResolveData { Impls(lsp_types::request::GotoImplementationParams), } -pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result { +pub fn handle_code_lens_resolve( + snap: GlobalStateSnapshot, + code_lens: CodeLens, +) -> Result { let _p = profile("handle_code_lens_resolve"); let data = code_lens.data.unwrap(); let resolve = from_json::>("CodeLensResolveData", data)?; match resolve { Some(CodeLensResolveData::Impls(lens_params)) => { let locations: Vec = - match handle_goto_implementation(world, lens_params.clone())? { + match handle_goto_implementation(snap, lens_params.clone())? { Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) => vec![loc], Some(lsp_types::GotoDefinitionResponse::Array(locs)) => locs, Some(lsp_types::GotoDefinitionResponse::Link(links)) => links @@ -902,14 +909,14 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re } pub fn handle_document_highlight( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_types::DocumentHighlightParams, ) -> Result>> { let _p = profile("handle_document_highlight"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; - let line_index = world.analysis().file_line_index(position.file_id)?; + let position = from_proto::file_position(&snap, params.text_document_position_params)?; + let line_index = snap.analysis().file_line_index(position.file_id)?; - let refs = match world + let refs = match snap .analysis() .find_all_refs(position, Some(SearchScope::single_file(position.file_id)))? { @@ -929,19 +936,19 @@ pub fn handle_document_highlight( } pub fn handle_ssr( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: lsp_ext::SsrParams, ) -> Result { let _p = profile("handle_ssr"); let source_change = - world.analysis().structural_search_replace(¶ms.query, params.parse_only)??; - to_proto::workspace_edit(&world, source_change) + snap.analysis().structural_search_replace(¶ms.query, params.parse_only)??; + to_proto::workspace_edit(&snap, source_change) } -pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result { +pub fn publish_diagnostics(snap: &GlobalStateSnapshot, file_id: FileId) -> Result { let _p = profile("publish_diagnostics"); - let line_index = world.analysis().file_line_index(file_id)?; - let diagnostics: Vec = world + let line_index = snap.analysis().file_line_index(file_id)?; + let diagnostics: Vec = snap .analysis() .diagnostics(file_id)? .into_iter() @@ -959,28 +966,28 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result Result> { let _p = profile("handle_inlay_hints"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let analysis = world.analysis(); + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let analysis = snap.analysis(); let line_index = analysis.file_line_index(file_id)?; Ok(analysis - .inlay_hints(file_id, &world.config.inlay_hints)? + .inlay_hints(file_id, &snap.config.inlay_hints)? .into_iter() .map(|it| to_proto::inlay_int(&line_index, it)) .collect()) } pub fn handle_call_hierarchy_prepare( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: CallHierarchyPrepareParams, ) -> Result>> { let _p = profile("handle_call_hierarchy_prepare"); - let position = from_proto::file_position(&world, params.text_document_position_params)?; + let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let nav_info = match world.analysis().call_hierarchy(position)? { + let nav_info = match snap.analysis().call_hierarchy(position)? { None => return Ok(None), Some(it) => it, }; @@ -989,24 +996,24 @@ pub fn handle_call_hierarchy_prepare( let res = navs .into_iter() .filter(|it| it.kind() == SyntaxKind::FN_DEF) - .map(|it| to_proto::call_hierarchy_item(&world, it)) + .map(|it| to_proto::call_hierarchy_item(&snap, it)) .collect::>>()?; Ok(Some(res)) } pub fn handle_call_hierarchy_incoming( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: CallHierarchyIncomingCallsParams, ) -> Result>> { let _p = profile("handle_call_hierarchy_incoming"); let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); - let frange = from_proto::file_range(&world, doc, item.range)?; + let frange = from_proto::file_range(&snap, doc, item.range)?; let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; - let call_items = match world.analysis().incoming_calls(fpos)? { + let call_items = match snap.analysis().incoming_calls(fpos)? { None => return Ok(None), Some(it) => it, }; @@ -1015,8 +1022,8 @@ pub fn handle_call_hierarchy_incoming( for call_item in call_items.into_iter() { let file_id = call_item.target.file_id(); - let line_index = world.analysis().file_line_index(file_id)?; - let item = to_proto::call_hierarchy_item(&world, call_item.target)?; + let line_index = snap.analysis().file_line_index(file_id)?; + let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; res.push(CallHierarchyIncomingCall { from: item, from_ranges: call_item @@ -1031,17 +1038,17 @@ pub fn handle_call_hierarchy_incoming( } pub fn handle_call_hierarchy_outgoing( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: CallHierarchyOutgoingCallsParams, ) -> Result>> { let _p = profile("handle_call_hierarchy_outgoing"); let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); - let frange = from_proto::file_range(&world, doc, item.range)?; + let frange = from_proto::file_range(&snap, doc, item.range)?; let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; - let call_items = match world.analysis().outgoing_calls(fpos)? { + let call_items = match snap.analysis().outgoing_calls(fpos)? { None => return Ok(None), Some(it) => it, }; @@ -1050,8 +1057,8 @@ pub fn handle_call_hierarchy_outgoing( for call_item in call_items.into_iter() { let file_id = call_item.target.file_id(); - let line_index = world.analysis().file_line_index(file_id)?; - let item = to_proto::call_hierarchy_item(&world, call_item.target)?; + let line_index = snap.analysis().file_line_index(file_id)?; + let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; res.push(CallHierarchyOutgoingCall { to: item, from_ranges: call_item @@ -1066,31 +1073,31 @@ pub fn handle_call_hierarchy_outgoing( } pub fn handle_semantic_tokens( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: SemanticTokensParams, ) -> Result> { let _p = profile("handle_semantic_tokens"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let text = world.analysis().file_text(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let text = snap.analysis().file_text(file_id)?; + let line_index = snap.analysis().file_line_index(file_id)?; - let highlights = world.analysis().highlight(file_id)?; + let highlights = snap.analysis().highlight(file_id)?; let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); Ok(Some(semantic_tokens.into())) } pub fn handle_semantic_tokens_range( - world: WorldSnapshot, + snap: GlobalStateSnapshot, params: SemanticTokensRangeParams, ) -> Result> { let _p = profile("handle_semantic_tokens_range"); - let frange = from_proto::file_range(&world, params.text_document, params.range)?; - let text = world.analysis().file_text(frange.file_id)?; - let line_index = world.analysis().file_line_index(frange.file_id)?; + let frange = from_proto::file_range(&snap, params.text_document, params.range)?; + let text = snap.analysis().file_text(frange.file_id)?; + let line_index = snap.analysis().file_line_index(frange.file_id)?; - let highlights = world.analysis().highlight_range(frange)?; + let highlights = snap.analysis().highlight_range(frange)?; let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); Ok(Some(semantic_tokens.into())) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 85304aa87..0915a7fcb 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -10,7 +10,8 @@ use ra_syntax::{SyntaxKind, TextRange, TextSize}; use ra_vfs::LineEndings; use crate::{ - cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, + cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, lsp_ext, + semantic_tokens, Result, }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { @@ -384,41 +385,44 @@ pub(crate) fn folding_range( } } -pub(crate) fn url(world: &WorldSnapshot, file_id: FileId) -> Result { - world.file_id_to_uri(file_id) +pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> Result { + snap.file_id_to_uri(file_id) } pub(crate) fn versioned_text_document_identifier( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, file_id: FileId, version: Option, ) -> Result { - let res = lsp_types::VersionedTextDocumentIdentifier { uri: url(world, file_id)?, version }; + let res = lsp_types::VersionedTextDocumentIdentifier { uri: url(snap, file_id)?, version }; Ok(res) } -pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result { - let url = url(world, frange.file_id)?; - let line_index = world.analysis().file_line_index(frange.file_id)?; +pub(crate) fn location( + snap: &GlobalStateSnapshot, + frange: FileRange, +) -> Result { + let url = url(snap, frange.file_id)?; + let line_index = snap.analysis().file_line_index(frange.file_id)?; let range = range(&line_index, frange.range); let loc = lsp_types::Location::new(url, range); Ok(loc) } pub(crate) fn location_link( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, src: Option, target: NavigationTarget, ) -> Result { let origin_selection_range = match src { Some(src) => { - let line_index = world.analysis().file_line_index(src.file_id)?; + let line_index = snap.analysis().file_line_index(src.file_id)?; let range = range(&line_index, src.range); Some(range) } None => None, }; - let (target_uri, target_range, target_selection_range) = location_info(world, target)?; + let (target_uri, target_range, target_selection_range) = location_info(snap, target)?; let res = lsp_types::LocationLink { origin_selection_range, target_uri, @@ -429,12 +433,12 @@ pub(crate) fn location_link( } fn location_info( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, target: NavigationTarget, ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { - let line_index = world.analysis().file_line_index(target.file_id())?; + let line_index = snap.analysis().file_line_index(target.file_id())?; - let target_uri = url(world, target.file_id())?; + let target_uri = url(snap, target.file_id())?; let target_range = range(&line_index, target.full_range()); let target_selection_range = target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range); @@ -442,14 +446,14 @@ fn location_info( } pub(crate) fn goto_definition_response( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, src: Option, targets: Vec, ) -> Result { - if world.config.client_caps.location_link { + if snap.config.client_caps.location_link { let links = targets .into_iter() - .map(|nav| location_link(world, src, nav)) + .map(|nav| location_link(snap, src, nav)) .collect::>>()?; Ok(links.into()) } else { @@ -457,7 +461,7 @@ pub(crate) fn goto_definition_response( .into_iter() .map(|nav| { location( - world, + snap, FileRange { file_id: nav.file_id(), range: nav.focus_range().unwrap_or(nav.range()), @@ -470,13 +474,13 @@ pub(crate) fn goto_definition_response( } pub(crate) fn snippet_text_document_edit( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, is_snippet: bool, source_file_edit: SourceFileEdit, ) -> Result { - let text_document = versioned_text_document_identifier(world, source_file_edit.file_id, None)?; - let line_index = world.analysis().file_line_index(source_file_edit.file_id)?; - let line_endings = world.file_line_endings(source_file_edit.file_id); + let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None)?; + let line_index = snap.analysis().file_line_index(source_file_edit.file_id)?; + let line_endings = snap.file_line_endings(source_file_edit.file_id); let edits = source_file_edit .edit .into_iter() @@ -486,17 +490,17 @@ pub(crate) fn snippet_text_document_edit( } pub(crate) fn resource_op( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, file_system_edit: FileSystemEdit, ) -> Result { let res = match file_system_edit { FileSystemEdit::CreateFile { source_root, path } => { - let uri = world.path_to_uri(source_root, &path)?; + let uri = snap.path_to_uri(source_root, &path)?; lsp_types::ResourceOp::Create(lsp_types::CreateFile { uri, options: None }) } FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => { - let old_uri = world.file_id_to_uri(src)?; - let new_uri = world.path_to_uri(dst_source_root, &dst_path)?; + let old_uri = snap.file_id_to_uri(src)?; + let new_uri = snap.path_to_uri(dst_source_root, &dst_path)?; lsp_types::ResourceOp::Rename(lsp_types::RenameFile { old_uri, new_uri, options: None }) } }; @@ -504,16 +508,16 @@ pub(crate) fn resource_op( } pub(crate) fn snippet_workspace_edit( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, source_change: SourceChange, ) -> Result { let mut document_changes: Vec = Vec::new(); for op in source_change.file_system_edits { - let op = resource_op(&world, op)?; + let op = resource_op(&snap, op)?; document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); } for edit in source_change.source_file_edits { - let edit = snippet_text_document_edit(&world, source_change.is_snippet, edit)?; + let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); } let workspace_edit = @@ -522,11 +526,11 @@ pub(crate) fn snippet_workspace_edit( } pub(crate) fn workspace_edit( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, source_change: SourceChange, ) -> Result { assert!(!source_change.is_snippet); - snippet_workspace_edit(world, source_change).map(|it| it.into()) + snippet_workspace_edit(snap, source_change).map(|it| it.into()) } impl From for lsp_types::WorkspaceEdit { @@ -565,13 +569,13 @@ impl From for lsp_types::WorkspaceEdit { } pub fn call_hierarchy_item( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, target: NavigationTarget, ) -> Result { let name = target.name().to_string(); let detail = target.description().map(|it| it.to_string()); let kind = symbol_kind(target.kind()); - let (uri, range, selection_range) = location_info(world, target)?; + let (uri, range, selection_range) = location_info(snap, target)?; Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) } @@ -619,23 +623,26 @@ fn main() { } } -pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result { +pub(crate) fn code_action( + snap: &GlobalStateSnapshot, + assist: Assist, +) -> Result { let res = lsp_ext::CodeAction { title: assist.label, - group: if world.config.client_caps.code_action_group { assist.group_label } else { None }, + group: if snap.config.client_caps.code_action_group { assist.group_label } else { None }, kind: Some(String::new()), - edit: Some(snippet_workspace_edit(world, assist.source_change)?), + edit: Some(snippet_workspace_edit(snap, assist.source_change)?), command: None, }; Ok(res) } pub(crate) fn runnable( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, file_id: FileId, runnable: Runnable, ) -> Result { - let spec = CargoTargetSpec::for_file(world, file_id)?; + let spec = CargoTargetSpec::for_file(snap, file_id)?; let target = spec.as_ref().map(|s| s.target.clone()); let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; @@ -648,14 +655,14 @@ pub(crate) fn runnable( target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) } }; - let location = location_link(world, None, runnable.nav)?; + let location = location_link(snap, None, runnable.nav)?; Ok(lsp_ext::Runnable { label, location: Some(location), kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { - workspace_root: world.workspace_root_for(file_id).map(|root| root.to_owned()), + workspace_root: snap.workspace_root_for(file_id).map(|root| root.to_owned()), cargo_args, executable_args, }, diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs deleted file mode 100644 index c1010e86a..000000000 --- a/crates/rust-analyzer/src/world.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! The context or environment in which the language server functions. In our -//! server implementation this is know as the `WorldState`. -//! -//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. - -use std::{ - path::{Path, PathBuf}, - sync::Arc, -}; - -use crossbeam_channel::{unbounded, Receiver}; -use lsp_types::Url; -use parking_lot::RwLock; -use ra_flycheck::{Flycheck, FlycheckConfig}; -use ra_ide::{ - Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, -}; -use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace}; -use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; -use relative_path::RelativePathBuf; -use stdx::format_to; - -use crate::{ - config::Config, - diagnostics::{ - to_proto::url_from_path_with_drive_lowercasing, CheckFixes, DiagnosticCollection, - }, - main_loop::pending_requests::{CompletedRequest, LatestRequests}, - vfs_glob::{Glob, RustPackageFilterBuilder}, - LspError, Result, -}; -use ra_db::ExternSourceId; -use rustc_hash::{FxHashMap, FxHashSet}; - -fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option { - // FIXME: Figure out the multi-workspace situation - workspaces - .iter() - .find_map(|w| match w { - ProjectWorkspace::Cargo { cargo, .. } => Some(cargo), - ProjectWorkspace::Json { .. } => None, - }) - .map(|cargo| { - let cargo_project_root = cargo.workspace_root().to_path_buf(); - Some(Flycheck::new(config.clone(), cargo_project_root)) - }) - .unwrap_or_else(|| { - log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); - None - }) -} - -/// `WorldState` is the primary mutable state of the language server -/// -/// The most interesting components are `vfs`, which stores a consistent -/// snapshot of the file systems, and `analysis_host`, which stores our -/// incremental salsa database. -#[derive(Debug)] -pub struct WorldState { - pub config: Config, - pub local_roots: Vec, - pub workspaces: Arc>, - pub analysis_host: AnalysisHost, - pub vfs: Arc>, - pub task_receiver: Receiver, - pub latest_requests: Arc>, - pub flycheck: Option, - pub diagnostics: DiagnosticCollection, - pub proc_macro_client: ProcMacroClient, -} - -/// An immutable snapshot of the world's state at a point in time. -pub struct WorldSnapshot { - pub config: Config, - pub workspaces: Arc>, - pub analysis: Analysis, - pub latest_requests: Arc>, - pub check_fixes: CheckFixes, - vfs: Arc>, -} - -impl WorldState { - pub fn new( - workspaces: Vec, - lru_capacity: Option, - exclude_globs: &[Glob], - watch: Watch, - config: Config, - ) -> WorldState { - let mut change = AnalysisChange::new(); - - let extern_dirs: FxHashSet<_> = - workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); - - let mut local_roots = Vec::new(); - let roots: Vec<_> = { - let create_filter = |is_member| { - RustPackageFilterBuilder::default() - .set_member(is_member) - .exclude(exclude_globs.iter().cloned()) - .into_vfs_filter() - }; - workspaces - .iter() - .flat_map(ProjectWorkspace::to_roots) - .map(|pkg_root| { - let path = pkg_root.path().to_owned(); - if pkg_root.is_member() { - local_roots.push(path.clone()); - } - RootEntry::new(path, create_filter(pkg_root.is_member())) - }) - .chain( - extern_dirs - .iter() - .map(|path| RootEntry::new(path.to_owned(), create_filter(false))), - ) - .collect() - }; - - let (task_sender, task_receiver) = unbounded(); - let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); - let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); - - let mut extern_source_roots = FxHashMap::default(); - for r in vfs_roots { - let vfs_root_path = vfs.root2path(r); - let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); - change.add_root(SourceRootId(r.0), is_local); - change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); - - // FIXME: add path2root in vfs to simpily this logic - if extern_dirs.contains(&vfs_root_path) { - extern_source_roots.insert(vfs_root_path, ExternSourceId(r.0)); - } - } - - // FIXME: Read default cfgs from config - let default_cfg_options = { - let mut opts = get_rustc_cfg_options(config.cargo.target.as_ref()); - opts.insert_atom("test".into()); - opts.insert_atom("debug_assertion".into()); - opts - }; - - let proc_macro_client = match &config.proc_macro_srv { - None => ProcMacroClient::dummy(), - Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { - Ok(it) => it, - Err(err) => { - log::error!( - "Failed to run ra_proc_macro_srv from path {}, error: {:?}", - path.display(), - err - ); - ProcMacroClient::dummy() - } - }, - }; - - // Create crate graph from all the workspaces - let mut crate_graph = CrateGraph::default(); - let mut load = |path: &Path| { - // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs - let path = path.canonicalize().ok()?; - let vfs_file = vfs.load(&path); - vfs_file.map(|f| FileId(f.0)) - }; - for ws in workspaces.iter() { - crate_graph.extend(ws.to_crate_graph( - &default_cfg_options, - &extern_source_roots, - &proc_macro_client, - &mut load, - )); - } - change.set_crate_graph(crate_graph); - - let flycheck = config.check.as_ref().and_then(|c| create_flycheck(&workspaces, c)); - - let mut analysis_host = AnalysisHost::new(lru_capacity); - analysis_host.apply_change(change); - WorldState { - config, - local_roots, - workspaces: Arc::new(workspaces), - analysis_host, - vfs: Arc::new(RwLock::new(vfs)), - task_receiver, - latest_requests: Default::default(), - flycheck, - diagnostics: Default::default(), - proc_macro_client, - } - } - - pub fn update_configuration(&mut self, config: Config) { - self.analysis_host.update_lru_capacity(config.lru_capacity); - if config.check != self.config.check { - self.flycheck = - config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it)); - } - - self.config = config; - } - - /// Returns a vec of libraries - /// FIXME: better API here - pub fn process_changes( - &mut self, - roots_scanned: &mut usize, - ) -> Option)>)>> { - let changes = self.vfs.write().commit_changes(); - if changes.is_empty() { - return None; - } - let mut libs = Vec::new(); - let mut change = AnalysisChange::new(); - for c in changes { - match c { - VfsChange::AddRoot { root, files } => { - let root_path = self.vfs.read().root2path(root); - let is_local = self.local_roots.iter().any(|r| root_path.starts_with(r)); - if is_local { - *roots_scanned += 1; - for (file, path, text) in files { - change.add_file(SourceRootId(root.0), FileId(file.0), path, text); - } - } else { - let files = files - .into_iter() - .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) - .collect(); - libs.push((SourceRootId(root.0), files)); - } - } - VfsChange::AddFile { root, file, path, text } => { - change.add_file(SourceRootId(root.0), FileId(file.0), path, text); - } - VfsChange::RemoveFile { root, file, path } => { - change.remove_file(SourceRootId(root.0), FileId(file.0), path) - } - VfsChange::ChangeFile { file, text } => { - change.change_file(FileId(file.0), text); - } - } - } - self.analysis_host.apply_change(change); - Some(libs) - } - - pub fn add_lib(&mut self, data: LibraryData) { - let mut change = AnalysisChange::new(); - change.add_library(data); - self.analysis_host.apply_change(change); - } - - pub fn snapshot(&self) -> WorldSnapshot { - WorldSnapshot { - config: self.config.clone(), - workspaces: Arc::clone(&self.workspaces), - analysis: self.analysis_host.analysis(), - vfs: Arc::clone(&self.vfs), - latest_requests: Arc::clone(&self.latest_requests), - check_fixes: Arc::clone(&self.diagnostics.check_fixes), - } - } - - pub fn maybe_collect_garbage(&mut self) { - self.analysis_host.maybe_collect_garbage() - } - - pub fn collect_garbage(&mut self) { - self.analysis_host.collect_garbage() - } - - pub fn complete_request(&mut self, request: CompletedRequest) { - self.latest_requests.write().record(request) - } -} - -impl WorldSnapshot { - pub fn analysis(&self) -> &Analysis { - &self.analysis - } - - pub fn uri_to_file_id(&self, uri: &Url) -> Result { - let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; - let file = self.vfs.read().path2file(&path).ok_or_else(|| { - // Show warning as this file is outside current workspace - // FIXME: just handle such files, and remove `LspError::UNKNOWN_FILE`. - LspError { - code: LspError::UNKNOWN_FILE, - message: "Rust file outside current workspace is not supported yet.".to_string(), - } - })?; - Ok(FileId(file.0)) - } - - pub fn file_id_to_uri(&self, id: FileId) -> Result { - let path = self.vfs.read().file2path(VfsFile(id.0)); - let url = url_from_path_with_drive_lowercasing(path)?; - - Ok(url) - } - - pub fn file_id_to_path(&self, id: FileId) -> PathBuf { - self.vfs.read().file2path(VfsFile(id.0)) - } - - pub fn file_line_endings(&self, id: FileId) -> LineEndings { - self.vfs.read().file_line_endings(VfsFile(id.0)) - } - - pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result { - let base = self.vfs.read().root2path(VfsRoot(root.0)); - let path = path.to_path(base); - let url = Url::from_file_path(&path) - .map_err(|_| format!("can't convert path to url: {}", path.display()))?; - Ok(url) - } - - pub fn status(&self) -> String { - let mut buf = String::new(); - if self.workspaces.is_empty() { - buf.push_str("no workspaces\n") - } else { - buf.push_str("workspaces:\n"); - for w in self.workspaces.iter() { - format_to!(buf, "{} packages loaded\n", w.n_packages()); - } - } - buf.push_str("\nanalysis:\n"); - buf.push_str( - &self - .analysis - .status() - .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()), - ); - buf - } - - pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> { - let path = self.vfs.read().file2path(VfsFile(file_id.0)); - self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) - } -} -- cgit v1.2.3 From 0a88de809f13f3b4abe0ffa11ff87c6f845050bd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 11:44:51 +0200 Subject: Move project discovery --- crates/ra_project_model/src/lib.rs | 16 ++++++++++++++-- crates/rust-analyzer/src/main_loop.rs | 8 ++------ 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 9b30bef8d..d5f82f17a 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -14,7 +14,7 @@ use std::{ use anyhow::{bail, Context, Result}; use ra_cfg::CfgOptions; use ra_db::{CrateGraph, CrateName, Edition, Env, ExternSource, ExternSourceId, FileId}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use serde_json::from_reader; pub use crate::{ @@ -57,7 +57,7 @@ impl PackageRoot { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ProjectRoot { ProjectJson(PathBuf), CargoToml(PathBuf), @@ -128,6 +128,18 @@ impl ProjectRoot { .collect() } } + + pub fn discover_all(paths: &[impl AsRef]) -> Vec { + let mut res = paths + .iter() + .filter_map(|it| ProjectRoot::discover(it.as_ref()).ok()) + .flatten() + .collect::>() + .into_iter() + .collect::>(); + res.sort(); + res + } } impl ProjectWorkspace { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 35f2d7001..82348c6fc 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -28,7 +28,7 @@ use lsp_types::{ use ra_flycheck::{CheckTask, Status}; use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; use ra_prof::profile; -use ra_project_model::{PackageRoot, ProjectWorkspace}; +use ra_project_model::{PackageRoot, ProjectRoot, ProjectWorkspace}; use ra_vfs::{VfsFile, VfsTask, Watch}; use relative_path::RelativePathBuf; use rustc_hash::FxHashSet; @@ -96,11 +96,7 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) let mut global_state = { let workspaces = { // FIXME: support dynamic workspace loading. - let project_roots: FxHashSet<_> = ws_roots - .iter() - .filter_map(|it| ra_project_model::ProjectRoot::discover(it).ok()) - .flatten() - .collect(); + let project_roots = ProjectRoot::discover_all(&ws_roots); if project_roots.is_empty() && config.notifications.cargo_toml_not_found { show_message( -- cgit v1.2.3 From 03a76191a18b450a8e4ae309296fd7c0614d14d2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 12:05:50 +0200 Subject: Rename ProjectRoot -> ProjectManifest --- crates/ra_project_model/src/lib.rs | 30 +++++++++++++++--------------- crates/rust-analyzer/src/cli/load_cargo.rs | 4 ++-- crates/rust-analyzer/src/main_loop.rs | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index d5f82f17a..a99612690 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -58,24 +58,24 @@ impl PackageRoot { } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum ProjectRoot { +pub enum ProjectManifest { ProjectJson(PathBuf), CargoToml(PathBuf), } -impl ProjectRoot { - pub fn from_manifest_file(path: PathBuf) -> Result { +impl ProjectManifest { + pub fn from_manifest_file(path: PathBuf) -> Result { if path.ends_with("rust-project.json") { - return Ok(ProjectRoot::ProjectJson(path)); + return Ok(ProjectManifest::ProjectJson(path)); } if path.ends_with("Cargo.toml") { - return Ok(ProjectRoot::CargoToml(path)); + return Ok(ProjectManifest::CargoToml(path)); } bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) } - pub fn discover_single(path: &Path) -> Result { - let mut candidates = ProjectRoot::discover(path)?; + pub fn discover_single(path: &Path) -> Result { + let mut candidates = ProjectManifest::discover(path)?; let res = match candidates.pop() { None => bail!("no projects"), Some(it) => it, @@ -87,12 +87,12 @@ impl ProjectRoot { Ok(res) } - pub fn discover(path: &Path) -> io::Result> { + pub fn discover(path: &Path) -> io::Result> { if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { - return Ok(vec![ProjectRoot::ProjectJson(project_json)]); + return Ok(vec![ProjectManifest::ProjectJson(project_json)]); } return find_cargo_toml(path) - .map(|paths| paths.into_iter().map(ProjectRoot::CargoToml).collect()); + .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); fn find_cargo_toml(path: &Path) -> io::Result> { match find_in_parent_dirs(path, "Cargo.toml") { @@ -129,10 +129,10 @@ impl ProjectRoot { } } - pub fn discover_all(paths: &[impl AsRef]) -> Vec { + pub fn discover_all(paths: &[impl AsRef]) -> Vec { let mut res = paths .iter() - .filter_map(|it| ProjectRoot::discover(it.as_ref()).ok()) + .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) .flatten() .collect::>() .into_iter() @@ -144,12 +144,12 @@ impl ProjectRoot { impl ProjectWorkspace { pub fn load( - root: ProjectRoot, + root: ProjectManifest, cargo_features: &CargoConfig, with_sysroot: bool, ) -> Result { let res = match root { - ProjectRoot::ProjectJson(project_json) => { + ProjectManifest::ProjectJson(project_json) => { let file = File::open(&project_json).with_context(|| { format!("Failed to open json file {}", project_json.display()) })?; @@ -160,7 +160,7 @@ impl ProjectWorkspace { })?, } } - ProjectRoot::CargoToml(cargo_toml) => { + ProjectManifest::CargoToml(cargo_toml) => { let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) .with_context(|| { format!( diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 8eaf75ff6..67491b42a 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -8,7 +8,7 @@ use crossbeam_channel::{unbounded, Receiver}; use ra_db::{ExternSourceId, FileId, SourceRootId}; use ra_ide::{AnalysisChange, AnalysisHost}; use ra_project_model::{ - get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectRoot, ProjectWorkspace, + get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, }; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -28,7 +28,7 @@ pub fn load_cargo( with_proc_macro: bool, ) -> Result<(AnalysisHost, FxHashMap)> { let root = std::env::current_dir()?.join(root); - let root = ProjectRoot::discover_single(&root)?; + let root = ProjectManifest::discover_single(&root)?; let ws = ProjectWorkspace::load( root, &CargoConfig { load_out_dirs_from_check, ..Default::default() }, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 82348c6fc..ea5b4c91c 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -28,7 +28,7 @@ use lsp_types::{ use ra_flycheck::{CheckTask, Status}; use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; use ra_prof::profile; -use ra_project_model::{PackageRoot, ProjectRoot, ProjectWorkspace}; +use ra_project_model::{PackageRoot, ProjectManifest, ProjectWorkspace}; use ra_vfs::{VfsFile, VfsTask, Watch}; use relative_path::RelativePathBuf; use rustc_hash::FxHashSet; @@ -96,7 +96,7 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) let mut global_state = { let workspaces = { // FIXME: support dynamic workspace loading. - let project_roots = ProjectRoot::discover_all(&ws_roots); + let project_roots = ProjectManifest::discover_all(&ws_roots); if project_roots.is_empty() && config.notifications.cargo_toml_not_found { show_message( -- cgit v1.2.3 From 8baa4c5d07690dc908b6299471c936c0d87ad871 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 12:22:01 +0200 Subject: Groundwork for specifying the set of projects via config --- crates/rust-analyzer/src/bin/main.rs | 41 ++++++++++++++++------- crates/rust-analyzer/src/cli/load_cargo.rs | 3 +- crates/rust-analyzer/src/config.rs | 25 ++++++++++++-- crates/rust-analyzer/src/main_loop.rs | 29 +++++++--------- crates/rust-analyzer/tests/heavy_tests/support.rs | 31 +++++++++-------- 5 files changed, 83 insertions(+), 46 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index e82fd57de..8d071ab1c 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -4,9 +4,14 @@ mod args; use lsp_server::Connection; -use rust_analyzer::{cli, config::Config, from_json, Result}; +use rust_analyzer::{ + cli, + config::{Config, LinkedProject}, + from_json, Result, +}; use crate::args::HelpPrinted; +use ra_project_model::ProjectManifest; fn main() -> Result<()> { setup_logging()?; @@ -97,17 +102,6 @@ fn run_server() -> Result<()> { log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); } - let cwd = std::env::current_dir()?; - let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); - - let workspace_roots = initialize_params - .workspace_folders - .map(|workspaces| { - workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::>() - }) - .filter(|workspaces| !workspaces.is_empty()) - .unwrap_or_else(|| vec![root]); - let config = { let mut config = Config::default(); if let Some(value) = &initialize_params.initialization_options { @@ -115,10 +109,31 @@ fn run_server() -> Result<()> { } config.update_caps(&initialize_params.capabilities); + if config.linked_projects.is_empty() { + let cwd = std::env::current_dir()?; + let root = + initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); + let workspace_roots = initialize_params + .workspace_folders + .map(|workspaces| { + workspaces + .into_iter() + .filter_map(|it| it.uri.to_file_path().ok()) + .collect::>() + }) + .filter(|workspaces| !workspaces.is_empty()) + .unwrap_or_else(|| vec![root]); + + config.linked_projects = ProjectManifest::discover_all(&workspace_roots) + .into_iter() + .map(LinkedProject::from) + .collect(); + } + config }; - rust_analyzer::main_loop(workspace_roots, config, connection)?; + rust_analyzer::main_loop(config, connection)?; log::info!("shutting down IO..."); io_threads.join()?; diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 67491b42a..c7e86fe0c 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -8,7 +8,8 @@ use crossbeam_channel::{unbounded, Receiver}; use ra_db::{ExternSourceId, FileId, SourceRootId}; use ra_ide::{AnalysisChange, AnalysisHost}; use ra_project_model::{ - get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, + get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, + ProjectWorkspace, }; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use rustc_hash::{FxHashMap, FxHashSet}; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9c6e369d2..761bc9c2d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -12,14 +12,13 @@ use std::{ffi::OsString, path::PathBuf}; use lsp_types::ClientCapabilities; use ra_flycheck::FlycheckConfig; use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; -use ra_project_model::CargoConfig; +use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; use serde::Deserialize; #[derive(Debug, Clone)] pub struct Config { pub client_caps: ClientCapsConfig, - pub with_sysroot: bool, pub publish_diagnostics: bool, pub lru_capacity: Option, pub proc_macro_srv: Option<(PathBuf, Vec)>, @@ -35,6 +34,27 @@ pub struct Config { pub assist: AssistConfig, pub call_info_full: bool, pub lens: LensConfig, + + pub with_sysroot: bool, + pub linked_projects: Vec, +} + +#[derive(Debug, Clone)] +pub enum LinkedProject { + ProjectManifest(ProjectManifest), + JsonProject(JsonProject), +} + +impl From for LinkedProject { + fn from(v: ProjectManifest) -> Self { + LinkedProject::ProjectManifest(v) + } +} + +impl From for LinkedProject { + fn from(v: JsonProject) -> Self { + LinkedProject::JsonProject(v) + } } #[derive(Clone, Debug, PartialEq, Eq)] @@ -141,6 +161,7 @@ impl Default for Config { assist: AssistConfig::default(), call_info_full: true, lens: LensConfig::default(), + linked_projects: Vec::new(), } } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ea5b4c91c..d901f21d7 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -12,13 +12,11 @@ use std::{ fmt, ops::Range, panic, - path::PathBuf, sync::Arc, time::{Duration, Instant}, }; use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; -use itertools::Itertools; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; use lsp_types::{ DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, @@ -28,7 +26,7 @@ use lsp_types::{ use ra_flycheck::{CheckTask, Status}; use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; use ra_prof::profile; -use ra_project_model::{PackageRoot, ProjectManifest, ProjectWorkspace}; +use ra_project_model::{PackageRoot, ProjectWorkspace}; use ra_vfs::{VfsFile, VfsTask, Watch}; use relative_path::RelativePathBuf; use rustc_hash::FxHashSet; @@ -36,7 +34,7 @@ use serde::{de::DeserializeOwned, Serialize}; use threadpool::ThreadPool; use crate::{ - config::{Config, FilesWatcher}, + config::{Config, FilesWatcher, LinkedProject}, diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, from_proto, global_state::{GlobalState, GlobalStateSnapshot}, @@ -70,7 +68,7 @@ impl fmt::Display for LspError { impl Error for LspError {} -pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) -> Result<()> { +pub fn main_loop(config: Config, connection: Connection) -> Result<()> { log::info!("initial config: {:#?}", config); // Windows scheduler implements priority boosts: if thread waits for an @@ -95,25 +93,24 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) let mut loop_state = LoopState::default(); let mut global_state = { let workspaces = { - // FIXME: support dynamic workspace loading. - let project_roots = ProjectManifest::discover_all(&ws_roots); - - if project_roots.is_empty() && config.notifications.cargo_toml_not_found { + if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found { show_message( lsp_types::MessageType::Error, - format!( - "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}", - ws_roots.iter().format_with(", ", |it, f| f(&it.display())) - ), + "rust-analyzer failed to discover workspace".to_string(), &connection.sender, ); }; - project_roots - .into_iter() + config + .linked_projects + .iter() + .filter_map(|project| match project { + LinkedProject::ProjectManifest(it) => Some(it), + LinkedProject::JsonProject(_) => None, + }) .filter_map(|root| { ra_project_model::ProjectWorkspace::load( - root, + root.clone(), &config.cargo, config.with_sysroot, ) diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index 66a6f4d54..30d03b622 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -19,8 +19,9 @@ use serde_json::{to_string_pretty, Value}; use tempfile::TempDir; use test_utils::{find_mismatch, parse_fixture}; +use ra_project_model::ProjectManifest; use rust_analyzer::{ - config::{ClientCapsConfig, Config}, + config::{ClientCapsConfig, Config, LinkedProject}, main_loop, }; @@ -42,7 +43,7 @@ impl<'a> Project<'a> { self } - pub fn root(mut self, path: &str) -> Project<'a> { + pub(crate) fn root(mut self, path: &str) -> Project<'a> { self.roots.push(path.into()); self } @@ -74,7 +75,16 @@ impl<'a> Project<'a> { paths.push((path, entry.text)); } - let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); + let mut roots = + self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::>(); + if roots.is_empty() { + roots.push(tmp_dir.path().to_path_buf()); + } + let linked_projects = roots + .into_iter() + .map(|it| ProjectManifest::discover_single(&it).unwrap()) + .map(LinkedProject::from) + .collect::>(); let mut config = Config { client_caps: ClientCapsConfig { @@ -84,6 +94,7 @@ impl<'a> Project<'a> { ..Default::default() }, with_sysroot: self.with_sysroot, + linked_projects, ..Config::default() }; @@ -91,7 +102,7 @@ impl<'a> Project<'a> { f(&mut config) } - Server::new(tmp_dir, config, roots, paths) + Server::new(tmp_dir, config, paths) } } @@ -109,20 +120,12 @@ pub struct Server { } impl Server { - fn new( - dir: TempDir, - config: Config, - roots: Vec, - files: Vec<(PathBuf, String)>, - ) -> Server { - let path = dir.path().to_path_buf(); - - let roots = if roots.is_empty() { vec![path] } else { roots }; + fn new(dir: TempDir, config: Config, files: Vec<(PathBuf, String)>) -> Server { let (connection, client) = Connection::memory(); let _thread = jod_thread::Builder::new() .name("test server".to_string()) - .spawn(move || main_loop(roots, config, connection).unwrap()) + .spawn(move || main_loop(config, connection).unwrap()) .expect("failed to spawn a thread"); let res = -- cgit v1.2.3 From 2e7d12d2f3ccfd1ef9946d1212e2455e5937c521 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 12:39:11 +0200 Subject: Drop test for old format --- crates/rust-analyzer/tests/heavy_tests/main.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 69dc719c5..c1805787a 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -331,8 +331,6 @@ fn test_missing_module_code_action_in_json_project() { "deps": [], "edition": "2015", "cfg": [ "cfg_atom_1", "feature=cfg_1"], - "atom_cfgs": ["atom_2"], - "key_value_cfgs": { "feature": "key_value_feature", "other": "value"} } ] }); -- cgit v1.2.3 From 4c655c01f31ceffae4f8219f9706992e0e7f188a Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sat, 30 May 2020 14:21:06 -0400 Subject: Enable hover and autocomplete docs on macro generated items --- crates/ra_hir_def/src/attr.rs | 8 +++++- crates/ra_hir_def/src/docs.rs | 43 +++++++++++++++++++++++++++-- crates/ra_hir_expand/src/name.rs | 1 + crates/ra_ide/src/hover.rs | 55 ++++++++++++++++++++++++++++++++++---- crates/ra_syntax/src/ast/traits.rs | 13 +++++++-- 5 files changed, 110 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 8b6c0bede..2eeba0572 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -87,12 +87,18 @@ impl Attrs { } pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { + let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map( + |docs_text| Attr { + input: Some(AttrInput::Literal(SmolStr::new(docs_text))), + path: ModPath::from(hir_expand::name!(doc)), + }, + ); let mut attrs = owner.attrs().peekable(); let entries = if attrs.peek().is_none() { // Avoid heap allocation None } else { - Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect()) + Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect()) }; Attrs { entries } } diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index b221ae1ce..74b9f8199 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs @@ -70,6 +70,45 @@ impl Documentation { } } -pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option { - node.doc_comment_text().map(|it| Documentation::new(&it)) +pub(crate) fn docs_from_ast(node: &N) -> Option +where + N: ast::DocCommentsOwner + ast::AttrsOwner, +{ + let doc_comment_text = node.doc_comment_text(); + let doc_attr_text = expand_doc_attrs(node); + let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + docs.map(|it| Documentation::new(&it)) +} + +fn merge_doc_comments_and_attrs( + doc_comment_text: Option, + doc_attr_text: Option, +) -> Option { + match (doc_comment_text, doc_attr_text) { + (Some(mut comment_text), Some(attr_text)) => { + comment_text.push_str("\n\n"); + comment_text.push_str(&attr_text); + Some(comment_text) + } + (Some(comment_text), None) => Some(comment_text), + (None, Some(attr_text)) => Some(attr_text), + (None, None) => None, + } +} + +fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option { + let mut docs = String::new(); + for attr in owner.attrs() { + if let Some(("doc", value)) = + attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) + { + docs.push_str(value); + docs.push_str("\n\n"); + } + } + if docs.is_empty() { + None + } else { + Some(docs) + } } diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index ea495cb11..660bdfe33 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs @@ -153,6 +153,7 @@ pub mod known { str, // Special names macro_rules, + doc, // Components of known path (value or mod name) std, core, diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index d96cb5596..e25a7dacf 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -169,13 +169,19 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option { let src = it.source(db); - hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) + let doc_comment_text = src.value.doc_comment_text(); + let doc_attr_text = expand_doc_attrs(&src.value); + let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + hover_text(docs, Some(macro_label(&src.value)), mod_path) } Definition::Field(it) => { let src = it.source(db); match src.value { FieldSource::Named(it) => { - hover_text(it.doc_comment_text(), it.short_label(), mod_path) + let doc_comment_text = it.doc_comment_text(); + let doc_attr_text = expand_doc_attrs(&it); + let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + hover_text(docs, it.short_label(), mod_path) } _ => None, } @@ -183,7 +189,10 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option match it { ModuleDef::Module(it) => match it.definition_source(db).value { ModuleSource::Module(it) => { - hover_text(it.doc_comment_text(), it.short_label(), mod_path) + let doc_comment_text = it.doc_comment_text(); + let doc_attr_text = expand_doc_attrs(&it); + let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + hover_text(docs, it.short_label(), mod_path) } _ => None, }, @@ -208,10 +217,46 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option(db: &RootDatabase, def: D, mod_path: Option) -> Option where D: HasSource, - A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, + A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, { let src = def.source(db); - hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) + let doc_comment_text = src.value.doc_comment_text(); + let doc_attr_text = expand_doc_attrs(&src.value); + let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + hover_text(docs, src.value.short_label(), mod_path) + } +} + +fn merge_doc_comments_and_attrs( + doc_comment_text: Option, + doc_attr_text: Option, +) -> Option { + match (doc_comment_text, doc_attr_text) { + (Some(mut comment_text), Some(attr_text)) => { + comment_text.push_str("\n\n"); + comment_text.push_str(&attr_text); + Some(comment_text) + } + (Some(comment_text), None) => Some(comment_text), + (None, Some(attr_text)) => Some(attr_text), + (None, None) => None, + } +} + +fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option { + let mut docs = String::new(); + for attr in owner.attrs() { + if let Some(("doc", value)) = + attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) + { + docs.push_str(value); + docs.push_str("\n\n"); + } + } + if docs.is_empty() { + None + } else { + Some(docs) } } diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index bfc05e08b..a8f2454fd 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs @@ -83,13 +83,22 @@ pub trait DocCommentsOwner: AstNode { CommentIter { iter: self.syntax().children_with_tokens() } } + fn doc_comment_text(&self) -> Option { + self.doc_comments().doc_comment_text() + } +} + +impl CommentIter { + pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> CommentIter { + CommentIter { iter: syntax_node.children_with_tokens() } + } + /// Returns the textual content of a doc comment block as a single string. /// That is, strips leading `///` (+ optional 1 character of whitespace), /// trailing `*/`, trailing whitespace and then joins the lines. - fn doc_comment_text(&self) -> Option { + pub fn doc_comment_text(self) -> Option { let mut has_comments = false; let docs = self - .doc_comments() .filter(|comment| comment.kind().doc.is_some()) .map(|comment| { has_comments = true; -- cgit v1.2.3 From 5837acce532e0cd65a1c0cb8c03cc18a4c22f327 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 31 May 2020 11:33:48 -0400 Subject: Add basic hover and completion doc tests for macro generated items --- crates/ra_hir_def/src/docs.rs | 2 +- crates/ra_ide/src/completion.rs | 78 ++++++++++++++++++++++++++++++ crates/ra_ide/src/hover.rs | 104 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 182 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index 74b9f8199..ab43cd3d3 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs @@ -109,6 +109,6 @@ fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option { if docs.is_empty() { None } else { - Some(docs) + Some(docs.trim_end_matches("\n\n").to_owned()) } } diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index d890b69d2..a721e23c6 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -125,3 +125,81 @@ pub(crate) fn completions( Some(acc) } + +#[cfg(test)] +mod tests { + use crate::completion::completion_config::CompletionConfig; + use crate::mock_analysis::analysis_and_position; + + struct DetailAndDocumentation<'a> { + detail: &'a str, + documentation: &'a str, + } + + fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { + let (analysis, position) = analysis_and_position(fixture); + let config = CompletionConfig::default(); + let completions = analysis.completions(&config, position).unwrap().unwrap(); + for item in completions { + if item.detail() == Some(expected.detail) { + let opt = item.documentation(); + let doc = opt.as_ref().map(|it| it.as_str()); + assert_eq!(doc, Some(expected.documentation)); + return; + } + } + panic!("completion detail not found: {}", expected.detail) + } + + #[test] + fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { + check_detail_and_documentation( + r#" + //- /lib.rs + macro_rules! bar { + () => { + struct Bar; + impl Bar { + #[doc = "Do the foo"] + fn foo(&self) {} + } + } + } + + bar!(); + + fn foo() { + let bar = Bar; + bar.fo<|>; + } + "#, + DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, + ); + } + + #[test] + fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { + check_detail_and_documentation( + r#" + //- /lib.rs + macro_rules! bar { + () => { + struct Bar; + impl Bar { + /// Do the foo + fn foo(&self) {} + } + } + } + + bar!(); + + fn foo() { + let bar = Bar; + bar.fo<|>; + } + "#, + DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, + ); + } +} diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index e25a7dacf..731fc3673 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -256,7 +256,7 @@ fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option { if docs.is_empty() { None } else { - Some(docs) + Some(docs.trim_end_matches("\n\n").to_owned()) } } @@ -996,4 +996,106 @@ fn func(foo: i32) { if true { <|>foo; }; } &["mod my"], ); } + + #[test] + fn test_hover_struct_doc_comment() { + check_hover_result( + r#" + //- /lib.rs + /// bar docs + struct Bar; + + fn foo() { + let bar = Ba<|>r; + } + "#, + &["struct Bar\n```\n___\n\nbar docs"], + ); + } + + #[test] + fn test_hover_struct_doc_attr() { + check_hover_result( + r#" + //- /lib.rs + #[doc = "bar docs"] + struct Bar; + + fn foo() { + let bar = Ba<|>r; + } + "#, + &["struct Bar\n```\n___\n\nbar docs"], + ); + } + + #[test] + fn test_hover_struct_doc_attr_multiple_and_mixed() { + check_hover_result( + r#" + //- /lib.rs + /// bar docs 0 + #[doc = "bar docs 1"] + #[doc = "bar docs 2"] + struct Bar; + + fn foo() { + let bar = Ba<|>r; + } + "#, + &["struct Bar\n```\n___\n\nbar docs 0\n\nbar docs 1\n\nbar docs 2"], + ); + } + + #[test] + fn test_hover_macro_generated_struct_fn_doc_comment() { + check_hover_result( + r#" + //- /lib.rs + macro_rules! bar { + () => { + struct Bar; + impl Bar { + /// Do the foo + fn foo(&self) {} + } + } + } + + bar!(); + + fn foo() { + let bar = Bar; + bar.fo<|>o(); + } + "#, + &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\n Do the foo"], + ); + } + + #[test] + fn test_hover_macro_generated_struct_fn_doc_attr() { + check_hover_result( + r#" + //- /lib.rs + macro_rules! bar { + () => { + struct Bar; + impl Bar { + #[doc = "Do the foo"] + fn foo(&self) {} + } + } + } + + bar!(); + + fn foo() { + let bar = Bar; + bar.fo<|>o(); + } + "#, + &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], + ); + } } -- cgit v1.2.3 From 85c4edb0afbc7cc855c434e5e7ec69aa469e0c4b Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Wed, 3 Jun 2020 06:14:56 -0400 Subject: Consolidate documentation expansion and merging Removes the duplicated `expand_doc_attrs` and `merge_doc_comments_and_attrs` functions from `ra_ide` and exposes the same functionality via `ra_hir::Documentation::from_ast`. --- crates/ra_hir_def/src/docs.rs | 7 +++++ crates/ra_ide/src/hover.rs | 60 +++++-------------------------------------- 2 files changed, 14 insertions(+), 53 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index ab43cd3d3..2630b3d89 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs @@ -29,6 +29,13 @@ impl Documentation { Documentation(s.into()) } + pub fn from_ast(node: &N) -> Option + where + N: ast::DocCommentsOwner + ast::AttrsOwner, + { + docs_from_ast(node) + } + pub fn as_str(&self) -> &str { &*self.0 } diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 731fc3673..9636cd0d6 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1,8 +1,8 @@ use std::iter::once; use hir::{ - Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, - ModuleSource, Semantics, + Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, + ModuleDef, ModuleSource, Semantics, }; use itertools::Itertools; use ra_db::SourceDatabase; @@ -10,12 +10,7 @@ use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition}, RootDatabase, }; -use ra_syntax::{ - ast::{self, DocCommentsOwner}, - match_ast, AstNode, - SyntaxKind::*, - SyntaxToken, TokenAtOffset, -}; +use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; use crate::{ display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, @@ -169,18 +164,14 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option { let src = it.source(db); - let doc_comment_text = src.value.doc_comment_text(); - let doc_attr_text = expand_doc_attrs(&src.value); - let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + let docs = Documentation::from_ast(&src.value).map(Into::into); hover_text(docs, Some(macro_label(&src.value)), mod_path) } Definition::Field(it) => { let src = it.source(db); match src.value { FieldSource::Named(it) => { - let doc_comment_text = it.doc_comment_text(); - let doc_attr_text = expand_doc_attrs(&it); - let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + let docs = Documentation::from_ast(&it).map(Into::into); hover_text(docs, it.short_label(), mod_path) } _ => None, @@ -189,9 +180,7 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option match it { ModuleDef::Module(it) => match it.definition_source(db).value { ModuleSource::Module(it) => { - let doc_comment_text = it.doc_comment_text(); - let doc_attr_text = expand_doc_attrs(&it); - let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); + let docs = Documentation::from_ast(&it).map(Into::into); hover_text(docs, it.short_label(), mod_path) } _ => None, @@ -220,46 +209,11 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option, - doc_attr_text: Option, -) -> Option { - match (doc_comment_text, doc_attr_text) { - (Some(mut comment_text), Some(attr_text)) => { - comment_text.push_str("\n\n"); - comment_text.push_str(&attr_text); - Some(comment_text) - } - (Some(comment_text), None) => Some(comment_text), - (None, Some(attr_text)) => Some(attr_text), - (None, None) => None, - } -} - -fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option { - let mut docs = String::new(); - for attr in owner.attrs() { - if let Some(("doc", value)) = - attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) - { - docs.push_str(value); - docs.push_str("\n\n"); - } - } - if docs.is_empty() { - None - } else { - Some(docs.trim_end_matches("\n\n").to_owned()) - } -} - fn pick_best(tokens: TokenAtOffset) -> Option { return tokens.max_by_key(priority); fn priority(n: &SyntaxToken) -> usize { -- cgit v1.2.3 From f06b2bcd91329fb795839a4eabd8f43aa472aeb2 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Wed, 3 Jun 2020 07:26:15 -0400 Subject: Use split1 when formatting function signature params --- crates/ra_ide/src/display/function_signature.rs | 8 +++----- crates/stdx/src/lib.rs | 5 +++++ crates/test_utils/Cargo.toml | 3 ++- crates/test_utils/src/lib.rs | 6 +----- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index b081ecaad..ca8a6a650 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs @@ -10,7 +10,7 @@ use std::{ use hir::{Docs, Documentation, HasSource, HirDisplay}; use ra_ide_db::RootDatabase; use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; -use stdx::SepBy; +use stdx::{split1, SepBy}; use crate::display::{generic_parameters, where_predicates}; @@ -210,10 +210,8 @@ impl From<&'_ ast::FnDef> for FunctionSignature { // macro-generated functions are missing whitespace fn fmt_param(param: ast::Param) -> String { let text = param.syntax().text().to_string(); - match text.find(':') { - Some(pos) if 1 + pos < text.len() => { - format!("{} {}", &text[0..1 + pos].trim(), &text[1 + pos..].trim()) - } + match split1(&text, ':') { + Some((left, right)) => format!("{}: {}", left.trim(), right.trim()), _ => text, } } diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 71a57fba2..c0356344c 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -124,3 +124,8 @@ pub fn replace(buf: &mut String, from: char, to: &str) { // FIXME: do this in place. *buf = buf.replace(from, to) } + +pub fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { + let idx = haystack.find(delim)?; + Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) +} diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 4d185b01c..8840bf36a 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml @@ -14,4 +14,5 @@ serde_json = "1.0.48" relative-path = "1.0.0" rustc-hash = "1.1.0" -ra_cfg = { path = "../ra_cfg" } \ No newline at end of file +ra_cfg = { path = "../ra_cfg" } +stdx = { path = "../stdx" } \ No newline at end of file diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 1bd97215c..2141bfc20 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -15,6 +15,7 @@ use std::{ }; pub use ra_cfg::CfgOptions; +use stdx::split1; pub use relative_path::{RelativePath, RelativePathBuf}; pub use rustc_hash::FxHashMap; @@ -332,11 +333,6 @@ fn parse_meta(meta: &str) -> FixtureMeta { FixtureMeta::File(FileMeta { path, crate_name: krate, deps, edition, cfg, env }) } -fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { - let idx = haystack.find(delim)?; - Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) -} - /// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines. /// This allows fixtures to start off in a different indentation, e.g. to align the first line with /// the other lines visually: -- cgit v1.2.3 From fa019c8f562326a720d2ef9165626c4c5703f67b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 14:48:38 +0200 Subject: Document rust-project.json --- crates/ra_project_model/src/lib.rs | 10 ++++++++-- crates/rust-analyzer/src/config.rs | 23 +++++++++++++++++++++++ crates/rust-analyzer/src/main_loop.rs | 35 +++++++++++++++++------------------ 3 files changed, 48 insertions(+), 20 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index a99612690..7ad941279 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -32,6 +32,12 @@ pub enum ProjectWorkspace { Json { project: JsonProject }, } +impl From for ProjectWorkspace { + fn from(project: JsonProject) -> ProjectWorkspace { + ProjectWorkspace::Json { project } + } +} + /// `PackageRoot` describes a package root folder. /// Which may be an external dependency, or a member of /// the current workspace. @@ -144,11 +150,11 @@ impl ProjectManifest { impl ProjectWorkspace { pub fn load( - root: ProjectManifest, + manifest: ProjectManifest, cargo_features: &CargoConfig, with_sysroot: bool, ) -> Result { - let res = match root { + let res = match manifest { ProjectManifest::ProjectJson(project_json) => { let file = File::open(&project_json).with_context(|| { format!("Failed to open json file {}", project_json.display()) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 761bc9c2d..0e5dc56fd 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -261,6 +261,22 @@ impl Config { self.lens = LensConfig::NO_LENS; } + if let Some(linked_projects) = get::>(value, "/linkedProjects") { + if !linked_projects.is_empty() { + self.linked_projects.clear(); + for linked_project in linked_projects { + let linked_project = match linked_project { + ManifestOrJsonProject::Manifest(it) => match ProjectManifest::from_manifest_file(it) { + Ok(it) => it.into(), + Err(_) => continue, + } + ManifestOrJsonProject::JsonProject(it) => it.into(), + }; + self.linked_projects.push(linked_project); + } + } + } + log::info!("Config::update() = {:#?}", self); fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option { @@ -324,3 +340,10 @@ impl Config { } } } + +#[derive(Deserialize)] +#[serde(untagged)] +enum ManifestOrJsonProject { + Manifest(PathBuf), + JsonProject(JsonProject), +} diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index d901f21d7..1f8f6b978 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -105,24 +105,23 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> { .linked_projects .iter() .filter_map(|project| match project { - LinkedProject::ProjectManifest(it) => Some(it), - LinkedProject::JsonProject(_) => None, - }) - .filter_map(|root| { - ra_project_model::ProjectWorkspace::load( - root.clone(), - &config.cargo, - config.with_sysroot, - ) - .map_err(|err| { - log::error!("failed to load workspace: {:#}", err); - show_message( - lsp_types::MessageType::Error, - format!("rust-analyzer failed to load workspace: {:#}", err), - &connection.sender, - ); - }) - .ok() + LinkedProject::ProjectManifest(manifest) => { + ra_project_model::ProjectWorkspace::load( + manifest.clone(), + &config.cargo, + config.with_sysroot, + ) + .map_err(|err| { + log::error!("failed to load workspace: {:#}", err); + show_message( + lsp_types::MessageType::Error, + format!("rust-analyzer failed to load workspace: {:#}", err), + &connection.sender, + ); + }) + .ok() + } + LinkedProject::JsonProject(it) => Some(it.clone().into()), }) .collect::>() }; -- cgit v1.2.3 From 9e71fc0314a2555eda446a64057df7e8f78fb7c9 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 17 May 2020 21:03:40 -0400 Subject: Mark fixes from diagnostics as quick fixes --- crates/rust-analyzer/src/main_loop/handlers.rs | 9 +++++++-- crates/rust-analyzer/tests/heavy_tests/main.rs | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 1bb8e4473..c2a5bf4d6 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -730,8 +730,13 @@ pub fn handle_code_action( for fix in fixes_from_diagnostics { let title = fix.label; let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; - let action = - lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; + let action = lsp_ext::CodeAction { + title, + group: None, + kind: Some(lsp_types::code_action_kind::QUICKFIX.into()), + edit: Some(edit), + command: None, + }; res.push(action); } diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index c1805787a..ad3476310 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -298,6 +298,7 @@ fn main() {} } ] }, + "kind": "quickfix", "title": "Create module" }]), ); @@ -368,6 +369,7 @@ fn main() {{}} } ] }, + "kind": "quickfix", "title": "Create module" }]), ); -- cgit v1.2.3 From bacd0428fa0fd744eb0aac6d5d7abd18c6c707b7 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Wed, 3 Jun 2020 18:39:01 +0200 Subject: Fix review comments --- crates/rust-analyzer/src/lsp_ext.rs | 1 - crates/rust-analyzer/src/main_loop/handlers.rs | 27 ++++++++++---------- crates/rust-analyzer/src/to_proto.rs | 34 +++++++++----------------- 3 files changed, 24 insertions(+), 38 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 4b436c301..3b957534d 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -111,7 +111,6 @@ impl Request for ResolveCodeActionRequest { pub struct ResolveCodeActionParams { pub code_action_params: lsp_types::CodeActionParams, pub id: String, - pub label: String, } pub enum OnEnter {} diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 3c4064441..fab82ff7e 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -756,9 +756,13 @@ pub fn handle_code_action( handle_fixes(&world, ¶ms, &mut res)?; if world.config.client_caps.resolve_code_action { - for assist in world.analysis().unresolved_assists(&world.config.assist, frange)?.into_iter() + for (index, assist) in world + .analysis() + .unresolved_assists(&world.config.assist, frange)? + .into_iter() + .enumerate() { - res.push(to_proto::unresolved_code_action(&world, assist)?); + res.push(to_proto::unresolved_code_action(&world, assist, index)?); } } else { for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { @@ -773,24 +777,19 @@ pub fn handle_resolve_code_action( world: WorldSnapshot, params: lsp_ext::ResolveCodeActionParams, ) -> Result> { - if !world.config.client_caps.resolve_code_action { - return Ok(None); - } - let _p = profile("handle_resolve_code_action"); let file_id = from_proto::file_id(&world, ¶ms.code_action_params.text_document.uri)?; let line_index = world.analysis().file_line_index(file_id)?; let range = from_proto::text_range(&line_index, params.code_action_params.range); let frange = FileRange { file_id, range }; - let mut res: Vec = Vec::new(); - for assist in world.analysis().resolved_assists(&world.config.assist, frange)?.into_iter() { - res.push(to_proto::resolved_code_action(&world, assist)?); - } - Ok(res - .into_iter() - .find(|action| action.id.clone().unwrap() == params.id && action.title == params.label) - .and_then(|action| action.edit)) + let assists = world.analysis().resolved_assists(&world.config.assist, frange)?; + let id_components = params.id.split(":").collect::>(); + let index = id_components.last().unwrap().parse::().unwrap(); + let id_string = id_components.first().unwrap(); + let assist = &assists[index]; + assert!(assist.assist.id.0 == *id_string); + Ok(to_proto::resolved_code_action(&world, assist.clone())?.edit) } pub fn handle_code_lens( diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 3672b1a26..fb33bdd5f 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -622,17 +622,12 @@ fn main() { pub(crate) fn unresolved_code_action( world: &WorldSnapshot, assist: Assist, + index: usize, ) -> Result { let res = lsp_ext::CodeAction { title: assist.label, - id: Some(assist.id.0.to_owned()), - group: assist.group.and_then(|it| { - if world.config.client_caps.code_action_group { - None - } else { - Some(it.0) - } - }), + id: Some(format!("{}:{}", assist.id.0.to_owned(), index.to_string())), + group: assist.group.filter(|_| world.config.client_caps.code_action_group).map(|gr| gr.0), kind: Some(String::new()), edit: None, command: None, @@ -644,21 +639,14 @@ pub(crate) fn resolved_code_action( world: &WorldSnapshot, assist: ResolvedAssist, ) -> Result { - let res = lsp_ext::CodeAction { - title: assist.assist.label, - id: Some(assist.assist.id.0.to_owned()), - group: assist.assist.group.and_then(|it| { - if world.config.client_caps.code_action_group { - None - } else { - Some(it.0) - } - }), - kind: Some(String::new()), - edit: Some(snippet_workspace_edit(world, assist.source_change)?), - command: None, - }; - Ok(res) + let change = assist.source_change; + unresolved_code_action(world, assist.assist, 0).and_then(|it| { + Ok(lsp_ext::CodeAction { + id: None, + edit: Some(snippet_workspace_edit(world, change)?), + ..it + }) + }) } pub(crate) fn runnable( -- cgit v1.2.3 From 6cd2e04bd2a703c335566224e8b6bf773b83c0c6 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Wed, 3 Jun 2020 19:33:57 +0200 Subject: Fix more comments --- crates/rust-analyzer/src/main_loop/handlers.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index a3361d6dc..6acf80c58 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -25,7 +25,7 @@ use ra_project_model::TargetKind; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; use serde::{Deserialize, Serialize}; use serde_json::to_value; -use stdx::format_to; +use stdx::{format_to, split1}; use crate::{ cargo_target_spec::CargoTargetSpec, @@ -786,11 +786,10 @@ pub fn handle_resolve_code_action( let frange = FileRange { file_id, range }; let assists = snap.analysis().resolved_assists(&snap.config.assist, frange)?; - let id_components = params.id.split(":").collect::>(); - let index = id_components.last().unwrap().parse::().unwrap(); - let id_string = id_components.first().unwrap(); + let (id_string, index) = split1(¶ms.id, ':').unwrap(); + let index = index.parse::().unwrap(); let assist = &assists[index]; - assert!(assist.assist.id.0 == *id_string); + assert!(assist.assist.id.0 == id_string); Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit) } -- cgit v1.2.3 From a9d567584857b1be4ca8eaa5ef2c7d85f7b2845e Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Wed, 3 Jun 2020 20:10:33 +0200 Subject: Fix incorrect behaviour if not resolved --- crates/ra_assists/src/assist_context.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index bc5481494..1925db8b2 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -179,6 +179,7 @@ impl Assists { f: impl FnOnce(&mut AssistDirector), ) -> Option<()> { if !self.resolve { + self.buf.push((label, None)); return None; } let mut director = AssistDirector::default(); -- cgit v1.2.3 From a6d3c77bdd998499941a6aceccde85f7a94b804d Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Wed, 3 Jun 2020 20:43:57 +0200 Subject: Fixed tests --- .../handlers/extract_struct_from_enum_variant.rs | 21 ++++++++++++--------- crates/ra_assists/src/lib.rs | 2 +- crates/ra_assists/src/tests/generated.rs | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index a36587633..2b1951aff 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -18,9 +18,9 @@ use ra_db::FileId; use ra_fmt::leading_indent; use rustc_hash::FxHashSet; -// Assist extract_struct_from_enum +// Assist: extract_struct_from_enum_variant // -// Extracts a struct from enum variant +// Extracts a struct from enum variant. // // ``` // enum A { <|>One(u32, u32) } @@ -29,9 +29,12 @@ use rustc_hash::FxHashSet; // ``` // struct One(pub u32, pub u32); // -// enum A { One(One) }" +// enum A { One(One) } // ``` -pub(crate) fn extract_struct_from_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { +pub(crate) fn extract_struct_from_enum_variant( + acc: &mut Assists, + ctx: &AssistContext, +) -> Option<()> { let variant = ctx.find_node_at_offset::()?; let field_list = match variant.kind() { ast::StructKind::Tuple(field_list) => field_list, @@ -221,7 +224,7 @@ mod tests { #[test] fn test_extract_struct_several_fields() { check_assist( - extract_struct_from_enum, + extract_struct_from_enum_variant, "enum A { <|>One(u32, u32) }", r#"struct One(pub u32, pub u32); @@ -232,7 +235,7 @@ enum A { One(One) }"#, #[test] fn test_extract_struct_one_field() { check_assist( - extract_struct_from_enum, + extract_struct_from_enum_variant, "enum A { <|>One(u32) }", r#"struct One(pub u32); @@ -243,7 +246,7 @@ enum A { One(One) }"#, #[test] fn test_extract_struct_pub_visibility() { check_assist( - extract_struct_from_enum, + extract_struct_from_enum_variant, "pub enum A { <|>One(u32, u32) }", r#"pub struct One(pub u32, pub u32); @@ -254,7 +257,7 @@ pub enum A { One(One) }"#, #[test] fn test_extract_struct_with_complex_imports() { check_assist( - extract_struct_from_enum, + extract_struct_from_enum_variant, r#"mod my_mod { fn another_fn() { let m = my_other_mod::MyEnum::MyField(1, 1); @@ -305,7 +308,7 @@ fn another_fn() { fn check_not_applicable(ra_fixture: &str) { let fixture = format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); - check_assist_not_applicable(extract_struct_from_enum, &fixture) + check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) } #[test] diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 88ce9b62e..185428bd5 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -156,7 +156,7 @@ mod handlers { change_return_type_to_result::change_return_type_to_result, change_visibility::change_visibility, early_return::convert_to_guarded_return, - extract_struct_from_enum_variant::extract_struct_from_enum, + extract_struct_from_enum_variant::extract_struct_from_enum_variant, fill_match_arms::fill_match_arms, fix_visibility::fix_visibility, flip_binexpr::flip_binexpr, diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index d17504529..40a223727 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs @@ -337,6 +337,21 @@ fn main() { ) } +#[test] +fn doctest_extract_struct_from_enum_variant() { + check_doc_test( + "extract_struct_from_enum_variant", + r#####" +enum A { <|>One(u32, u32) } +"#####, + r#####" +struct One(pub u32, pub u32); + +enum A { One(One) } +"#####, + ) +} + #[test] fn doctest_fill_match_arms() { check_doc_test( -- cgit v1.2.3 From fb632c747d953d615575850477d4662802be320f Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Wed, 3 Jun 2020 15:21:47 -0400 Subject: Parse default unsafe & default const --- crates/ra_parser/src/grammar/items.rs | 26 ++++++++++++++++- .../parser/inline/err/0010_wrong_order_fns.rast | 34 +++++++++++++--------- 2 files changed, 45 insertions(+), 15 deletions(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 67a924de5..41f8bb0b6 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -118,7 +118,15 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul && p.at_contextual_kw("default") && (match p.nth(1) { T![impl] => true, - T![fn] | T![type] => { + T![unsafe] => { + if T![impl] == p.nth(2) { + p.bump_remap(T![default]); + p.bump_remap(T![unsafe]); + has_mods = true; + } + false + } + T![fn] | T![type] | T![const] => { if let ItemFlavor::Mod = flavor { true } else { @@ -187,6 +195,9 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // test default_impl // default impl Foo {} + // test default_unsafe_impl + // default unsafe impl Foo {} + // test_err default_fn_type // trait T { // default type T = Bar; @@ -199,6 +210,19 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // default fn foo() {} // } + // test_err default_const + // trait T { + // default const f: u8 = 0; + // } + + // test default_const + // impl T for Foo { + // default const f: u8 = 0; + // } + T![const] => { + consts::const_def(p, m); + } + // test unsafe_default_impl // unsafe default impl Foo {} T![impl] => { diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast index 9be441110..53f7ebaf9 100644 --- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast +++ b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast @@ -17,23 +17,29 @@ SOURCE_FILE@0..50 L_CURLY@22..23 "{" R_CURLY@23..24 "}" WHITESPACE@24..25 "\n" - ERROR@25..31 + CONST_DEF@25..46 UNSAFE_KW@25..31 "unsafe" - WHITESPACE@31..32 " " - FN_DEF@32..49 + WHITESPACE@31..32 " " CONST_KW@32..37 "const" WHITESPACE@37..38 " " - FN_KW@38..40 "fn" + ERROR@38..40 + FN_KW@38..40 "fn" WHITESPACE@40..41 " " - NAME@41..44 - IDENT@41..44 "bar" - PARAM_LIST@44..46 - L_PAREN@44..45 "(" - R_PAREN@45..46 ")" - WHITESPACE@46..47 " " - BLOCK_EXPR@47..49 - L_CURLY@47..48 "{" - R_CURLY@48..49 "}" + PATH_TYPE@41..46 + PATH@41..46 + PATH_SEGMENT@41..46 + NAME_REF@41..44 + IDENT@41..44 "bar" + PARAM_LIST@44..46 + L_PAREN@44..45 "(" + R_PAREN@45..46 ")" + WHITESPACE@46..47 " " + ERROR@47..49 + L_CURLY@47..48 "{" + R_CURLY@48..49 "}" WHITESPACE@49..50 "\n" error 6..6: expected existential, fn, trait or impl -error 31..31: expected existential, fn, trait or impl +error 38..38: expected a name +error 40..40: expected COLON +error 46..46: expected SEMICOLON +error 47..47: expected an item -- cgit v1.2.3 From a5588b9e19cbbc18b1afd9afcc9bab2bce2b711c Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Wed, 3 Jun 2020 20:39:57 -0400 Subject: Update tests --- .../parser/inline/err/0015_default_const.rast | 40 ++++++++++++++++++++ .../parser/inline/err/0015_default_const.rs | 3 ++ .../parser/inline/ok/0162_default_const.rast | 44 ++++++++++++++++++++++ .../parser/inline/ok/0162_default_const.rs | 3 ++ .../parser/inline/ok/0163_default_unsafe_impl.rast | 18 +++++++++ .../parser/inline/ok/0163_default_unsafe_impl.rs | 1 + 6 files changed, 109 insertions(+) create mode 100644 crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast create mode 100644 crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs (limited to 'crates') diff --git a/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast b/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast new file mode 100644 index 000000000..8eb583ef8 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast @@ -0,0 +1,40 @@ +SOURCE_FILE@0..39 + TRAIT_DEF@0..38 + TRAIT_KW@0..5 "trait" + WHITESPACE@5..6 " " + NAME@6..7 + IDENT@6..7 "T" + WHITESPACE@7..8 " " + ITEM_LIST@8..38 + L_CURLY@8..9 "{" + WHITESPACE@9..12 "\n " + MACRO_CALL@12..19 + PATH@12..19 + PATH_SEGMENT@12..19 + NAME_REF@12..19 + IDENT@12..19 "default" + WHITESPACE@19..20 " " + CONST_DEF@20..36 + CONST_KW@20..25 "const" + WHITESPACE@25..26 " " + NAME@26..27 + IDENT@26..27 "f" + COLON@27..28 ":" + WHITESPACE@28..29 " " + PATH_TYPE@29..31 + PATH@29..31 + PATH_SEGMENT@29..31 + NAME_REF@29..31 + IDENT@29..31 "u8" + WHITESPACE@31..32 " " + EQ@32..33 "=" + WHITESPACE@33..34 " " + LITERAL@34..35 + INT_NUMBER@34..35 "0" + SEMICOLON@35..36 ";" + WHITESPACE@36..37 "\n" + R_CURLY@37..38 "}" + WHITESPACE@38..39 "\n" +error 19..19: expected BANG +error 19..19: expected `{`, `[`, `(` +error 19..19: expected SEMICOLON diff --git a/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs b/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs new file mode 100644 index 000000000..80f15474a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs @@ -0,0 +1,3 @@ +trait T { + default const f: u8 = 0; +} diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast b/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast new file mode 100644 index 000000000..dab0247ee --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast @@ -0,0 +1,44 @@ +SOURCE_FILE@0..46 + IMPL_DEF@0..45 + IMPL_KW@0..4 "impl" + WHITESPACE@4..5 " " + PATH_TYPE@5..6 + PATH@5..6 + PATH_SEGMENT@5..6 + NAME_REF@5..6 + IDENT@5..6 "T" + WHITESPACE@6..7 " " + FOR_KW@7..10 "for" + WHITESPACE@10..11 " " + PATH_TYPE@11..14 + PATH@11..14 + PATH_SEGMENT@11..14 + NAME_REF@11..14 + IDENT@11..14 "Foo" + WHITESPACE@14..15 " " + ITEM_LIST@15..45 + L_CURLY@15..16 "{" + WHITESPACE@16..19 "\n " + CONST_DEF@19..43 + DEFAULT_KW@19..26 "default" + WHITESPACE@26..27 " " + CONST_KW@27..32 "const" + WHITESPACE@32..33 " " + NAME@33..34 + IDENT@33..34 "f" + COLON@34..35 ":" + WHITESPACE@35..36 " " + PATH_TYPE@36..38 + PATH@36..38 + PATH_SEGMENT@36..38 + NAME_REF@36..38 + IDENT@36..38 "u8" + WHITESPACE@38..39 " " + EQ@39..40 "=" + WHITESPACE@40..41 " " + LITERAL@41..42 + INT_NUMBER@41..42 "0" + SEMICOLON@42..43 ";" + WHITESPACE@43..44 "\n" + R_CURLY@44..45 "}" + WHITESPACE@45..46 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs b/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs new file mode 100644 index 000000000..dfb3b92dc --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs @@ -0,0 +1,3 @@ +impl T for Foo { + default const f: u8 = 0; +} diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast new file mode 100644 index 000000000..a9eda5668 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast @@ -0,0 +1,18 @@ +SOURCE_FILE@0..27 + IMPL_DEF@0..26 + DEFAULT_KW@0..7 "default" + WHITESPACE@7..8 " " + UNSAFE_KW@8..14 "unsafe" + WHITESPACE@14..15 " " + IMPL_KW@15..19 "impl" + WHITESPACE@19..20 " " + PATH_TYPE@20..23 + PATH@20..23 + PATH_SEGMENT@20..23 + NAME_REF@20..23 + IDENT@20..23 "Foo" + WHITESPACE@23..24 " " + ITEM_LIST@24..26 + L_CURLY@24..25 "{" + R_CURLY@25..26 "}" + WHITESPACE@26..27 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs new file mode 100644 index 000000000..ba0998ff4 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs @@ -0,0 +1 @@ +default unsafe impl Foo {} -- cgit v1.2.3 From 19b27f2ec93e30a32643caf173accdc238d86683 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 3 Jun 2020 17:55:06 -0700 Subject: Declare required lsp-server dependency of rust-analyzer crate My codebase already depended on lsp-server and introducing a dependency on rust-analyzer failed at first because it assumes some functions that were first present in lsp-server 0.3.2. Without this change: error[E0599]: no method named `initialize_start` found for struct `lsp_server::Connection` in the current scope --> crates/rust-analyzer/./src/bin/main.rs:83:57 | 83 | let (initialize_id, initialize_params) = connection.initialize_start()?; | ^^^^^^^^^^^^^^^^ method not found in `lsp_server::Connection` error[E0599]: no method named `initialize_finish` found for struct `lsp_server::Connection` in the current scope --> crates/rust-analyzer/./src/bin/main.rs:99:16 | 99 | connection.initialize_finish(initialize_id, initialize_result)?; | ^^^^^^^^^^^^^^^^^ method not found in `lsp_server::Connection` --- crates/rust-analyzer/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 65b487db3..a010125b7 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -32,7 +32,7 @@ threadpool = "1.7.1" stdx = { path = "../stdx" } -lsp-server = "0.3.1" +lsp-server = "0.3.2" ra_flycheck = { path = "../ra_flycheck" } ra_ide = { path = "../ra_ide" } ra_prof = { path = "../ra_prof" } -- cgit v1.2.3 From 73480409440a04183cd7b74a166d0bf7f2c30d03 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 3 Jun 2020 18:01:24 -0700 Subject: Remove unneeded "./" prefix affecting error messages Before: error[E0599]: no method named `initialize_finish` found for struct `lsp_server::Connection` in the current scope --> crates/rust-analyzer/./src/bin/main.rs:99:16 | 99 | connection.initialize_finish(initialize_id, initialize_result)?; | ^^^^^^^^^^^^^^^^^ method not found in `lsp_server::Connection` After: error[E0599]: no method named `initialize_finish` found for struct `lsp_server::Connection` in the current scope --> crates/rust-analyzer/src/bin/main.rs:99:16 | 99 | connection.initialize_finish(initialize_id, initialize_result)?; | ^^^^^^^^^^^^^^^^^ method not found in `lsp_server::Connection` --- crates/rust-analyzer/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 65b487db3..bf8ca9e7d 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -10,7 +10,7 @@ doctest = false [[bin]] name = "rust-analyzer" -path = "./src/bin/main.rs" +path = "src/bin/main.rs" [dependencies] anyhow = "1.0.26" -- cgit v1.2.3 From 4461796f33d3d50de4d704a76fae6fa3cb2b73aa Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 3 Jun 2020 19:05:55 -0700 Subject: Fix type inference failure when built with log/kv_unstable This code is broken by an `impl From for fmt::Error` in the log crate when building in a codebase that has the log/kv_unstable feature enabled. $ cargo check --manifest-path crates/ra_hir_def/Cargo.toml Checking ra_hir_def v0.1.0 Finished dev [unoptimized] target(s) in 0.75s $ cargo check --manifest-path crates/ra_hir_def/Cargo.toml --features log/kv_unstable Checking ra_hir_def v0.1.0 error[E0282]: type annotations needed for the closure `fn(&str) -> std::result::Result<(), _>` --> crates/ra_hir_def/src/path.rs:278:17 | 278 | f.write_str("::")?; | ^^^^^^^^^^^^^^^^^^ cannot infer type | help: give this closure an explicit return type without `_` placeholders | 276 | let mut add_segment = |s| -> std::result::Result<(), _> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- crates/ra_hir_def/src/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index e84efe2ab..4512448e0 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -273,7 +273,7 @@ impl From for ModPath { impl Display for ModPath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut first_segment = true; - let mut add_segment = |s| { + let mut add_segment = |s| -> fmt::Result { if !first_segment { f.write_str("::")?; } -- cgit v1.2.3 From b0c8a2be7bd0d053eb9dd0e02fe2cf08b093a19a Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Thu, 4 Jun 2020 10:03:44 +0200 Subject: Remove AsName import --- .../src/handlers/extract_struct_from_enum_variant.rs | 13 +++++++++---- crates/ra_assists/src/utils/insert_use.rs | 11 ++++++++++- crates/ra_hir/src/lib.rs | 5 ++--- 3 files changed, 21 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 2b1951aff..72e5dd735 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -9,11 +9,11 @@ use ra_syntax::{ use crate::{ assist_context::{AssistBuilder, AssistDirector}, - utils::insert_use_statement, + utils::insert_use::insert_use_statement_with_string_path, AssistContext, AssistId, Assists, }; use ast::{ArgListOwner, VisibilityOwner}; -use hir::{AsName, EnumVariant, Module, ModuleDef}; +use hir::{EnumVariant, Module, ModuleDef}; use ra_db::FileId; use ra_fmt::leading_indent; use rustc_hash::FxHashSet; @@ -109,8 +109,13 @@ fn insert_import( let mod_path = module.find_use_path(db, module_def.clone()); if let Some(mut mod_path) = mod_path { mod_path.segments.pop(); - mod_path.segments.push(path_segment.as_name()); - insert_use_statement(path.syntax(), &mod_path, ctx, builder.text_edit_builder()); + let use_path = format!("{}::{}", mod_path.to_string(), path_segment.to_string()); + insert_use_statement_with_string_path( + path.syntax(), + &use_path, + ctx, + builder.text_edit_builder(), + ); } Some(()) } diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index 0ee43482f..114f5949a 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs @@ -23,7 +23,16 @@ pub(crate) fn insert_use_statement( ctx: &AssistContext, builder: &mut TextEditBuilder, ) { - let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::>(); + insert_use_statement_with_string_path(position, &path_to_import.to_string(), ctx, builder); +} + +pub(crate) fn insert_use_statement_with_string_path( + position: &SyntaxNode, + path_to_import: &str, + ctx: &AssistContext, + builder: &mut TextEditBuilder, +) { + let target = path_to_import.split("::").map(SmolStr::new).collect::>(); let container = ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| { if let Some(module) = ast::Module::cast(n.clone()) { return module.item_list().map(|it| it.syntax().clone()); diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f4a6b0503..3364a822f 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -71,8 +71,7 @@ pub use hir_def::{ type_ref::Mutability, }; pub use hir_expand::{ - hygiene::Hygiene, - name::{AsName, Name}, - HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, + hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, + MacroFile, Origin, }; pub use hir_ty::{display::HirDisplay, CallableDef}; -- cgit v1.2.3 From 3ec2dcfc0d7ea7d9fb9c499616e9eca06b5c865b Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Thu, 4 Jun 2020 13:00:21 -0400 Subject: Address review --- crates/ra_parser/src/grammar/items.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 41f8bb0b6..0d3568e5f 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -119,9 +119,11 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul && (match p.nth(1) { T![impl] => true, T![unsafe] => { - if T![impl] == p.nth(2) { + // test default_unsafe_impl + // default unsafe impl Foo {} + if p.nth(2) == T![impl] { p.bump_remap(T![default]); - p.bump_remap(T![unsafe]); + p.bump(T![unsafe]); has_mods = true; } false @@ -195,9 +197,6 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // test default_impl // default impl Foo {} - // test default_unsafe_impl - // default unsafe impl Foo {} - // test_err default_fn_type // trait T { // default type T = Bar; -- cgit v1.2.3 From c4fd46398132a409d7947141094d7301c0f0af73 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Thu, 4 Jun 2020 13:06:26 -0400 Subject: Move default const test out of line --- crates/ra_parser/src/grammar/items.rs | 10 ----- .../test_data/parser/err/0043_default_const.rast | 40 ++++++++++++++++++++ .../test_data/parser/err/0043_default_const.rs | 3 ++ .../parser/inline/err/0015_default_const.rast | 40 -------------------- .../parser/inline/err/0015_default_const.rs | 3 -- .../parser/inline/ok/0162_default_const.rast | 44 ---------------------- .../parser/inline/ok/0162_default_const.rs | 3 -- .../test_data/parser/ok/0066_default_const.rast | 44 ++++++++++++++++++++++ .../test_data/parser/ok/0066_default_const.rs | 3 ++ 9 files changed, 90 insertions(+), 100 deletions(-) create mode 100644 crates/ra_syntax/test_data/parser/err/0043_default_const.rast create mode 100644 crates/ra_syntax/test_data/parser/err/0043_default_const.rs delete mode 100644 crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast delete mode 100644 crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs delete mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast delete mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs create mode 100644 crates/ra_syntax/test_data/parser/ok/0066_default_const.rast create mode 100644 crates/ra_syntax/test_data/parser/ok/0066_default_const.rs (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 0d3568e5f..9c14b954a 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -208,16 +208,6 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // default type T = Bar; // default fn foo() {} // } - - // test_err default_const - // trait T { - // default const f: u8 = 0; - // } - - // test default_const - // impl T for Foo { - // default const f: u8 = 0; - // } T![const] => { consts::const_def(p, m); } diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast new file mode 100644 index 000000000..8eb583ef8 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast @@ -0,0 +1,40 @@ +SOURCE_FILE@0..39 + TRAIT_DEF@0..38 + TRAIT_KW@0..5 "trait" + WHITESPACE@5..6 " " + NAME@6..7 + IDENT@6..7 "T" + WHITESPACE@7..8 " " + ITEM_LIST@8..38 + L_CURLY@8..9 "{" + WHITESPACE@9..12 "\n " + MACRO_CALL@12..19 + PATH@12..19 + PATH_SEGMENT@12..19 + NAME_REF@12..19 + IDENT@12..19 "default" + WHITESPACE@19..20 " " + CONST_DEF@20..36 + CONST_KW@20..25 "const" + WHITESPACE@25..26 " " + NAME@26..27 + IDENT@26..27 "f" + COLON@27..28 ":" + WHITESPACE@28..29 " " + PATH_TYPE@29..31 + PATH@29..31 + PATH_SEGMENT@29..31 + NAME_REF@29..31 + IDENT@29..31 "u8" + WHITESPACE@31..32 " " + EQ@32..33 "=" + WHITESPACE@33..34 " " + LITERAL@34..35 + INT_NUMBER@34..35 "0" + SEMICOLON@35..36 ";" + WHITESPACE@36..37 "\n" + R_CURLY@37..38 "}" + WHITESPACE@38..39 "\n" +error 19..19: expected BANG +error 19..19: expected `{`, `[`, `(` +error 19..19: expected SEMICOLON diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rs b/crates/ra_syntax/test_data/parser/err/0043_default_const.rs new file mode 100644 index 000000000..80f15474a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0043_default_const.rs @@ -0,0 +1,3 @@ +trait T { + default const f: u8 = 0; +} diff --git a/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast b/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast deleted file mode 100644 index 8eb583ef8..000000000 --- a/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rast +++ /dev/null @@ -1,40 +0,0 @@ -SOURCE_FILE@0..39 - TRAIT_DEF@0..38 - TRAIT_KW@0..5 "trait" - WHITESPACE@5..6 " " - NAME@6..7 - IDENT@6..7 "T" - WHITESPACE@7..8 " " - ITEM_LIST@8..38 - L_CURLY@8..9 "{" - WHITESPACE@9..12 "\n " - MACRO_CALL@12..19 - PATH@12..19 - PATH_SEGMENT@12..19 - NAME_REF@12..19 - IDENT@12..19 "default" - WHITESPACE@19..20 " " - CONST_DEF@20..36 - CONST_KW@20..25 "const" - WHITESPACE@25..26 " " - NAME@26..27 - IDENT@26..27 "f" - COLON@27..28 ":" - WHITESPACE@28..29 " " - PATH_TYPE@29..31 - PATH@29..31 - PATH_SEGMENT@29..31 - NAME_REF@29..31 - IDENT@29..31 "u8" - WHITESPACE@31..32 " " - EQ@32..33 "=" - WHITESPACE@33..34 " " - LITERAL@34..35 - INT_NUMBER@34..35 "0" - SEMICOLON@35..36 ";" - WHITESPACE@36..37 "\n" - R_CURLY@37..38 "}" - WHITESPACE@38..39 "\n" -error 19..19: expected BANG -error 19..19: expected `{`, `[`, `(` -error 19..19: expected SEMICOLON diff --git a/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs b/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs deleted file mode 100644 index 80f15474a..000000000 --- a/crates/ra_syntax/test_data/parser/inline/err/0015_default_const.rs +++ /dev/null @@ -1,3 +0,0 @@ -trait T { - default const f: u8 = 0; -} diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast b/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast deleted file mode 100644 index dab0247ee..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rast +++ /dev/null @@ -1,44 +0,0 @@ -SOURCE_FILE@0..46 - IMPL_DEF@0..45 - IMPL_KW@0..4 "impl" - WHITESPACE@4..5 " " - PATH_TYPE@5..6 - PATH@5..6 - PATH_SEGMENT@5..6 - NAME_REF@5..6 - IDENT@5..6 "T" - WHITESPACE@6..7 " " - FOR_KW@7..10 "for" - WHITESPACE@10..11 " " - PATH_TYPE@11..14 - PATH@11..14 - PATH_SEGMENT@11..14 - NAME_REF@11..14 - IDENT@11..14 "Foo" - WHITESPACE@14..15 " " - ITEM_LIST@15..45 - L_CURLY@15..16 "{" - WHITESPACE@16..19 "\n " - CONST_DEF@19..43 - DEFAULT_KW@19..26 "default" - WHITESPACE@26..27 " " - CONST_KW@27..32 "const" - WHITESPACE@32..33 " " - NAME@33..34 - IDENT@33..34 "f" - COLON@34..35 ":" - WHITESPACE@35..36 " " - PATH_TYPE@36..38 - PATH@36..38 - PATH_SEGMENT@36..38 - NAME_REF@36..38 - IDENT@36..38 "u8" - WHITESPACE@38..39 " " - EQ@39..40 "=" - WHITESPACE@40..41 " " - LITERAL@41..42 - INT_NUMBER@41..42 "0" - SEMICOLON@42..43 ";" - WHITESPACE@43..44 "\n" - R_CURLY@44..45 "}" - WHITESPACE@45..46 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs b/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs deleted file mode 100644 index dfb3b92dc..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0162_default_const.rs +++ /dev/null @@ -1,3 +0,0 @@ -impl T for Foo { - default const f: u8 = 0; -} diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast new file mode 100644 index 000000000..dab0247ee --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast @@ -0,0 +1,44 @@ +SOURCE_FILE@0..46 + IMPL_DEF@0..45 + IMPL_KW@0..4 "impl" + WHITESPACE@4..5 " " + PATH_TYPE@5..6 + PATH@5..6 + PATH_SEGMENT@5..6 + NAME_REF@5..6 + IDENT@5..6 "T" + WHITESPACE@6..7 " " + FOR_KW@7..10 "for" + WHITESPACE@10..11 " " + PATH_TYPE@11..14 + PATH@11..14 + PATH_SEGMENT@11..14 + NAME_REF@11..14 + IDENT@11..14 "Foo" + WHITESPACE@14..15 " " + ITEM_LIST@15..45 + L_CURLY@15..16 "{" + WHITESPACE@16..19 "\n " + CONST_DEF@19..43 + DEFAULT_KW@19..26 "default" + WHITESPACE@26..27 " " + CONST_KW@27..32 "const" + WHITESPACE@32..33 " " + NAME@33..34 + IDENT@33..34 "f" + COLON@34..35 ":" + WHITESPACE@35..36 " " + PATH_TYPE@36..38 + PATH@36..38 + PATH_SEGMENT@36..38 + NAME_REF@36..38 + IDENT@36..38 "u8" + WHITESPACE@38..39 " " + EQ@39..40 "=" + WHITESPACE@40..41 " " + LITERAL@41..42 + INT_NUMBER@41..42 "0" + SEMICOLON@42..43 ";" + WHITESPACE@43..44 "\n" + R_CURLY@44..45 "}" + WHITESPACE@45..46 "\n" diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs new file mode 100644 index 000000000..dfb3b92dc --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs @@ -0,0 +1,3 @@ +impl T for Foo { + default const f: u8 = 0; +} -- cgit v1.2.3 From d08c63cb9e3574fa97374a8529136814530bf416 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 20 May 2020 23:51:20 +0200 Subject: Add an ImportMap --- crates/ra_db/src/lib.rs | 4 +- crates/ra_hir_def/src/db.rs | 4 + crates/ra_hir_def/src/find_path.rs | 19 +-- crates/ra_hir_def/src/import_map.rs | 323 ++++++++++++++++++++++++++++++++++++ crates/ra_hir_def/src/lib.rs | 1 + crates/ra_hir_def/src/path.rs | 13 ++ crates/ra_hir_def/src/per_ns.rs | 10 +- 7 files changed, 360 insertions(+), 14 deletions(-) create mode 100644 crates/ra_hir_def/src/import_map.rs (limited to 'crates') diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index fd4280de2..e7868268b 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -11,8 +11,8 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; pub use crate::{ cancellation::Canceled, input::{ - CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId, - FileId, ProcMacroId, SourceRoot, SourceRootId, + CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, + ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId, }, }; pub use relative_path::{RelativePath, RelativePathBuf}; diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 945a0025e..a23d65371 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -14,6 +14,7 @@ use crate::{ docs::Documentation, find_path, generics::GenericParams, + import_map::ImportMap, item_scope::ItemInNs, lang_item::{LangItemTarget, LangItems}, nameres::{raw::RawItems, CrateDefMap}, @@ -122,6 +123,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { #[salsa::invoke(find_path::find_path_inner_query)] fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option; + + #[salsa::invoke(ImportMap::import_map_query)] + fn import_map(&self, krate: CrateId) -> Arc; } fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc { diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 4db798473..088e8dd32 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -36,17 +36,6 @@ impl ModPath { let first_segment = self.segments.first(); first_segment == Some(&known::alloc) || first_segment == Some(&known::core) } - - fn len(&self) -> usize { - self.segments.len() - + match self.kind { - PathKind::Plain => 0, - PathKind::Super(i) => i as usize, - PathKind::Crate => 1, - PathKind::Abs => 0, - PathKind::DollarCrate(_) => 1, - } - } } pub(crate) fn find_path_inner_query( @@ -192,9 +181,17 @@ fn find_importable_locations( ) -> Vec<(ModuleId, Name)> { let crate_graph = db.crate_graph(); let mut result = Vec::new(); + // We only look in the crate from which we are importing, and the direct // dependencies. We cannot refer to names from transitive dependencies // directly (only through reexports in direct dependencies). + + // For the crate from which we're importing, we have to check whether any + // module visible to `from` exports the item we're looking for. + // For dependencies of the crate only `pub` items reachable through `pub` + // modules from the crate root are relevant. For that we precompute an + // import map that tells us the shortest path to any importable item with a + // single lookup. for krate in Some(from.krate) .into_iter() .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id)) diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs new file mode 100644 index 000000000..7dae64efa --- /dev/null +++ b/crates/ra_hir_def/src/import_map.rs @@ -0,0 +1,323 @@ +//! A map of all publicly exported items in a crate. + +use crate::{ + db::DefDatabase, + item_scope::ItemInNs, + path::{ModPath, PathKind}, + visibility::Visibility, + ModuleDefId, ModuleId, +}; +use ra_db::CrateId; +use rustc_hash::FxHashMap; +use std::{collections::hash_map::Entry, sync::Arc}; + +/// A map from publicly exported items to the path needed to import/name them from a downstream +/// crate. +/// +/// Reexports of items are taken into account, ie. if something is exported under multiple +/// names, the one with the shortest import path will be used. +/// +/// Note that all paths are relative to the containing crate's root, so the crate name still needs +/// to be prepended to the `ModPath` before the path is valid. +#[derive(Debug, Eq, PartialEq)] +pub struct ImportMap { + map: FxHashMap, +} + +impl ImportMap { + pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { + let _p = ra_prof::profile("import_map_query"); + let def_map = db.crate_def_map(krate); + let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default()); + + // We look only into modules that are public(ly reexported), starting with the crate root. + let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; + let root = ModuleId { krate, local_id: def_map.root }; + let mut worklist = vec![(root, empty)]; + while let Some((module, mod_path)) = worklist.pop() { + let ext_def_map; + let mod_data = if module.krate == krate { + &def_map[module.local_id] + } else { + // The crate might reexport a module defined in another crate. + ext_def_map = db.crate_def_map(module.krate); + &ext_def_map[module.local_id] + }; + + let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { + let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); + if per_ns.is_none() { + None + } else { + Some((name, per_ns)) + } + }); + + for (name, per_ns) in visible_items { + let mk_path = || { + let mut path = mod_path.clone(); + path.segments.push(name.clone()); + path + }; + + for item in per_ns.iter_items() { + let path = mk_path(); + match import_map.entry(item) { + Entry::Vacant(entry) => { + entry.insert(path); + } + Entry::Occupied(mut entry) => { + // If the new path is shorter, prefer that one. + if path.len() < entry.get().len() { + *entry.get_mut() = path; + } else { + continue; + } + } + } + + // If we've just added a path to a module, descend into it. + if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { + worklist.push((mod_id, mk_path())); + } + } + } + } + + Arc::new(Self { map: import_map }) + } + + /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. + pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { + self.map.get(&item) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_db::TestDB; + use insta::assert_snapshot; + use ra_db::fixture::WithFixture; + use ra_db::SourceDatabase; + + fn import_map(ra_fixture: &str) -> String { + let db = TestDB::with_files(ra_fixture); + let crate_graph = db.crate_graph(); + + let import_maps: Vec<_> = crate_graph + .iter() + .filter_map(|krate| { + let cdata = &crate_graph[krate]; + let name = cdata.display_name.as_ref()?; + + let map = db.import_map(krate); + + let mut importable_paths: Vec<_> = map + .map + .iter() + .map(|(item, modpath)| { + let ns = match item { + ItemInNs::Types(_) => "t", + ItemInNs::Values(_) => "v", + ItemInNs::Macros(_) => "m", + }; + format!("- {} ({})", modpath, ns) + }) + .collect(); + + importable_paths.sort(); + let importable_paths = importable_paths.join("\n"); + + Some(format!("{}:\n{}", name, importable_paths)) + }) + .collect(); + + import_maps.join("\n") + } + + #[test] + fn smoke() { + let map = import_map( + r" + //- /main.rs crate:main deps:lib + + mod private { + pub use lib::Pub; + pub struct InPrivateModule; + } + + pub mod publ1 { + use lib::Pub; + } + + pub mod real_pub { + pub use lib::Pub; + } + pub mod real_pu2 { // same path length as above + pub use lib::Pub; + } + + //- /lib.rs crate:lib + pub struct Pub {} + pub struct Pub2; // t + v + struct Priv; + ", + ); + + assert_snapshot!(map, @r###" + main: + - publ1 (t) + - real_pu2 (t) + - real_pub (t) + - real_pub::Pub (t) + lib: + - Pub (t) + - Pub2 (t) + - Pub2 (v) + "###); + } + + #[test] + fn prefers_shortest_path() { + let map = import_map( + r" + //- /main.rs crate:main + + pub mod sub { + pub mod subsub { + pub struct Def {} + } + + pub use super::sub::subsub::Def; + } + ", + ); + + assert_snapshot!(map, @r###" + main: + - sub (t) + - sub::Def (t) + - sub::subsub (t) + "###); + } + + #[test] + fn type_reexport_cross_crate() { + // Reexports need to be visible from a crate, even if the original crate exports the item + // at a shorter path. + let map = import_map( + r" + //- /main.rs crate:main deps:lib + pub mod m { + pub use lib::S; + } + //- /lib.rs crate:lib + pub struct S; + ", + ); + + assert_snapshot!(map, @r###" + main: + - m (t) + - m::S (t) + - m::S (v) + lib: + - S (t) + - S (v) + "###); + } + + #[test] + fn macro_reexport() { + let map = import_map( + r" + //- /main.rs crate:main deps:lib + pub mod m { + pub use lib::pub_macro; + } + //- /lib.rs crate:lib + #[macro_export] + macro_rules! pub_macro { + () => {}; + } + ", + ); + + assert_snapshot!(map, @r###" + main: + - m (t) + - m::pub_macro (m) + lib: + - pub_macro (m) + "###); + } + + #[test] + fn module_reexport() { + // Reexporting modules from a dependency adds all contents to the import map. + let map = import_map( + r" + //- /main.rs crate:main deps:lib + pub use lib::module as reexported_module; + //- /lib.rs crate:lib + pub mod module { + pub struct S; + } + ", + ); + + assert_snapshot!(map, @r###" + main: + - reexported_module (t) + - reexported_module::S (t) + - reexported_module::S (v) + lib: + - module (t) + - module::S (t) + - module::S (v) + "###); + } + + #[test] + fn cyclic_module_reexport() { + // Reexporting modules from a dependency adds all contents to the import map. + let map = import_map( + r" + //- /lib.rs crate:lib + pub mod module { + pub struct S; + pub use super::sub::*; + } + + pub mod sub { + pub use super::module; + } + ", + ); + + assert_snapshot!(map, @r###" + lib: + - module (t) + - module::S (t) + - module::S (v) + - sub (t) + "###); + } + + #[test] + fn private_macro() { + let map = import_map( + r" + //- /lib.rs crate:lib + macro_rules! private_macro { + () => {}; + } + ", + ); + + assert_snapshot!(map, @r###" + lib: + "###); + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 5325a2760..de490fcc5 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -43,6 +43,7 @@ pub mod child_by_source; pub mod visibility; pub mod find_path; +pub mod import_map; #[cfg(test)] mod test_db; diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 4512448e0..bfa921de2 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -76,6 +76,19 @@ impl ModPath { } } + /// Returns the number of segments in the path (counting special segments like `$crate` and + /// `super`). + pub fn len(&self) -> usize { + self.segments.len() + + match self.kind { + PathKind::Plain => 0, + PathKind::Super(i) => i as usize, + PathKind::Crate => 1, + PathKind::Abs => 0, + PathKind::DollarCrate(_) => 1, + } + } + pub fn is_ident(&self) -> bool { self.kind == PathKind::Plain && self.segments.len() == 1 } diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs index 6e435c8c1..74665c588 100644 --- a/crates/ra_hir_def/src/per_ns.rs +++ b/crates/ra_hir_def/src/per_ns.rs @@ -5,7 +5,7 @@ use hir_expand::MacroDefId; -use crate::{visibility::Visibility, ModuleDefId}; +use crate::{item_scope::ItemInNs, visibility::Visibility, ModuleDefId}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct PerNs { @@ -84,4 +84,12 @@ impl PerNs { macros: self.macros.or(other.macros), } } + + pub fn iter_items(self) -> impl Iterator { + self.types + .map(|it| ItemInNs::Types(it.0)) + .into_iter() + .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter()) + .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter()) + } } -- cgit v1.2.3 From 3c496f7fa7afe78102ea2c7ee5f7e006a66629d4 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 4 Jun 2020 19:30:29 +0200 Subject: Use `ImportMap` in `find_path`, remove old queries --- crates/ra_hir_def/src/db.rs | 16 +-- crates/ra_hir_def/src/find_path.rs | 199 +++++++++++++++++++++--------------- crates/ra_hir_def/src/item_scope.rs | 22 +++- 3 files changed, 140 insertions(+), 97 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index a23d65371..10cc26480 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -1,7 +1,7 @@ //! Defines database & queries for name resolution. use std::sync::Arc; -use hir_expand::{db::AstDatabase, name::Name, HirFileId}; +use hir_expand::{db::AstDatabase, HirFileId}; use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; use ra_prof::profile; use ra_syntax::SmolStr; @@ -12,14 +12,10 @@ use crate::{ body::{scope::ExprScopes, Body, BodySourceMap}, data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, docs::Documentation, - find_path, generics::GenericParams, import_map::ImportMap, - item_scope::ItemInNs, lang_item::{LangItemTarget, LangItems}, nameres::{raw::RawItems, CrateDefMap}, - path::ModPath, - visibility::Visibility, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, @@ -114,16 +110,6 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { #[salsa::invoke(Documentation::documentation_query)] fn documentation(&self, def: AttrDefId) -> Option; - #[salsa::invoke(find_path::importable_locations_of_query)] - fn importable_locations_of( - &self, - item: ItemInNs, - krate: CrateId, - ) -> Arc<[(ModuleId, Name, Visibility)]>; - - #[salsa::invoke(find_path::find_path_inner_query)] - fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option; - #[salsa::invoke(ImportMap::import_map_query)] fn import_map(&self, krate: CrateId) -> Arc; } diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 088e8dd32..79f4afab6 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -1,7 +1,5 @@ //! An algorithm to find a path to refer to a certain item. -use std::sync::Arc; - use hir_expand::name::{known, AsName, Name}; use ra_prof::profile; use test_utils::mark; @@ -11,8 +9,9 @@ use crate::{ item_scope::ItemInNs, path::{ModPath, PathKind}, visibility::Visibility, - CrateId, ModuleDefId, ModuleId, + ModuleDefId, ModuleId, }; +use rustc_hash::FxHashSet; // FIXME: handle local items @@ -20,7 +19,7 @@ use crate::{ /// *from where* you're referring to the item, hence the `from` parameter. pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option { let _p = profile("find_path"); - db.find_path_inner(item, from, MAX_PATH_LEN) + find_path_inner(db, item, from, MAX_PATH_LEN) } const MAX_PATH_LEN: usize = 15; @@ -38,7 +37,7 @@ impl ModPath { } } -pub(crate) fn find_path_inner_query( +pub(crate) fn find_path_inner( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, @@ -122,31 +121,61 @@ pub(crate) fn find_path_inner_query( } // - otherwise, look for modules containing (reexporting) it and import it from one of those + let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; let crate_attrs = db.attrs(crate_root.into()); let prefer_no_std = crate_attrs.by_key("no_std").exists(); - let importable_locations = find_importable_locations(db, item, from); let mut best_path = None; let mut best_path_len = max_len; - for (module_id, name) in importable_locations { - let mut path = match db.find_path_inner( - ItemInNs::Types(ModuleDefId::ModuleId(module_id)), - from, - best_path_len - 1, - ) { - None => continue, - Some(path) => path, - }; - path.segments.push(name); - let new_path = if let Some(best_path) = best_path { - select_best_path(best_path, path, prefer_no_std) - } else { - path - }; - best_path_len = new_path.len(); - best_path = Some(new_path); + if item.defining_crate(db) == Some(from.krate) { + // Item was defined in the same crate that wants to import it. It cannot be found in any + // dependency in this case. + + let local_imports = find_local_import_locations(db, item, from); + for (module_id, name) in local_imports { + if let Some(mut path) = find_path_inner( + db, + ItemInNs::Types(ModuleDefId::ModuleId(module_id)), + from, + best_path_len - 1, + ) { + path.segments.push(name); + + let new_path = if let Some(best_path) = best_path { + select_best_path(best_path, path, prefer_no_std) + } else { + path + }; + best_path_len = new_path.len(); + best_path = Some(new_path); + } + } + } else { + // Item was defined in some upstream crate. This means that it must be exported from one, + // too (unless we can't name it at all). It could *also* be (re)exported by the same crate + // that wants to import it here, but we always prefer to use the external path here. + + let crate_graph = db.crate_graph(); + let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { + let import_map = db.import_map(dep.crate_id); + import_map.path_of(item).map(|modpath| { + let mut modpath = modpath.clone(); + modpath.segments.insert(0, dep.as_name()); + modpath + }) + }); + + for path in extern_paths { + let new_path = if let Some(best_path) = best_path { + select_best_path(best_path, path, prefer_no_std) + } else { + path + }; + best_path = Some(new_path); + } } + best_path } @@ -174,77 +203,86 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) - } } -fn find_importable_locations( +/// Finds locations in `from.krate` from which `item` can be imported by `from`. +fn find_local_import_locations( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, ) -> Vec<(ModuleId, Name)> { - let crate_graph = db.crate_graph(); - let mut result = Vec::new(); - - // We only look in the crate from which we are importing, and the direct - // dependencies. We cannot refer to names from transitive dependencies - // directly (only through reexports in direct dependencies). - - // For the crate from which we're importing, we have to check whether any - // module visible to `from` exports the item we're looking for. - // For dependencies of the crate only `pub` items reachable through `pub` - // modules from the crate root are relevant. For that we precompute an - // import map that tells us the shortest path to any importable item with a - // single lookup. - for krate in Some(from.krate) - .into_iter() - .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id)) - { - result.extend( - db.importable_locations_of(item, krate) - .iter() - .filter(|(_, _, vis)| vis.is_visible_from(db, from)) - .map(|(m, n, _)| (*m, n.clone())), - ); - } - result -} + let _p = profile("find_local_import_locations"); + + // `from` can import anything below `from` with visibility of at least `from`, and anything + // above `from` with any visibility. That means we do not need to descend into private siblings + // of `from` (and similar). + + let def_map = db.crate_def_map(from.krate); + + // Compute the initial worklist. We start with all direct child modules of `from` as well as all + // of its (recursive) parent modules. + let data = &def_map.modules[from.local_id]; + let mut worklist = data + .children + .values() + .map(|child| ModuleId { krate: from.krate, local_id: *child }) + .collect::>(); + let mut parent = data.parent; + while let Some(p) = parent { + worklist.push(ModuleId { krate: from.krate, local_id: p }); + parent = def_map.modules[p].parent; + } + + let mut seen: FxHashSet<_> = FxHashSet::default(); + + let mut locations = Vec::new(); + while let Some(module) = worklist.pop() { + if !seen.insert(module) { + continue; // already processed this module + } + + let ext_def_map; + let data = if module.krate == from.krate { + &def_map[module.local_id] + } else { + // The crate might reexport a module defined in another crate. + ext_def_map = db.crate_def_map(module.krate); + &ext_def_map[module.local_id] + }; -/// Collects all locations from which we might import the item in a particular -/// crate. These include the original definition of the item, and any -/// non-private `use`s. -/// -/// Note that the crate doesn't need to be the one in which the item is defined; -/// it might be re-exported in other crates. -pub(crate) fn importable_locations_of_query( - db: &dyn DefDatabase, - item: ItemInNs, - krate: CrateId, -) -> Arc<[(ModuleId, Name, Visibility)]> { - let _p = profile("importable_locations_of_query"); - let def_map = db.crate_def_map(krate); - let mut result = Vec::new(); - for (local_id, data) in def_map.modules.iter() { if let Some((name, vis)) = data.scope.name_of(item) { - let is_private = if let Visibility::Module(private_to) = vis { - private_to.local_id == local_id - } else { - false - }; - let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { - data.scope.declarations().any(|it| it == module_def_id) - } else { - false - }; - if is_private && !is_original_def { + if vis.is_visible_from(db, from) { + let is_private = if let Visibility::Module(private_to) = vis { + private_to.local_id == module.local_id + } else { + false + }; + let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { + data.scope.declarations().any(|it| it == module_def_id) + } else { + false + }; + // Ignore private imports. these could be used if we are // in a submodule of this module, but that's usually not // what the user wants; and if this module can import // the item and we're a submodule of it, so can we. // Also this keeps the cached data smaller. - continue; + if !is_private || is_original_def { + locations.push((module, name.clone())); + } + } + } + + // Descend into all modules visible from `from`. + for (_, per_ns) in data.scope.entries() { + if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() { + if vis.is_visible_from(db, from) { + worklist.push(module); + } } - result.push((ModuleId { krate, local_id }, name.clone(), vis)); } } - Arc::from(result) + locations } #[cfg(test)] @@ -382,6 +420,7 @@ mod tests { #[test] fn different_crate_renamed() { + // Even if a local path exists, if the item is defined externally, prefer an external path. let code = r#" //- /main.rs crate:main deps:std extern crate std as std_renamed; @@ -389,7 +428,7 @@ mod tests { //- /std.rs crate:std pub struct S; "#; - check_found_path(code, "std_renamed::S"); + check_found_path(code, "std::S"); } #[test] diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index fc15948ad..ede1aa045 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs @@ -6,9 +6,10 @@ use once_cell::sync::Lazy; use rustc_hash::FxHashMap; use crate::{ - per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, - TraitId, + db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, + Lookup, MacroDefId, ModuleDefId, TraitId, }; +use ra_db::CrateId; #[derive(Debug, Default, PartialEq, Eq)] pub struct ItemScope { @@ -203,4 +204,21 @@ impl ItemInNs { ItemInNs::Macros(_) => None, } } + + pub fn defining_crate(&self, db: &dyn DefDatabase) -> Option { + Some(match self { + ItemInNs::Types(did) | ItemInNs::Values(did) => match did { + ModuleDefId::ModuleId(id) => id.krate, + ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate, + ModuleDefId::AdtId(id) => id.module(db).krate, + ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate, + ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate, + ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate, + ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate, + ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate, + ModuleDefId::BuiltinType(_) => return None, + }, + ItemInNs::Macros(id) => return id.krate, + }) + } } -- cgit v1.2.3 From 921306757baa636af7872b003d33dc1a8bd2b725 Mon Sep 17 00:00:00 2001 From: Jess Balint Date: Wed, 3 Jun 2020 17:54:23 -0500 Subject: introduce_named_lifetime assist wasn't applicable when type parameter followed anonymous lifetime token (fixes #4684) --- .../src/handlers/introduce_named_lifetime.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs index beb5b7366..28fcbc9ba 100644 --- a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs @@ -41,8 +41,6 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) - if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) { generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) { - // only allow naming the last anonymous lifetime - lifetime_token.next_token().filter(|tok| tok.kind() == SyntaxKind::R_ANGLE)?; generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range()) } else { None @@ -190,6 +188,23 @@ mod tests { ); } + #[test] + fn test_impl_with_other_type_param() { + check_assist( + introduce_named_lifetime, + "impl fmt::Display for SepByBuilder<'_<|>, I> + where + I: Iterator, + I::Item: fmt::Display, + {", + "impl fmt::Display for SepByBuilder<'a, I> + where + I: Iterator, + I::Item: fmt::Display, + {", + ) + } + #[test] fn test_example_case_cursor_before_tick() { check_assist( -- cgit v1.2.3 From 74c3e7a1adf9d14bbac5cbbe9cd893d758f82561 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Fri, 5 Jun 2020 11:45:41 +0200 Subject: Remove unnecessary return --- crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 72e5dd735..ef963ddba 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -52,7 +52,7 @@ pub(crate) fn extract_struct_from_enum_variant( ImportsLocator::new(ctx.db).find_imports(&enum_name).first()?.left()?; let current_module = current_module_def.module(ctx.db)?; let target = variant.syntax().text_range(); - return acc.add_in_multiple_files( + acc.add_in_multiple_files( AssistId("extract_struct_from_enum_variant"), "Extract struct from enum variant", target, @@ -85,7 +85,7 @@ pub(crate) fn extract_struct_from_enum_variant( let list_range = field_list.syntax().text_range(); update_variant(edit, &variant_name, ctx.frange.file_id, list_range); }, - ); + ) } fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool { -- cgit v1.2.3 From e0e9c6d1a4cfdd4410b802ad8db1e29c9f1b4291 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 13:04:35 +0200 Subject: Fix wrong comment --- crates/ra_hir_def/src/import_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 7dae64efa..7c8c4b6cb 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -281,7 +281,7 @@ mod tests { #[test] fn cyclic_module_reexport() { - // Reexporting modules from a dependency adds all contents to the import map. + // A cyclic reexport does not hang. let map = import_map( r" //- /lib.rs crate:lib -- cgit v1.2.3 From 86fbd8cc2b71f473b9e6d41f4fe3e1a114f1f992 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 13:05:19 +0200 Subject: defining_crate -> krate --- crates/ra_hir_def/src/find_path.rs | 2 +- crates/ra_hir_def/src/item_scope.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 79f4afab6..e6cd89478 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -128,7 +128,7 @@ pub(crate) fn find_path_inner( let mut best_path = None; let mut best_path_len = max_len; - if item.defining_crate(db) == Some(from.krate) { + if item.krate(db) == Some(from.krate) { // Item was defined in the same crate that wants to import it. It cannot be found in any // dependency in this case. diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index ede1aa045..d340e1f13 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs @@ -205,7 +205,8 @@ impl ItemInNs { } } - pub fn defining_crate(&self, db: &dyn DefDatabase) -> Option { + /// Returns the crate defining this item (or `None` if `self` is built-in). + pub fn krate(&self, db: &dyn DefDatabase) -> Option { Some(match self { ItemInNs::Types(did) | ItemInNs::Values(did) => match did { ModuleDefId::ModuleId(id) => id.krate, -- cgit v1.2.3 From f085e592fe4ddd47c20e96a944c5902ff8a2f439 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 13:10:43 +0200 Subject: Measure memory usage of ImportMap --- crates/ra_hir/src/db.rs | 10 +++++----- crates/ra_ide_db/src/change.rs | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index ec931b34f..098b66529 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -3,11 +3,11 @@ pub use hir_def::db::{ AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery, CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, - ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternConstQuery, - InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, - InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, - LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery, - TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, + ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, + InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, + InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, + InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, + StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, }; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 8446ef88e..ea78e49e0 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -334,6 +334,7 @@ impl RootDatabase { hir::db::CrateLangItemsQuery hir::db::LangItemQuery hir::db::DocumentationQuery + hir::db::ImportMapQuery // InternDatabase hir::db::InternFunctionQuery -- cgit v1.2.3 From 5f23f8ca449e456087d0657f925837bfb1a3f5ec Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 13:11:53 +0200 Subject: Make `find_path_inner` private again --- crates/ra_hir_def/src/find_path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index e6cd89478..d6ae970dc 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -37,7 +37,7 @@ impl ModPath { } } -pub(crate) fn find_path_inner( +fn find_path_inner( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, -- cgit v1.2.3 From 8395396782e343c6fe6bd318c74e8c9884b22323 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 13:15:16 +0200 Subject: Reorder imports --- crates/ra_hir_def/src/find_path.rs | 2 +- crates/ra_hir_def/src/import_map.rs | 8 +++++--- crates/ra_hir_def/src/item_scope.rs | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index d6ae970dc..a7f59e028 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -2,6 +2,7 @@ use hir_expand::name::{known, AsName, Name}; use ra_prof::profile; +use rustc_hash::FxHashSet; use test_utils::mark; use crate::{ @@ -11,7 +12,6 @@ use crate::{ visibility::Visibility, ModuleDefId, ModuleId, }; -use rustc_hash::FxHashSet; // FIXME: handle local items diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 7c8c4b6cb..1c812a19a 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -1,5 +1,10 @@ //! A map of all publicly exported items in a crate. +use std::{collections::hash_map::Entry, sync::Arc}; + +use ra_db::CrateId; +use rustc_hash::FxHashMap; + use crate::{ db::DefDatabase, item_scope::ItemInNs, @@ -7,9 +12,6 @@ use crate::{ visibility::Visibility, ModuleDefId, ModuleId, }; -use ra_db::CrateId; -use rustc_hash::FxHashMap; -use std::{collections::hash_map::Entry, sync::Arc}; /// A map from publicly exported items to the path needed to import/name them from a downstream /// crate. diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index d340e1f13..b03ba939a 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs @@ -3,13 +3,13 @@ use hir_expand::name::Name; use once_cell::sync::Lazy; +use ra_db::CrateId; use rustc_hash::FxHashMap; use crate::{ db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, Lookup, MacroDefId, ModuleDefId, TraitId, }; -use ra_db::CrateId; #[derive(Debug, Default, PartialEq, Eq)] pub struct ItemScope { -- cgit v1.2.3 From 5dda9955380c6214aa5720ad640b76b870aaa556 Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Fri, 5 Jun 2020 13:17:17 +0200 Subject: Fix review comments --- .../handlers/extract_struct_from_enum_variant.rs | 41 ++++++++++------------ crates/ra_assists/src/utils/insert_use.rs | 11 +----- 2 files changed, 19 insertions(+), 33 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index ef963ddba..2c455a1fd 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -1,6 +1,4 @@ -use ra_ide_db::{ - defs::Definition, imports_locator::ImportsLocator, search::Reference, RootDatabase, -}; +use ra_ide_db::{defs::Definition, search::Reference, RootDatabase}; use ra_syntax::{ algo::find_node_at_offset, ast::{self, AstNode, NameOwner}, @@ -9,11 +7,11 @@ use ra_syntax::{ use crate::{ assist_context::{AssistBuilder, AssistDirector}, - utils::insert_use::insert_use_statement_with_string_path, + utils::insert_use_statement, AssistContext, AssistId, Assists, }; use ast::{ArgListOwner, VisibilityOwner}; -use hir::{EnumVariant, Module, ModuleDef}; +use hir::{EnumVariant, Module, ModuleDef, Name}; use ra_db::FileId; use ra_fmt::leading_indent; use rustc_hash::FxHashSet; @@ -46,11 +44,11 @@ pub(crate) fn extract_struct_from_enum_variant( return None; } let enum_ast = variant.parent_enum(); - let enum_name = enum_ast.name()?.to_string(); let visibility = enum_ast.visibility(); - let current_module_def = - ImportsLocator::new(ctx.db).find_imports(&enum_name).first()?.left()?; - let current_module = current_module_def.module(ctx.db)?; + let enum_hir = ctx.sema.to_def(&enum_ast)?; + let variant_hir_name = variant_hir.name(ctx.db); + let enum_module_def = ModuleDef::from(enum_hir); + let current_module = enum_hir.module(ctx.db); let target = variant.syntax().text_range(); acc.add_in_multiple_files( AssistId("extract_struct_from_enum_variant"), @@ -69,7 +67,8 @@ pub(crate) fn extract_struct_from_enum_variant( edit, reference, &source_file, - ¤t_module_def, + &enum_module_def, + &variant_hir_name, &mut visited_modules_set, ); } @@ -102,20 +101,15 @@ fn insert_import( builder: &mut AssistBuilder, path: &ast::PathExpr, module: &Module, - module_def: &ModuleDef, - path_segment: ast::NameRef, + enum_module_def: &ModuleDef, + variant_hir_name: &Name, ) -> Option<()> { let db = ctx.db; - let mod_path = module.find_use_path(db, module_def.clone()); + let mod_path = module.find_use_path(db, enum_module_def.clone()); if let Some(mut mod_path) = mod_path { mod_path.segments.pop(); - let use_path = format!("{}::{}", mod_path.to_string(), path_segment.to_string()); - insert_use_statement_with_string_path( - path.syntax(), - &use_path, - ctx, - builder.text_edit_builder(), - ); + mod_path.segments.push(variant_hir_name.clone()); + insert_use_statement(path.syntax(), &mod_path, ctx, builder.text_edit_builder()); } Some(()) } @@ -175,7 +169,8 @@ fn update_reference( edit: &mut AssistDirector, reference: Reference, source_file: &SourceFile, - module_def: &ModuleDef, + enum_module_def: &ModuleDef, + variant_hir_name: &Name, visited_modules_set: &mut FxHashSet, ) -> Option<()> { let path_expr: ast::PathExpr = find_node_at_offset::( @@ -185,7 +180,6 @@ fn update_reference( let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; let list = call.arg_list()?; let segment = path_expr.path()?.segment()?; - let segment_name = segment.name_ref()?; let module = ctx.sema.scope(&path_expr.syntax()).module()?; let list_range = list.syntax().text_range(); let inside_list_range = TextRange::new( @@ -194,7 +188,8 @@ fn update_reference( ); edit.perform(reference.file_range.file_id, |builder| { if !visited_modules_set.contains(&module) { - if insert_import(ctx, builder, &path_expr, &module, module_def, segment_name).is_some() + if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name) + .is_some() { visited_modules_set.insert(module); } diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index 114f5949a..0ee43482f 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs @@ -23,16 +23,7 @@ pub(crate) fn insert_use_statement( ctx: &AssistContext, builder: &mut TextEditBuilder, ) { - insert_use_statement_with_string_path(position, &path_to_import.to_string(), ctx, builder); -} - -pub(crate) fn insert_use_statement_with_string_path( - position: &SyntaxNode, - path_to_import: &str, - ctx: &AssistContext, - builder: &mut TextEditBuilder, -) { - let target = path_to_import.split("::").map(SmolStr::new).collect::>(); + let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::>(); let container = ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| { if let Some(module) = ast::Module::cast(n.clone()) { return module.item_list().map(|it| it.syntax().clone()); -- cgit v1.2.3 From 2fb3d87bf77826f213d2876c921308e9f168ca63 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 13:36:19 +0200 Subject: impl Debug for ImportMap --- crates/ra_hir_def/src/import_map.rs | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 1c812a19a..70749f380 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -1,6 +1,6 @@ //! A map of all publicly exported items in a crate. -use std::{collections::hash_map::Entry, sync::Arc}; +use std::{collections::hash_map::Entry, fmt, sync::Arc}; use ra_db::CrateId; use rustc_hash::FxHashMap; @@ -21,7 +21,7 @@ use crate::{ /// /// Note that all paths are relative to the containing crate's root, so the crate name still needs /// to be prepended to the `ModPath` before the path is valid. -#[derive(Debug, Eq, PartialEq)] +#[derive(Eq, PartialEq)] pub struct ImportMap { map: FxHashMap, } @@ -95,6 +95,26 @@ impl ImportMap { } } +impl fmt::Debug for ImportMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut importable_paths: Vec<_> = self + .map + .iter() + .map(|(item, modpath)| { + let ns = match item { + ItemInNs::Types(_) => "t", + ItemInNs::Values(_) => "v", + ItemInNs::Macros(_) => "m", + }; + format!("- {} ({})", modpath, ns) + }) + .collect(); + + importable_paths.sort(); + f.write_str(&importable_paths.join("\n")) + } +} + #[cfg(test)] mod tests { use super::*; @@ -115,23 +135,7 @@ mod tests { let map = db.import_map(krate); - let mut importable_paths: Vec<_> = map - .map - .iter() - .map(|(item, modpath)| { - let ns = match item { - ItemInNs::Types(_) => "t", - ItemInNs::Values(_) => "v", - ItemInNs::Macros(_) => "m", - }; - format!("- {} ({})", modpath, ns) - }) - .collect(); - - importable_paths.sort(); - let importable_paths = importable_paths.join("\n"); - - Some(format!("{}:\n{}", name, importable_paths)) + Some(format!("{}:\n{:?}", name, map)) }) .collect(); -- cgit v1.2.3 From 522d24a607c100fdc12fa6650807a1dfcb0f4b12 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 5 Jun 2020 13:58:52 +0200 Subject: Inlay Hints: more directly account for self param --- crates/ra_ide/src/inlay_hints.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 75bd3c96b..49366de98 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs @@ -149,11 +149,10 @@ fn get_param_name_hints( ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(), _ => return None, }; - let args_count = args.clone().count(); let fn_signature = get_fn_signature(sema, &expr)?; let n_params_to_skip = - if fn_signature.has_self_param && fn_signature.parameter_names.len() > args_count { + if fn_signature.has_self_param && matches!(&expr, ast::Expr::MethodCallExpr(_)) { 1 } else { 0 -- cgit v1.2.3 From 7d0dd17b09240385333805637ea17992a8089cf2 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 3 Jun 2020 14:15:54 +0300 Subject: Add hover actions as LSP extension --- crates/ra_ide/src/hover.rs | 134 ++++++++++++++++++++++--- crates/ra_ide/src/lib.rs | 2 +- crates/ra_ide_db/src/defs.rs | 2 +- crates/rust-analyzer/src/config.rs | 28 ++++-- crates/rust-analyzer/src/lsp_ext.rs | 34 +++++++ crates/rust-analyzer/src/main_loop.rs | 2 +- crates/rust-analyzer/src/main_loop/handlers.rs | 119 +++++++++++++++++----- 7 files changed, 272 insertions(+), 49 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 9636cd0d6..baa9fc8a8 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -13,14 +13,43 @@ use ra_ide_db::{ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; use crate::{ - display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, - FilePosition, RangeInfo, + display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, + FilePosition, RangeInfo, NavigationTarget, }; +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct HoverConfig { + pub implementations: bool, +} + +impl Default for HoverConfig { + fn default() -> Self { + Self { implementations: true } + } +} + +impl HoverConfig { + pub const NO_ACTIONS: Self = Self { implementations: false }; + + pub fn any(&self) -> bool { + self.implementations + } + + pub fn none(&self) -> bool { + !self.any() + } +} + +#[derive(Debug, Clone)] +pub enum HoverAction { + Implementaion(FilePosition), +} + /// Contains the results when hovering over an item #[derive(Debug, Default)] pub struct HoverResult { results: Vec, + actions: Vec, } impl HoverResult { @@ -48,10 +77,20 @@ impl HoverResult { &self.results } + pub fn actions(&self) -> &[HoverAction] { + &self.actions + } + + pub fn push_action(&mut self, action: HoverAction) { + self.actions.push(action); + } + /// Returns the results converted into markup /// for displaying in a UI + /// + /// Does not process actions! pub fn to_markup(&self) -> String { - self.results.join("\n\n---\n") + self.results.join("\n\n___\n") } } @@ -82,6 +121,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option Option Option { + fn to_action(nav_target: NavigationTarget) -> HoverAction { + HoverAction::Implementaion(FilePosition { + file_id: nav_target.file_id(), + offset: nav_target.range().start(), + }) + } + + match def { + Definition::ModuleDef(it) => match it { + ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), + ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), + ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), + ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), + _ => None, + }, + _ => None, + } +} + fn hover_text( docs: Option, desc: Option, @@ -228,6 +291,8 @@ fn pick_best(tokens: TokenAtOffset) -> Option { #[cfg(test)] mod tests { + use super::*; + use ra_db::FileLoader; use ra_syntax::TextRange; @@ -241,7 +306,14 @@ mod tests { s.map(trim_markup) } - fn check_hover_result(fixture: &str, expected: &[&str]) -> String { + fn assert_impl_action(action: &HoverAction, position: u32) { + let offset = match action { + HoverAction::Implementaion(pos) => pos.offset + }; + assert_eq!(offset, position.into()); + } + + fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec) { let (analysis, position) = analysis_and_position(fixture); let hover = analysis.hover(position).unwrap().unwrap(); let mut results = Vec::from(hover.info.results()); @@ -256,7 +328,7 @@ mod tests { assert_eq!(hover.info.len(), expected.len()); let content = analysis.db.file_text(position.file_id); - content[hover.range].to_string() + (content[hover.range].to_string(), hover.info.actions().to_vec()) } fn check_hover_no_result(fixture: &str) { @@ -746,7 +818,7 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_through_macro() { - let hover_on = check_hover_result( + let (hover_on, _) = check_hover_result( " //- /lib.rs macro_rules! id { @@ -767,7 +839,7 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_through_expr_in_macro() { - let hover_on = check_hover_result( + let (hover_on, _) = check_hover_result( " //- /lib.rs macro_rules! id { @@ -785,7 +857,7 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_through_expr_in_macro_recursive() { - let hover_on = check_hover_result( + let (hover_on, _) = check_hover_result( " //- /lib.rs macro_rules! id_deep { @@ -806,7 +878,7 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_through_func_in_macro_recursive() { - let hover_on = check_hover_result( + let (hover_on, _) = check_hover_result( " //- /lib.rs macro_rules! id_deep { @@ -830,7 +902,7 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_through_literal_string_in_macro() { - let hover_on = check_hover_result( + let (hover_on, _) = check_hover_result( r#" //- /lib.rs macro_rules! arr { @@ -849,7 +921,7 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_through_assert_macro() { - let hover_on = check_hover_result( + let (hover_on, _) = check_hover_result( r#" //- /lib.rs #[rustc_builtin_macro] @@ -925,13 +997,14 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_trait_show_qualifiers() { - check_hover_result( + let (_, actions) = check_hover_result( " //- /lib.rs unsafe trait foo<|>() {} ", &["unsafe trait foo"], ); + assert_impl_action(&actions[0], 13); } #[test] @@ -1052,4 +1125,41 @@ fn func(foo: i32) { if true { <|>foo; }; } &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], ); } + + #[test] + fn test_hover_trait_hash_impl_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait foo<|>() {} + ", + &["trait foo"], + ); + assert_impl_action(&actions[0], 6); + } + + #[test] + fn test_hover_struct_hash_impl_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + struct foo<|>() {} + ", + &["struct foo"], + ); + assert_impl_action(&actions[0], 7); + } + + #[test] + fn test_hover_union_hash_impl_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + union foo<|>() {} + ", + &["union foo"], + ); + assert_impl_action(&actions[0], 6); + } + } diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 34c2d75fe..a9601400f 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -66,7 +66,7 @@ pub use crate::{ display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, expand_macro::ExpandedMacro, folding_ranges::{Fold, FoldKind}, - hover::HoverResult, + hover::{HoverResult, HoverAction, HoverConfig}, inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, runnables::{Runnable, RunnableKind, TestId}, diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 8b06cbfc5..1db60b87f 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -18,7 +18,7 @@ use ra_syntax::{ use crate::RootDatabase; // FIXME: a more precise name would probably be `Symbol`? -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Definition { Macro(MacroDef), Field(Field), diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 23168c3ae..e7c859577 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -11,7 +11,7 @@ use std::{ffi::OsString, path::PathBuf}; use lsp_types::ClientCapabilities; use ra_flycheck::FlycheckConfig; -use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; +use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig, HoverConfig}; use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; use serde::Deserialize; @@ -34,6 +34,7 @@ pub struct Config { pub assist: AssistConfig, pub call_info_full: bool, pub lens: LensConfig, + pub hover: HoverConfig, pub with_sysroot: bool, pub linked_projects: Vec, @@ -124,6 +125,7 @@ pub struct ClientCapsConfig { pub work_done_progress: bool, pub code_action_group: bool, pub resolve_code_action: bool, + pub hover_actions: bool, } impl Default for Config { @@ -162,6 +164,7 @@ impl Default for Config { assist: AssistConfig::default(), call_info_full: true, lens: LensConfig::default(), + hover: HoverConfig::default(), linked_projects: Vec::new(), } } @@ -278,6 +281,14 @@ impl Config { } } + let mut use_hover_actions = false; + set(value, "/hoverActions/enable", &mut use_hover_actions); + if use_hover_actions { + set(value, "/hoverActions/implementations", &mut self.hover.implementations); + } else { + self.hover = HoverConfig::NO_ACTIONS; + } + log::info!("Config::update() = {:#?}", self); fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option { @@ -331,17 +342,14 @@ impl Config { self.assist.allow_snippets(false); if let Some(experimental) = &caps.experimental { - let snippet_text_edit = - experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); - self.assist.allow_snippets(snippet_text_edit); + let get_bool = |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true); - let code_action_group = - experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true); - self.client_caps.code_action_group = code_action_group; + let snippet_text_edit = get_bool("snippetTextEdit"); + self.assist.allow_snippets(snippet_text_edit); - let resolve_code_action = - experimental.get("resolveCodeAction").and_then(|it| it.as_bool()) == Some(true); - self.client_caps.resolve_code_action = resolve_code_action; + self.client_caps.code_action_group = get_bool("codeActionGroup"); + self.client_caps.resolve_code_action = get_bool("resolveCodeAction"); + self.client_caps.hover_actions = get_bool("hoverActions"); } } } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 3b957534d..145a389ce 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -260,3 +260,37 @@ pub struct SnippetTextEdit { #[serde(skip_serializing_if = "Option::is_none")] pub insert_text_format: Option, } + +pub enum HoverRequest {} + +impl Request for HoverRequest { + type Params = lsp_types::HoverParams; + type Result = Option; + const METHOD: &'static str = "textDocument/hover"; +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct Hover { + pub contents: lsp_types::HoverContents, + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub actions: Option>, +} + +#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)] +pub struct CommandLinkGroup { + pub title: Option, + pub commands: Vec, +} + +// LSP v3.15 Command does not have a `tooltip` field, vscode supports one. +#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)] +pub struct CommandLink { + pub title: String, + pub command: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option>, +} diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index e60337b8e..752dbf145 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -510,6 +510,7 @@ fn on_request( .on::(handlers::handle_inlay_hints)? .on::(handlers::handle_code_action)? .on::(handlers::handle_resolve_code_action)? + .on::(handlers::handle_hover)? .on::(handlers::handle_on_type_formatting)? .on::(handlers::handle_document_symbol)? .on::(handlers::handle_workspace_symbol)? @@ -521,7 +522,6 @@ fn on_request( .on::(handlers::handle_code_lens_resolve)? .on::(handlers::handle_folding_range)? .on::(handlers::handle_signature_help)? - .on::(handlers::handle_hover)? .on::(handlers::handle_prepare_rename)? .on::(handlers::handle_rename)? .on::(handlers::handle_references)? diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 6acf80c58..0958a231f 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -12,13 +12,14 @@ use lsp_types::{ CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, - DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, - MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, - SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, - SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, + DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, MarkupContent, + MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams, + SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, + TextDocumentIdentifier, Url, WorkspaceEdit, }; use ra_ide::{ - FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit, + FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, RunnableKind, SearchScope, + TextEdit, }; use ra_prof::profile; use ra_project_model::TargetKind; @@ -537,7 +538,7 @@ pub fn handle_signature_help( pub fn handle_hover( snap: GlobalStateSnapshot, params: lsp_types::HoverParams, -) -> Result> { +) -> Result> { let _p = profile("handle_hover"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let info = match snap.analysis().hover(position)? { @@ -546,12 +547,13 @@ pub fn handle_hover( }; let line_index = snap.analysis.file_line_index(position.file_id)?; let range = to_proto::range(&line_index, info.range); - let res = Hover { + let res = lsp_ext::Hover { contents: HoverContents::Markup(MarkupContent { kind: MarkupKind::Markdown, value: crate::markdown::format_docs(&info.info.to_markup()), }), range: Some(range), + actions: Some(prepare_hover_actions(&world, info.info.actions())), }; Ok(Some(res)) } @@ -924,24 +926,13 @@ pub fn handle_code_lens_resolve( _ => vec![], }; - let title = if locations.len() == 1 { - "1 implementation".into() - } else { - format!("{} implementations", locations.len()) - }; - - // We cannot use the 'editor.action.showReferences' command directly - // because that command requires vscode types which we convert in the handler - // on the client side. - let cmd = Command { + let title = implementation_title(locations.len()); + let cmd = show_references_command( title, - command: "rust-analyzer.showReferences".into(), - arguments: Some(vec![ - to_value(&lens_params.text_document_position_params.text_document.uri).unwrap(), - to_value(code_lens.range.start).unwrap(), - to_value(locations).unwrap(), - ]), - }; + &lens_params.text_document_position_params.text_document.uri, + code_lens.range.start, + locations, + ); Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) } None => Ok(CodeLens { @@ -1145,3 +1136,83 @@ pub fn handle_semantic_tokens_range( let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); Ok(Some(semantic_tokens.into())) } + +fn implementation_title(count: usize) -> String { + if count == 1 { + "1 implementation".into() + } else { + format!("{} implementations", count) + } +} + +fn show_references_command( + title: String, + uri: &lsp_types::Url, + position: lsp_types::Position, + locations: Vec, +) -> Command { + // We cannot use the 'editor.action.showReferences' command directly + // because that command requires vscode types which we convert in the handler + // on the client side. + + Command { + title, + command: "rust-analyzer.showReferences".into(), + arguments: Some(vec![ + to_value(uri).unwrap(), + to_value(position).unwrap(), + to_value(locations).unwrap(), + ]), + } +} + +fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { + lsp_ext::CommandLink { + tooltip: Some(tooltip), + title: command.title, + command: command.command, + arguments: command.arguments, + } +} + +fn show_impl_command_link( + world: &WorldSnapshot, + position: &FilePosition, +) -> Option { + if world.config.hover.implementations { + if let Some(nav_data) = world.analysis().goto_implementation(*position).unwrap_or(None) { + let uri = to_proto::url(world, position.file_id).ok()?; + let line_index = world.analysis().file_line_index(position.file_id).ok()?; + let position = to_proto::position(&line_index, position.offset); + let locations: Vec<_> = nav_data + .info + .iter() + .filter_map(|it| to_proto::location(world, it.file_range()).ok()) + .collect(); + let title = implementation_title(locations.len()); + let command = show_references_command(title, &uri, position, locations); + + return Some(lsp_ext::CommandLinkGroup { + commands: vec![to_command_link(command, "Go to implementations".into())], + ..Default::default() + }); + } + } + None +} + +fn prepare_hover_actions( + world: &WorldSnapshot, + actions: &[HoverAction], +) -> Vec { + if world.config.hover.none() || !world.config.client_caps.hover_actions { + return Vec::new(); + } + + actions + .iter() + .filter_map(|it| match it { + HoverAction::Implementaion(position) => show_impl_command_link(world, position), + }) + .collect() +} -- cgit v1.2.3 From b147e6eb95b8bbc8cd9a56f9a9a629b8671bdc0e Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 3 Jun 2020 14:44:40 +0300 Subject: Code formatting --- crates/ra_ide/src/hover.rs | 5 ++--- crates/ra_ide/src/lib.rs | 2 +- crates/rust-analyzer/src/config.rs | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index baa9fc8a8..2b9095a82 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -14,7 +14,7 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs use crate::{ display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, - FilePosition, RangeInfo, NavigationTarget, + FilePosition, NavigationTarget, RangeInfo, }; #[derive(Clone, Debug, PartialEq, Eq)] @@ -308,7 +308,7 @@ mod tests { fn assert_impl_action(action: &HoverAction, position: u32) { let offset = match action { - HoverAction::Implementaion(pos) => pos.offset + HoverAction::Implementaion(pos) => pos.offset, }; assert_eq!(offset, position.into()); } @@ -1161,5 +1161,4 @@ fn func(foo: i32) { if true { <|>foo; }; } ); assert_impl_action(&actions[0], 6); } - } diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index a9601400f..a56718d3f 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -66,7 +66,7 @@ pub use crate::{ display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, expand_macro::ExpandedMacro, folding_ranges::{Fold, FoldKind}, - hover::{HoverResult, HoverAction, HoverConfig}, + hover::{HoverAction, HoverConfig, HoverResult}, inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, runnables::{Runnable, RunnableKind, TestId}, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index e7c859577..14c4fe9ad 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -11,7 +11,7 @@ use std::{ffi::OsString, path::PathBuf}; use lsp_types::ClientCapabilities; use ra_flycheck::FlycheckConfig; -use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig, HoverConfig}; +use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; use serde::Deserialize; @@ -342,7 +342,8 @@ impl Config { self.assist.allow_snippets(false); if let Some(experimental) = &caps.experimental { - let get_bool = |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true); + let get_bool = + |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true); let snippet_text_edit = get_bool("snippetTextEdit"); self.assist.allow_snippets(snippet_text_edit); -- cgit v1.2.3 From 5d0c1aa1625a17723209e537590dc7fc7f181df1 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 3 Jun 2020 15:13:26 +0300 Subject: Rebase on the latest master. --- crates/ra_ide/src/hover.rs | 6 +++--- crates/rust-analyzer/src/main_loop/handlers.rs | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 2b9095a82..2fbe0ba1f 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1127,7 +1127,7 @@ fn func(foo: i32) { if true { <|>foo; }; } } #[test] - fn test_hover_trait_hash_impl_action() { + fn test_hover_trait_has_impl_action() { let (_, actions) = check_hover_result( " //- /lib.rs @@ -1139,7 +1139,7 @@ fn func(foo: i32) { if true { <|>foo; }; } } #[test] - fn test_hover_struct_hash_impl_action() { + fn test_hover_struct_has_impl_action() { let (_, actions) = check_hover_result( " //- /lib.rs @@ -1151,7 +1151,7 @@ fn func(foo: i32) { if true { <|>foo; }; } } #[test] - fn test_hover_union_hash_impl_action() { + fn test_hover_union_has_impl_action() { let (_, actions) = check_hover_result( " //- /lib.rs diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 0958a231f..d998d9ddd 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -553,7 +553,7 @@ pub fn handle_hover( value: crate::markdown::format_docs(&info.info.to_markup()), }), range: Some(range), - actions: Some(prepare_hover_actions(&world, info.info.actions())), + actions: Some(prepare_hover_actions(&snap, info.info.actions())), }; Ok(Some(res)) } @@ -1176,18 +1176,18 @@ fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { } fn show_impl_command_link( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, position: &FilePosition, ) -> Option { - if world.config.hover.implementations { - if let Some(nav_data) = world.analysis().goto_implementation(*position).unwrap_or(None) { - let uri = to_proto::url(world, position.file_id).ok()?; - let line_index = world.analysis().file_line_index(position.file_id).ok()?; + if snap.config.hover.implementations { + if let Some(nav_data) = snap.analysis().goto_implementation(*position).unwrap_or(None) { + let uri = to_proto::url(snap, position.file_id).ok()?; + let line_index = snap.analysis().file_line_index(position.file_id).ok()?; let position = to_proto::position(&line_index, position.offset); let locations: Vec<_> = nav_data .info .iter() - .filter_map(|it| to_proto::location(world, it.file_range()).ok()) + .filter_map(|it| to_proto::location(snap, it.file_range()).ok()) .collect(); let title = implementation_title(locations.len()); let command = show_references_command(title, &uri, position, locations); @@ -1202,17 +1202,17 @@ fn show_impl_command_link( } fn prepare_hover_actions( - world: &WorldSnapshot, + snap: &GlobalStateSnapshot, actions: &[HoverAction], ) -> Vec { - if world.config.hover.none() || !world.config.client_caps.hover_actions { + if snap.config.hover.none() || !snap.config.client_caps.hover_actions { return Vec::new(); } actions .iter() .filter_map(|it| match it { - HoverAction::Implementaion(position) => show_impl_command_link(world, position), + HoverAction::Implementaion(position) => show_impl_command_link(snap, position), }) .collect() } -- cgit v1.2.3 From 92cfc0f2a1edd4e825d4dea96d4f96dcea513629 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 3 Jun 2020 15:29:03 +0300 Subject: Add enum hover action test. --- crates/ra_ide/src/hover.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 2fbe0ba1f..62df07459 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1161,4 +1161,19 @@ fn func(foo: i32) { if true { <|>foo; }; } ); assert_impl_action(&actions[0], 6); } + + #[test] + fn test_hover_enum_has_impl_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + enum foo<|>() { + A, + B + } + ", + &["enum foo"], + ); + assert_impl_action(&actions[0], 5); + } } -- cgit v1.2.3 From e35418ceb9b07bd596cc09144f4f4df13432a712 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 3 Jun 2020 16:39:32 +0300 Subject: Apply suggestions from @kjeremy review --- crates/rust-analyzer/src/lsp_ext.rs | 16 +++++++--------- crates/rust-analyzer/src/main_loop/handlers.rs | 21 +++++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 145a389ce..75ea48892 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -271,26 +271,24 @@ impl Request for HoverRequest { #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] pub struct Hover { - pub contents: lsp_types::HoverContents, - #[serde(skip_serializing_if = "Option::is_none")] - pub range: Option, + #[serde(flatten)] + pub hover: lsp_types::Hover, #[serde(skip_serializing_if = "Option::is_none")] pub actions: Option>, } -#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)] +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] pub struct CommandLinkGroup { + #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, pub commands: Vec, } // LSP v3.15 Command does not have a `tooltip` field, vscode supports one. -#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)] +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] pub struct CommandLink { - pub title: String, - pub command: String, + #[serde(flatten)] + pub command: lsp_types::Command, #[serde(skip_serializing_if = "Option::is_none")] pub tooltip: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub arguments: Option>, } diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index d998d9ddd..894df5837 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -547,15 +547,18 @@ pub fn handle_hover( }; let line_index = snap.analysis.file_line_index(position.file_id)?; let range = to_proto::range(&line_index, info.range); - let res = lsp_ext::Hover { - contents: HoverContents::Markup(MarkupContent { - kind: MarkupKind::Markdown, - value: crate::markdown::format_docs(&info.info.to_markup()), - }), - range: Some(range), + let hover = lsp_ext::Hover { + hover: lsp_types::Hover { + contents: HoverContents::Markup(MarkupContent { + kind: MarkupKind::Markdown, + value: crate::markdown::format_docs(&info.info.to_markup()), + }), + range: Some(range), + }, actions: Some(prepare_hover_actions(&snap, info.info.actions())), }; - Ok(Some(res)) + + Ok(Some(hover)) } pub fn handle_prepare_rename( @@ -1169,9 +1172,7 @@ fn show_references_command( fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { lsp_ext::CommandLink { tooltip: Some(tooltip), - title: command.title, - command: command.command, - arguments: command.arguments, + command, } } -- cgit v1.2.3 From 0fe43a124bb2b135cfd1268fda2941c3ac170c96 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 3 Jun 2020 17:35:26 +0300 Subject: Add capabilities tests. --- crates/rust-analyzer/src/lsp_ext.rs | 4 +- crates/rust-analyzer/src/main_loop/handlers.rs | 7 +- crates/rust-analyzer/tests/heavy_tests/main.rs | 180 +++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 75ea48892..1371f6cb4 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -273,8 +273,8 @@ impl Request for HoverRequest { pub struct Hover { #[serde(flatten)] pub hover: lsp_types::Hover, - #[serde(skip_serializing_if = "Option::is_none")] - pub actions: Option>, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub actions: Vec, } #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 894df5837..3ff779702 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -555,7 +555,7 @@ pub fn handle_hover( }), range: Some(range), }, - actions: Some(prepare_hover_actions(&snap, info.info.actions())), + actions: prepare_hover_actions(&snap, info.info.actions()), }; Ok(Some(hover)) @@ -1170,10 +1170,7 @@ fn show_references_command( } fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { - lsp_ext::CommandLink { - tooltip: Some(tooltip), - command, - } + lsp_ext::CommandLink { tooltip: Some(tooltip), command } } fn show_impl_command_link( diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index ad3476310..78c6195d7 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -715,3 +715,183 @@ pub fn foo(_input: TokenStream) -> TokenStream { let value = res.get("contents").unwrap().get("value").unwrap().to_string(); assert_eq!(value, r#""```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#) } + +#[test] +fn test_client_support_hover_actions() { + if skip_slow_tests() { + return; + } + + let server = Project::with_fixture( + r#" +//- Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- src/lib.rs +struct Foo(u32); + +struct NoImpl(u32); + +impl Foo { + fn new() -> Self { + Self(1) + } +} +"#, + ) + .with_config(|config| { + config.client_caps.hover_actions = true; + }) + .server(); + + server.wait_until_workspace_is_loaded(); + + // has 1 implementation + server.request::( + HoverParams { + text_document_position_params: TextDocumentPositionParams::new( + server.doc_id("src/lib.rs"), + Position::new(0, 9), + ), + work_done_progress_params: Default::default(), + }, + json!({ + "actions": [{ + "commands": [{ + "arguments": [ + "file:///[..]src/lib.rs", + { + "character": 7, + "line": 0 + }, + [{ + "range": { "end": { "character": 1, "line": 8 }, "start": { "character": 0, "line": 4 } }, + "uri": "file:///[..]src/lib.rs" + }] + ], + "command": "rust-analyzer.showReferences", + "title": "1 implementation", + "tooltip": "Go to implementations" + }] + }], + "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct Foo\n```" }, + "range": { "end": { "character": 10, "line": 0 }, "start": { "character": 7, "line": 0 } } + }) + ); + + // no hover + server.request::( + HoverParams { + text_document_position_params: TextDocumentPositionParams::new( + server.doc_id("src/lib.rs"), + Position::new(1, 0), + ), + work_done_progress_params: Default::default(), + }, + json!(null), + ); + + // no implementations + server.request::( + HoverParams { + text_document_position_params: TextDocumentPositionParams::new( + server.doc_id("src/lib.rs"), + Position::new(2, 12), + ), + work_done_progress_params: Default::default(), + }, + json!({ + "actions": [{ + "commands": [{ + "arguments": [ + "file:///[..]src/lib.rs", + { "character": 7, "line": 2 }, + [] + ], + "command": "rust-analyzer.showReferences", + "title": "0 implementations", + "tooltip": "Go to implementations" + }] + }], + "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct NoImpl\n```" }, + "range": { "end": { "character": 13, "line": 2 }, "start": { "character": 7, "line": 2 } } + }) + ); +} + +#[test] +fn test_client_does_not_support_hover_actions() { + if skip_slow_tests() { + return; + } + + let server = Project::with_fixture( + r#" +//- Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- src/lib.rs +struct Foo(u32); + +struct NoImpl(u32); + +impl Foo { + fn new() -> Self { + Self(1) + } +} +"#, + ) + .with_config(|config| { + config.client_caps.hover_actions = false; + }) + .server(); + + server.wait_until_workspace_is_loaded(); + + // has 1 implementation + server.request::( + HoverParams { + text_document_position_params: TextDocumentPositionParams::new( + server.doc_id("src/lib.rs"), + Position::new(0, 9), + ), + work_done_progress_params: Default::default(), + }, + json!({ + "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct Foo\n```" }, + "range": { "end": { "character": 10, "line": 0 }, "start": { "character": 7, "line": 0 } } + }) + ); + + // no hover + server.request::( + HoverParams { + text_document_position_params: TextDocumentPositionParams::new( + server.doc_id("src/lib.rs"), + Position::new(1, 0), + ), + work_done_progress_params: Default::default(), + }, + json!(null), + ); + + // no implementations + server.request::( + HoverParams { + text_document_position_params: TextDocumentPositionParams::new( + server.doc_id("src/lib.rs"), + Position::new(2, 12), + ), + work_done_progress_params: Default::default(), + }, + json!({ + "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct NoImpl\n```" }, + "range": { "end": { "character": 13, "line": 2 }, "start": { "character": 7, "line": 2 } } + }) + ); +} -- cgit v1.2.3 From bc2d1729957a25bf5ee8e2213d07460e22c76def Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Jun 2020 14:24:51 +0200 Subject: Clarify when we visit modules multiple times --- crates/ra_hir_def/src/import_map.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 70749f380..4284a0a91 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -78,7 +78,9 @@ impl ImportMap { } } - // If we've just added a path to a module, descend into it. + // If we've just added a path to a module, descend into it. We might traverse + // modules multiple times, but only if the new path to it is shorter than the + // first (else we `continue` above). if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { worklist.push((mod_id, mk_path())); } -- cgit v1.2.3 From 78c9223b7bd4bffe64b7ec69e5fee08604dc0057 Mon Sep 17 00:00:00 2001 From: vsrs Date: Fri, 5 Jun 2020 15:25:01 +0300 Subject: Remove hover contents marking as trusted. Hover contents might be extracted from raw doc comments and need some validation. --- crates/rust-analyzer/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 14c4fe9ad..8d6efdbe8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -349,7 +349,7 @@ impl Config { self.assist.allow_snippets(snippet_text_edit); self.client_caps.code_action_group = get_bool("codeActionGroup"); - self.client_caps.resolve_code_action = get_bool("resolveCodeAction"); + self.client_caps.resolve_code_action = get_bool("resolveCodeAction"); self.client_caps.hover_actions = get_bool("hoverActions"); } } -- cgit v1.2.3 From bd9d7b6ad885f775df91ff3dfebd8927c8e272b2 Mon Sep 17 00:00:00 2001 From: vsrs Date: Fri, 5 Jun 2020 15:26:46 +0300 Subject: Remove hover actions heavy tests. --- crates/rust-analyzer/tests/heavy_tests/main.rs | 180 ------------------------- 1 file changed, 180 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 78c6195d7..ad3476310 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -715,183 +715,3 @@ pub fn foo(_input: TokenStream) -> TokenStream { let value = res.get("contents").unwrap().get("value").unwrap().to_string(); assert_eq!(value, r#""```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#) } - -#[test] -fn test_client_support_hover_actions() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r#" -//- Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- src/lib.rs -struct Foo(u32); - -struct NoImpl(u32); - -impl Foo { - fn new() -> Self { - Self(1) - } -} -"#, - ) - .with_config(|config| { - config.client_caps.hover_actions = true; - }) - .server(); - - server.wait_until_workspace_is_loaded(); - - // has 1 implementation - server.request::( - HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(0, 9), - ), - work_done_progress_params: Default::default(), - }, - json!({ - "actions": [{ - "commands": [{ - "arguments": [ - "file:///[..]src/lib.rs", - { - "character": 7, - "line": 0 - }, - [{ - "range": { "end": { "character": 1, "line": 8 }, "start": { "character": 0, "line": 4 } }, - "uri": "file:///[..]src/lib.rs" - }] - ], - "command": "rust-analyzer.showReferences", - "title": "1 implementation", - "tooltip": "Go to implementations" - }] - }], - "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct Foo\n```" }, - "range": { "end": { "character": 10, "line": 0 }, "start": { "character": 7, "line": 0 } } - }) - ); - - // no hover - server.request::( - HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(1, 0), - ), - work_done_progress_params: Default::default(), - }, - json!(null), - ); - - // no implementations - server.request::( - HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(2, 12), - ), - work_done_progress_params: Default::default(), - }, - json!({ - "actions": [{ - "commands": [{ - "arguments": [ - "file:///[..]src/lib.rs", - { "character": 7, "line": 2 }, - [] - ], - "command": "rust-analyzer.showReferences", - "title": "0 implementations", - "tooltip": "Go to implementations" - }] - }], - "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct NoImpl\n```" }, - "range": { "end": { "character": 13, "line": 2 }, "start": { "character": 7, "line": 2 } } - }) - ); -} - -#[test] -fn test_client_does_not_support_hover_actions() { - if skip_slow_tests() { - return; - } - - let server = Project::with_fixture( - r#" -//- Cargo.toml -[package] -name = "foo" -version = "0.0.0" - -//- src/lib.rs -struct Foo(u32); - -struct NoImpl(u32); - -impl Foo { - fn new() -> Self { - Self(1) - } -} -"#, - ) - .with_config(|config| { - config.client_caps.hover_actions = false; - }) - .server(); - - server.wait_until_workspace_is_loaded(); - - // has 1 implementation - server.request::( - HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(0, 9), - ), - work_done_progress_params: Default::default(), - }, - json!({ - "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct Foo\n```" }, - "range": { "end": { "character": 10, "line": 0 }, "start": { "character": 7, "line": 0 } } - }) - ); - - // no hover - server.request::( - HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(1, 0), - ), - work_done_progress_params: Default::default(), - }, - json!(null), - ); - - // no implementations - server.request::( - HoverParams { - text_document_position_params: TextDocumentPositionParams::new( - server.doc_id("src/lib.rs"), - Position::new(2, 12), - ), - work_done_progress_params: Default::default(), - }, - json!({ - "contents": { "kind": "markdown", "value": "```rust\nfoo\n```\n\n```rust\nstruct NoImpl\n```" }, - "range": { "end": { "character": 13, "line": 2 }, "start": { "character": 7, "line": 2 } } - }) - ); -} -- cgit v1.2.3 From e63c00f100e960f7b72997026b4b2cd3cd29774b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 5 Jun 2020 14:55:23 +0200 Subject: Rename resolve_relative_path -> resolve_path For things like `concant!(env!("OUT_DIR"))`, we need to support abs paths --- crates/ra_db/src/lib.rs | 9 ++------- crates/ra_hir_def/src/nameres/mod_resolution.rs | 2 +- crates/ra_hir_def/src/test_db.rs | 8 ++------ crates/ra_hir_expand/src/builtin_macro.rs | 2 +- crates/ra_hir_expand/src/test_db.rs | 8 ++------ crates/ra_hir_ty/src/test_db.rs | 8 ++------ crates/ra_ide_db/src/lib.rs | 8 ++------ 7 files changed, 12 insertions(+), 33 deletions(-) (limited to 'crates') diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index fd4280de2..07e1b8aba 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -89,8 +89,7 @@ pub const DEFAULT_LRU_CAP: usize = 128; pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; - fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) - -> Option; + fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option; fn relevant_crates(&self, file_id: FileId) -> Arc>; fn resolve_extern_path( @@ -155,11 +154,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { fn file_text(&self, file_id: FileId) -> Arc { SourceDatabaseExt::file_text(self.0, file_id) } - fn resolve_relative_path( - &self, - anchor: FileId, - relative_path: &RelativePath, - ) -> Option { + fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { let path = { let mut path = self.0.file_relative_path(anchor); assert!(path.pop()); diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index 386c5cade..7af922c21 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs @@ -61,7 +61,7 @@ impl ModDir { }; for candidate in candidate_files.iter() { - if let Some(file_id) = db.resolve_relative_path(file_id, candidate) { + if let Some(file_id) = db.resolve_path(file_id, candidate) { let mut root_non_dir_owner = false; let mut mod_path = RelativePathBuf::new(); if !(candidate.ends_with("mod.rs") || attr_path.is_some()) { diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index eb83dee79..d33b57c93 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -58,12 +58,8 @@ impl FileLoader for TestDB { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_relative_path( - &self, - anchor: FileId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, relative_path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 3bce8f673..4374d9eda 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -297,7 +297,7 @@ fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Opti let call_site = call_id.as_file().original_file(db); // Handle trivial case - if let Some(res) = db.resolve_relative_path(call_site, &RelativePath::new(&path)) { + if let Some(res) = db.resolve_path(call_site, &RelativePath::new(&path)) { // Prevent include itself return if res == call_site { None } else { Some(res) }; } diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index c1fb762de..60321fa0a 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs @@ -41,12 +41,8 @@ impl FileLoader for TestDB { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_relative_path( - &self, - anchor: FileId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, relative_path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 8498d3d96..43927c991 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs @@ -72,12 +72,8 @@ impl FileLoader for TestDB { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_relative_path( - &self, - anchor: FileId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, relative_path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 1b74e6558..72793d63d 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -57,12 +57,8 @@ impl FileLoader for RootDatabase { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_relative_path( - &self, - anchor: FileId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, relative_path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) -- cgit v1.2.3 From bba374bab2ee53643a899e7ea459b4ab27663bd0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 5 Jun 2020 15:07:30 +0200 Subject: More direct signature for resolve_path --- crates/ra_db/src/lib.rs | 21 +++++++++++++-------- crates/ra_hir_def/src/nameres/mod_resolution.rs | 2 +- crates/ra_hir_def/src/test_db.rs | 4 ++-- crates/ra_hir_expand/src/builtin_macro.rs | 4 ++-- crates/ra_hir_expand/src/test_db.rs | 4 ++-- crates/ra_hir_ty/src/test_db.rs | 4 ++-- crates/ra_ide_db/src/lib.rs | 4 ++-- 7 files changed, 24 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 07e1b8aba..2e63cb46e 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -89,7 +89,7 @@ pub const DEFAULT_LRU_CAP: usize = 128; pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; - fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option; + fn resolve_path(&self, anchor: FileId, path: &str) -> Option; fn relevant_crates(&self, file_id: FileId) -> Arc>; fn resolve_extern_path( @@ -154,16 +154,21 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { fn file_text(&self, file_id: FileId) -> Arc { SourceDatabaseExt::file_text(self.0, file_id) } - fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { - let path = { - let mut path = self.0.file_relative_path(anchor); - assert!(path.pop()); - path.push(relative_path); - path.normalize() + /// Note that we intentionally accept a `&str` and not a `&Path` here. This + /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such, + /// so the input is guaranteed to be utf-8 string. We might introduce + /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we + /// get by with a `&str` for the time being. + fn resolve_path(&self, anchor: FileId, path: &str) -> Option { + let rel_path = { + let mut rel_path = self.0.file_relative_path(anchor); + assert!(rel_path.pop()); + rel_path.push(path); + rel_path.normalize() }; let source_root = self.0.file_source_root(anchor); let source_root = self.0.source_root(source_root); - source_root.file_by_relative_path(&path) + source_root.file_by_relative_path(&rel_path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index 7af922c21..cede4a6fc 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs @@ -61,7 +61,7 @@ impl ModDir { }; for candidate in candidate_files.iter() { - if let Some(file_id) = db.resolve_path(file_id, candidate) { + if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) { let mut root_non_dir_owner = false; let mut mod_path = RelativePathBuf::new(); if !(candidate.ends_with("mod.rs") || attr_path.is_some()) { diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index d33b57c93..e7a5182f0 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -58,8 +58,8 @@ impl FileLoader for TestDB { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { - FileLoaderDelegate(self).resolve_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, path: &str) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 4374d9eda..eec5fb8eb 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -8,7 +8,7 @@ use crate::{ use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; use either::Either; use mbe::parse_to_token_tree; -use ra_db::{FileId, RelativePath}; +use ra_db::FileId; use ra_parser::FragmentKind; macro_rules! register_builtin { @@ -297,7 +297,7 @@ fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Opti let call_site = call_id.as_file().original_file(db); // Handle trivial case - if let Some(res) = db.resolve_path(call_site, &RelativePath::new(&path)) { + if let Some(res) = db.resolve_path(call_site, path) { // Prevent include itself return if res == call_site { None } else { Some(res) }; } diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index 60321fa0a..765a2f6d1 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs @@ -41,8 +41,8 @@ impl FileLoader for TestDB { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { - FileLoaderDelegate(self).resolve_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, path: &str) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 43927c991..21a3bdfd1 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs @@ -72,8 +72,8 @@ impl FileLoader for TestDB { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { - FileLoaderDelegate(self).resolve_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, path: &str) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 72793d63d..93d5891a0 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -57,8 +57,8 @@ impl FileLoader for RootDatabase { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } - fn resolve_path(&self, anchor: FileId, relative_path: &RelativePath) -> Option { - FileLoaderDelegate(self).resolve_path(anchor, relative_path) + fn resolve_path(&self, anchor: FileId, path: &str) -> Option { + FileLoaderDelegate(self).resolve_path(anchor, path) } fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) -- cgit v1.2.3 From cb9d9040f7e5cb5971deabe3b66045010576a689 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 5 Jun 2020 15:14:47 +0200 Subject: Cleanup test --- crates/rust-analyzer/tests/heavy_tests/main.rs | 62 +++++--------------------- 1 file changed, 12 insertions(+), 50 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index ad3476310..237aaa2a1 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -523,8 +523,6 @@ fn main() { let vb = B; message(); } - -fn main() { message(); } "###, ) .with_config(|config| { @@ -552,34 +550,16 @@ fn main() { message(); } }, json!([{ "originSelectionRange": { - "end": { - "character": 10, - "line": 12 - }, - "start": { - "character": 8, - "line": 12 - } + "end": { "character": 10, "line": 12 }, + "start": { "character": 8, "line": 12 } }, "targetRange": { - "end": { - "character": 9, - "line": 3 - }, - "start": { - "character": 0, - "line": 2 - } + "end": { "character": 9, "line": 3 }, + "start": { "character": 0, "line": 2 } }, "targetSelectionRange": { - "end": { - "character": 8, - "line": 3 - }, - "start": { - "character": 7, - "line": 3 - } + "end": { "character": 8, "line": 3 }, + "start": { "character": 7, "line": 3 } }, "targetUri": "file:///[..]src/main.rs" }]), @@ -595,34 +575,16 @@ fn main() { message(); } }, json!([{ "originSelectionRange": { - "end": { - "character": 10, - "line": 13 - }, - "start": { - "character": 8, - "line":13 - } + "end": { "character": 10, "line": 13 }, + "start": { "character": 8, "line":13 } }, "targetRange": { - "end": { - "character": 9, - "line": 7 - }, - "start": { - "character": 0, - "line":6 - } + "end": { "character": 9, "line": 7 }, + "start": { "character": 0, "line":6 } }, "targetSelectionRange": { - "end": { - "character": 8, - "line": 7 - }, - "start": { - "character": 7, - "line": 7 - } + "end": { "character": 8, "line": 7 }, + "start": { "character": 7, "line": 7 } }, "targetUri": "file:///[..]src/main.rs" }]), -- cgit v1.2.3 From c9a41bd92d384ae7bd1e956d215b7e6c17c1b099 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 5 Jun 2020 15:49:12 +0200 Subject: Actually test include!(concant!(env!())); It triggered index-based goto definition before :-( --- crates/rust-analyzer/tests/heavy_tests/main.rs | 45 +++++++++++++------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 237aaa2a1..0e2a83c6a 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -4,9 +4,7 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; use lsp_types::{ notification::DidOpenTextDocument, - request::{ - CodeActionRequest, Completion, Formatting, GotoDefinition, GotoTypeDefinition, HoverRequest, - }, + request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest}, CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions, GotoDefinitionParams, HoverParams, PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, @@ -507,6 +505,10 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); } //- src/main.rs +#[rustc_builtin_macro] macro_rules! include {} +#[rustc_builtin_macro] macro_rules! concat {} +#[rustc_builtin_macro] macro_rules! env {} + include!(concat!(env!("OUT_DIR"), "/hello.rs")); #[cfg(atom_cfg)] @@ -521,7 +523,7 @@ struct B; fn main() { let va = A; let vb = B; - message(); + let should_be_str = message(); } "###, ) @@ -530,36 +532,35 @@ fn main() { }) .server(); server.wait_until_workspace_is_loaded(); - let res = server.send_request::(GotoDefinitionParams { + let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(14, 8), + Position::new(18, 10), ), work_done_progress_params: Default::default(), - partial_result_params: Default::default(), }); - assert!(format!("{}", res).contains("hello.rs")); + assert!(res.to_string().contains("&str")); server.request::( GotoDefinitionParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(12, 9), + Position::new(16, 9), ), work_done_progress_params: Default::default(), partial_result_params: Default::default(), }, json!([{ "originSelectionRange": { - "end": { "character": 10, "line": 12 }, - "start": { "character": 8, "line": 12 } + "end": { "character": 10, "line": 16 }, + "start": { "character": 8, "line": 16 } }, "targetRange": { - "end": { "character": 9, "line": 3 }, - "start": { "character": 0, "line": 2 } + "end": { "character": 9, "line": 7 }, + "start": { "character": 0, "line": 6 } }, "targetSelectionRange": { - "end": { "character": 8, "line": 3 }, - "start": { "character": 7, "line": 3 } + "end": { "character": 8, "line": 7 }, + "start": { "character": 7, "line": 7 } }, "targetUri": "file:///[..]src/main.rs" }]), @@ -568,23 +569,23 @@ fn main() { GotoDefinitionParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(13, 9), + Position::new(17, 9), ), work_done_progress_params: Default::default(), partial_result_params: Default::default(), }, json!([{ "originSelectionRange": { - "end": { "character": 10, "line": 13 }, - "start": { "character": 8, "line":13 } + "end": { "character": 10, "line": 17 }, + "start": { "character": 8, "line": 17 } }, "targetRange": { - "end": { "character": 9, "line": 7 }, - "start": { "character": 0, "line":6 } + "end": { "character": 9, "line": 11 }, + "start": { "character": 0, "line":10 } }, "targetSelectionRange": { - "end": { "character": 8, "line": 7 }, - "start": { "character": 7, "line": 7 } + "end": { "character": 8, "line": 11 }, + "start": { "character": 7, "line": 11 } }, "targetUri": "file:///[..]src/main.rs" }]), -- cgit v1.2.3 From 69854f7795e2a5f961f4e35c13a655f0d41cc306 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 5 Jun 2020 17:06:07 +0200 Subject: Upgrade Chalk to published version --- crates/ra_hir_ty/Cargo.toml | 4 ++-- crates/ra_hir_ty/src/traits/chalk/mapping.rs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 4b8dcdc07..112fcd07e 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -27,8 +27,8 @@ test_utils = { path = "../test_utils" } scoped-tls = "1" -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } +chalk-solve = "0.11" +chalk-ir = "0.11" [dev-dependencies] insta = "0.16.0" diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 5f6daf842..9150f65d4 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -447,6 +447,11 @@ impl ToChalk for GenericPredicate { let ty = from_chalk(db, projection_eq.ty); GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) } + + chalk_ir::WhereClause::LifetimeOutlives(_) => { + // we shouldn't get these from Chalk + panic!("encountered LifetimeOutlives from Chalk") + } } } } -- cgit v1.2.3 From 02962b374ecefd6f2a75956f4fb18806531d1d51 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 4 Mar 2020 23:00:44 +0100 Subject: Implement return position impl trait / opaque type support This is working, but I'm not that happy with how the lowering works. We might need an additional representation between `TypeRef` and `Ty` where names are resolved and `impl Trait` bounds are separated out, but things like inference variables don't exist and `impl Trait` is always represented the same way. Also note that this doesn't implement correct handling of RPIT *inside* the function (which involves turning the `impl Trait`s into variables and creating obligations for them). That intermediate representation might help there as well. --- crates/ra_hir_ty/src/db.rs | 20 +++- crates/ra_hir_ty/src/display.rs | 37 +++++-- crates/ra_hir_ty/src/infer.rs | 23 +---- crates/ra_hir_ty/src/lib.rs | 98 ++++++++++++++++-- crates/ra_hir_ty/src/lower.rs | 143 ++++++++++++++++++++++---- crates/ra_hir_ty/src/tests/traits.rs | 47 ++++++++- crates/ra_hir_ty/src/traits/chalk.rs | 52 ++++++++-- crates/ra_hir_ty/src/traits/chalk/interner.rs | 2 + crates/ra_hir_ty/src/traits/chalk/mapping.rs | 45 +++++++- crates/ra_hir_ty/src/traits/chalk/tls.rs | 5 + 10 files changed, 395 insertions(+), 77 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 0a8bb24ac..bf71d38d6 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use hir_def::{ - db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalFieldId, TraitId, TypeParamId, - VariantId, + db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId, + TypeParamId, VariantId, }; use ra_arena::map::ArenaMap; use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; @@ -13,8 +13,8 @@ use ra_prof::profile; use crate::{ method_resolution::{CrateImplDefs, TyFingerprint}, traits::{chalk, AssocTyValue, Impl}, - Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, - TyDefId, TypeCtor, ValueTyDefId, + Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, + ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, }; use hir_expand::name::Name; @@ -48,6 +48,12 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::callable_item_sig)] fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; + #[salsa::invoke(crate::lower::return_type_impl_traits)] + fn return_type_impl_traits( + &self, + def: FunctionId, + ) -> Option>>; + #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] fn generic_predicates_for_param( @@ -80,6 +86,8 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::interned] fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; #[salsa::interned] + fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; + #[salsa::interned] fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; #[salsa::interned] fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; @@ -142,3 +150,7 @@ fn hir_database_is_object_safe() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct GlobalTypeParamId(salsa::InternId); impl_intern_key!(GlobalTypeParamId); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InternedOpaqueTyId(salsa::InternId); +impl_intern_key!(InternedOpaqueTyId); diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index b9c4d2e89..3e63a2415 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs @@ -359,6 +359,21 @@ impl HirDisplay for ApplicationTy { write!(f, ">")?; } } + TypeCtor::OpaqueType(opaque_ty_id) => { + let bounds = match opaque_ty_id { + crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { + let datas = + f.db.return_type_impl_traits(func).expect("impl trait id without data"); + let data = (*datas) + .as_ref() + .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); + data.clone().subst(&self.parameters) + } + }; + write!(f, "impl ")?; + write_bounds_like_dyn_trait(&bounds.value, f)?; + // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution + } TypeCtor::Closure { .. } => { let sig = self.parameters[0].callable_sig(f.db); if let Some(sig) = sig { @@ -427,14 +442,24 @@ impl HirDisplay for Ty { } } Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, - Ty::Dyn(predicates) | Ty::Opaque(predicates) => { - match self { - Ty::Dyn(_) => write!(f, "dyn ")?, - Ty::Opaque(_) => write!(f, "impl ")?, - _ => unreachable!(), - }; + Ty::Dyn(predicates) => { + write!(f, "dyn ")?; write_bounds_like_dyn_trait(predicates, f)?; } + Ty::Opaque(opaque_ty) => { + let bounds = match opaque_ty.opaque_ty_id { + crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { + let datas = + f.db.return_type_impl_traits(func).expect("impl trait id without data"); + let data = (*datas) + .as_ref() + .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); + data.clone().subst(&opaque_ty.parameters) + } + }; + write!(f, "impl ")?; + write_bounds_like_dyn_trait(&bounds.value, f)?; + } Ty::Unknown => write!(f, "{{unknown}}")?, Ty::Infer(..) => write!(f, "_")?, } diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index dc77e88e5..d9bf3c2f0 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -39,8 +39,8 @@ use ra_syntax::SmolStr; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, - TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, + ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, + TypeWalk, Uncertain, }; use crate::{ db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, @@ -383,25 +383,6 @@ impl<'a> InferenceContext<'a> { ) -> Ty { match assoc_ty { Some(res_assoc_ty) => { - // FIXME: - // Check if inner_ty is is `impl Trait` and contained input TypeAlias id - // this is a workaround while Chalk assoc type projection doesn't always work yet, - // but once that is fixed I don't think we should keep this - // (we'll probably change how associated types are resolved anyway) - if let Ty::Opaque(ref predicates) = inner_ty { - for p in predicates.iter() { - if let GenericPredicate::Projection(projection) = p { - if projection.projection_ty.associated_ty == res_assoc_ty { - if let ty_app!(_, params) = &projection.ty { - if params.len() == 0 { - return projection.ty.clone(); - } - } - } - } - } - } - let ty = self.table.new_type_var(); let builder = Substs::build_for_def(self.db, res_assoc_ty) .push(inner_ty) diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 9fa8d3bdc..135976fcd 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -147,6 +147,12 @@ pub enum TypeCtor { /// an **application type** like `(Iterator::Item)`. AssociatedType(TypeAliasId), + /// This represents a placeholder for an opaque type in situations where we + /// don't know the hidden type (i.e. currently almost always). This is + /// analogous to the `AssociatedType` type constructor. As with that one, + /// these are only produced by Chalk. + OpaqueType(OpaqueTyId), + /// The type of a specific closure. /// /// The closure signature is stored in a `FnPtr` type in the first type @@ -194,6 +200,14 @@ impl TypeCtor { let generic_params = generics(db.upcast(), type_alias.into()); generic_params.len() } + TypeCtor::OpaqueType(opaque_ty_id) => { + match opaque_ty_id { + OpaqueTyId::ReturnTypeImplTrait(func, _) => { + let generic_params = generics(db.upcast(), func.into()); + generic_params.len() + } + } + } TypeCtor::FnPtr { num_args } => num_args as usize + 1, TypeCtor::Tuple { cardinality } => cardinality as usize, } @@ -220,6 +234,11 @@ impl TypeCtor { TypeCtor::AssociatedType(type_alias) => { Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) } + TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { + OpaqueTyId::ReturnTypeImplTrait(func, _) => { + Some(func.lookup(db.upcast()).module(db.upcast()).krate) + } + }, } } @@ -241,6 +260,7 @@ impl TypeCtor { TypeCtor::Adt(adt) => Some(adt.into()), TypeCtor::FnDef(callable) => Some(callable.into()), TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), + TypeCtor::OpaqueType(_impl_trait_id) => None, } } } @@ -254,6 +274,12 @@ pub struct ApplicationTy { pub parameters: Substs, } +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct OpaqueTy { + pub opaque_ty_id: OpaqueTyId, + pub parameters: Substs, +} + /// A "projection" type corresponds to an (unnormalized) /// projection like `>::Foo`. Note that the /// trait and all its parameters are fully known. @@ -308,6 +334,12 @@ pub enum Ty { /// trait and all its parameters are fully known. Projection(ProjectionTy), + /// An opaque type (`impl Trait`). + /// + /// This is currently only used for return type impl trait; each instance of + /// `impl Trait` in a return type gets its own ID. + Opaque(OpaqueTy), + /// A placeholder for a type parameter; for example, `T` in `fn f(x: T) /// {}` when we're type-checking the body of that function. In this /// situation, we know this stands for *some* type, but don't know the exact @@ -332,12 +364,6 @@ pub enum Ty { /// didn't seem worth the overhead yet. Dyn(Arc<[GenericPredicate]>), - /// An opaque type (`impl Trait`). - /// - /// The predicates are quantified over the `Self` type; see `Ty::Dyn` for - /// more. - Opaque(Arc<[GenericPredicate]>), - /// A placeholder for a type which could not be computed; this is propagated /// to avoid useless error messages. Doubles as a placeholder where type /// variables are inserted before type checking, since we want to try to @@ -490,7 +516,7 @@ impl Deref for Substs { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct Binders { pub num_binders: usize, pub value: T, @@ -534,6 +560,20 @@ impl Binders { } } +impl TypeWalk for Binders { + fn walk(&self, f: &mut impl FnMut(&Ty)) { + self.value.walk(f); + } + + fn walk_mut_binders( + &mut self, + f: &mut impl FnMut(&mut Ty, DebruijnIndex), + binders: DebruijnIndex, + ) { + self.value.walk_mut_binders(f, binders.shifted_in()) + } +} + /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. /// Name to be bikeshedded: TraitBound? TraitImplements? #[derive(Clone, PartialEq, Eq, Debug, Hash)] @@ -947,11 +987,16 @@ impl TypeWalk for Ty { t.walk(f); } } - Ty::Dyn(predicates) | Ty::Opaque(predicates) => { + Ty::Dyn(predicates) => { for p in predicates.iter() { p.walk(f); } } + Ty::Opaque(o_ty) => { + for t in o_ty.parameters.iter() { + t.walk(f); + } + } Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self); @@ -969,13 +1014,48 @@ impl TypeWalk for Ty { Ty::Projection(p_ty) => { p_ty.parameters.walk_mut_binders(f, binders); } - Ty::Dyn(predicates) | Ty::Opaque(predicates) => { + Ty::Dyn(predicates) => { for p in make_mut_slice(predicates) { p.walk_mut_binders(f, binders.shifted_in()); } } + Ty::Opaque(o_ty) => { + o_ty.parameters.walk_mut_binders(f, binders); + } Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self, binders); } } + +impl TypeWalk for Vec { + fn walk(&self, f: &mut impl FnMut(&Ty)) { + for t in self { + t.walk(f); + } + } + fn walk_mut_binders( + &mut self, + f: &mut impl FnMut(&mut Ty, DebruijnIndex), + binders: DebruijnIndex, + ) { + for t in self { + t.walk_mut_binders(f, binders); + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub enum OpaqueTyId { + ReturnTypeImplTrait(hir_def::FunctionId, u16), +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct ReturnTypeImplTraits { + pub(crate) impl_traits: Vec, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub(crate) struct ReturnTypeImplTrait { + pub(crate) bounds: Binders>, +} diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 35ac86a46..dfc018b0b 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -31,8 +31,9 @@ use crate::{ all_super_trait_refs, associated_type_by_name_including_super_traits, generics, make_mut_slice, variant_data, }, - Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, - ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, + Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig, + ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs, + TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; use hir_expand::name::Name; @@ -47,7 +48,16 @@ pub struct TyLoweringContext<'a> { /// possible currently, so this should be fine for now. pub type_param_mode: TypeParamLoweringMode, pub impl_trait_mode: ImplTraitLoweringMode, - pub impl_trait_counter: std::cell::Cell, + impl_trait_counter: std::cell::Cell, + /// When turning `impl Trait` into opaque types, we have to collect the + /// bounds at the same time to get the IDs correct (without becoming too + /// complicated). I don't like using interior mutability (as for the + /// counter), but I've tried and failed to make the lifetimes work for + /// passing around a `&mut TyLoweringContext`. The core problem is that + /// we're grouping the mutable data (the counter and this field) together + /// with the immutable context (the references to the DB and resolver). + /// Splitting this up would be a possible fix. + opaque_type_data: std::cell::RefCell>, } impl<'a> TyLoweringContext<'a> { @@ -56,26 +66,42 @@ impl<'a> TyLoweringContext<'a> { let impl_trait_mode = ImplTraitLoweringMode::Disallowed; let type_param_mode = TypeParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; - Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode } + let opaque_type_data = std::cell::RefCell::new(Vec::new()); + Self { + db, + resolver, + in_binders, + impl_trait_mode, + impl_trait_counter, + type_param_mode, + opaque_type_data, + } } - pub fn with_shifted_in( + pub fn with_debruijn( &self, debruijn: DebruijnIndex, f: impl FnOnce(&TyLoweringContext) -> T, ) -> T { + let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); let new_ctx = Self { - in_binders: self.in_binders.shifted_in_from(debruijn), + in_binders: debruijn, impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), + opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), ..*self }; let result = f(&new_ctx); self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); + self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); result } - pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self { - Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self } + pub fn with_shifted_in( + &self, + debruijn: DebruijnIndex, + f: impl FnOnce(&TyLoweringContext) -> T, + ) -> T { + self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) } pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { @@ -167,20 +193,47 @@ impl Ty { TypeRef::ImplTrait(bounds) => { match ctx.impl_trait_mode { ImplTraitLoweringMode::Opaque => { - let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); - let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { - bounds - .iter() - .flat_map(|b| { - GenericPredicate::from_type_bound(ctx, b, self_ty.clone()) - }) - .collect() - }); - Ty::Opaque(predicates) + let idx = ctx.impl_trait_counter.get(); + ctx.impl_trait_counter.set(idx + 1); + + assert!(idx as usize == ctx.opaque_type_data.borrow().len()); + // this dance is to make sure the data is in the right + // place even if we encounter more opaque types while + // lowering the bounds + ctx.opaque_type_data + .borrow_mut() + .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) }); + // We don't want to lower the bounds inside the binders + // we're currently in, because they don't end up inside + // those binders. E.g. when we have `impl Trait>`, the `impl OtherTrait` can't refer + // to the self parameter from `impl Trait`, and the + // bounds aren't actually stored nested within each + // other, but separately. So if the `T` refers to a type + // parameter of the outer function, it's just one binder + // away instead of two. + let actual_opaque_type_data = ctx + .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { + ReturnTypeImplTrait::from_hir(ctx, &bounds) + }); + ctx.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; + + let func = match ctx.resolver.generic_def() { + Some(GenericDefId::FunctionId(f)) => f, + _ => { + // this shouldn't happen + return (Ty::Unknown, None); + } + }; + let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx); + let generics = generics(ctx.db.upcast(), func.into()); + let parameters = Substs::bound_vars(&generics, ctx.in_binders); + Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) } ImplTraitLoweringMode::Param => { let idx = ctx.impl_trait_counter.get(); - ctx.impl_trait_counter.set(idx + 1); + // FIXME we're probably doing something wrong here + ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); if let Some(def) = ctx.resolver.generic_def() { let generics = generics(ctx.db.upcast(), def); let param = generics @@ -197,7 +250,8 @@ impl Ty { } ImplTraitLoweringMode::Variable => { let idx = ctx.impl_trait_counter.get(); - ctx.impl_trait_counter.set(idx + 1); + // FIXME we're probably doing something wrong here + ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); let (parent_params, self_params, list_params, _impl_trait_params) = if let Some(def) = ctx.resolver.generic_def() { let generics = generics(ctx.db.upcast(), def); @@ -663,6 +717,29 @@ fn assoc_type_bindings_from_type_bound<'a>( }) } +impl ReturnTypeImplTrait { + fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { + let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); + let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { + bounds + .iter() + .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) + .collect() + }); + ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } + } +} + +fn count_impl_traits(type_ref: &TypeRef) -> usize { + let mut count = 0; + type_ref.walk(&mut |type_ref| { + if matches!(type_ref, TypeRef::ImplTrait(_)) { + count += 1; + } + }); + count +} + /// Build the signature of a callable item (function, struct or enum variant). pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { match def { @@ -864,7 +941,9 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(TypeParamLoweringMode::Variable); let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::>(); - let ctx_ret = ctx_params.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + let ctx_ret = TyLoweringContext::new(db, &resolver) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) + .with_type_param_mode(TypeParamLoweringMode::Variable); let ret = Ty::from_hir(&ctx_ret, &data.ret_type); let generics = generics(db.upcast(), def.into()); let num_binders = generics.len(); @@ -1084,3 +1163,25 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, )) } + +pub(crate) fn return_type_impl_traits( + db: &impl HirDatabase, + def: hir_def::FunctionId, +) -> Option>> { + // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe + let data = db.function_data(def); + let resolver = def.resolver(db.upcast()); + let ctx_ret = TyLoweringContext::new(db, &resolver) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) + .with_type_param_mode(TypeParamLoweringMode::Variable); + let _ret = Ty::from_hir(&ctx_ret, &data.ret_type); + let generics = generics(db.upcast(), def.into()); + let num_binders = generics.len(); + let return_type_impl_traits = + ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; + if return_type_impl_traits.impl_traits.is_empty() { + None + } else { + Some(Arc::new(Binders::new(num_binders, return_type_impl_traits))) + } +} diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e8778d419..d83dc6d79 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1110,7 +1110,6 @@ fn test() { } #[test] -#[ignore] fn impl_trait() { assert_snapshot!( infer(r#" @@ -1160,6 +1159,52 @@ fn test(x: impl Trait, y: &impl Trait) { ); } +#[test] +fn return_pos_impl_trait() { + assert_snapshot!( + infer(r#" +trait Iterator { + type Item; + fn next(&mut self) -> Self::Item; +} +trait Trait { + fn foo(&self) -> T; +} +fn bar() -> (impl Iterator>, impl Trait) { loop {} } +fn baz(t: T) -> (impl Iterator>, impl Trait) { loop {} } + +fn test() { + // let (a, b) = bar(); + // a.next().foo(); + // b.foo(); + let (c, d) = baz(1u128); + c.next();//.foo(); + // d.foo(); +} +"#), + @r###" + 50..54 'self': &mut Self + 102..106 'self': &Self + 185..196 '{ loop {} }': ({unknown}, {unknown}) + 187..194 'loop {}': ! + 192..194 '{}': () + 207..208 't': T + 269..280 '{ loop {} }': ({unknown}, {unknown}) + 271..278 'loop {}': ! + 276..278 '{}': () + 292..429 '{ ...o(); }': () + 368..374 '(c, d)': (impl Iterator>, impl Trait) + 369..370 'c': impl Iterator> + 372..373 'd': impl Trait + 377..380 'baz': fn baz(u128) -> (impl Iterator>, impl Trait) + 377..387 'baz(1u128)': (impl Iterator>, impl Trait) + 381..386 '1u128': u128 + 393..394 'c': impl Iterator> + 393..401 'c.next()': impl Trait + "### + ); +} + #[test] fn dyn_trait() { assert_snapshot!( diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 61de3cc30..a72a82f5a 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use log::debug; use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; -use chalk_solve::rust_ir::{self, WellKnownTrait}; +use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; use hir_def::{ lang_item::{lang_attr, LangItemTarget}, @@ -100,6 +100,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { self.db.associated_ty_value(self.krate, id) } + fn custom_clauses(&self) -> Vec> { vec![] } @@ -130,11 +131,34 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) } - fn opaque_ty_data( - &self, - _id: chalk_ir::OpaqueTyId, - ) -> Arc> { - unimplemented!() + fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId) -> Arc { + let interned_id = crate::db::InternedOpaqueTyId::from(id); + let full_id = self.db.lookup_intern_impl_trait_id(interned_id); + let (func, idx) = match full_id { + crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), + }; + let datas = + self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); + let data = &datas.value.impl_traits[idx as usize]; + let bound = OpaqueTyDatumBound { + bounds: make_binders( + data.bounds + .value + .iter() + .cloned() + .filter(|b| !b.is_error()) + .map(|b| b.to_chalk(self.db)) + .collect(), + 1, + ), + }; + let num_vars = datas.num_binders; + Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) + } + + fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { + // FIXME: actually provide the hidden type; it is relevant for auto traits + Ty::Unknown.to_chalk(self.db) } fn force_impl_for( @@ -150,10 +174,6 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { // FIXME: implement actual object safety true } - - fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { - Ty::Unknown.to_chalk(self.db) - } } pub(crate) fn program_clauses_for_chalk_env_query( @@ -460,6 +480,18 @@ impl From for ImplId { } } +impl From for crate::db::InternedOpaqueTyId { + fn from(id: OpaqueTyId) -> Self { + InternKey::from_intern_id(id.0) + } +} + +impl From for OpaqueTyId { + fn from(id: crate::db::InternedOpaqueTyId) -> Self { + chalk_ir::OpaqueTyId(id.as_intern_id()) + } +} + impl From> for crate::traits::AssocTyValueId { fn from(id: rust_ir::AssociatedTyValueId) -> Self { Self::from_intern_id(id.0) diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs index e27074ba6..56aab640c 100644 --- a/crates/ra_hir_ty/src/traits/chalk/interner.rs +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs @@ -22,6 +22,8 @@ pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId; pub type FnDefId = chalk_ir::FnDefId; pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum; +pub type OpaqueTyId = chalk_ir::OpaqueTyId; +pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum; impl chalk_ir::interner::Interner for Interner { type InternedType = Box>; // FIXME use Arc? diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 5f6daf842..834360430 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -16,8 +16,8 @@ use crate::{ db::HirDatabase, primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, - ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, - Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, + ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, + ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, }; use super::interner::*; @@ -68,7 +68,16 @@ impl ToChalk for Ty { let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) } - Ty::Opaque(_) | Ty::Unknown => { + Ty::Opaque(opaque_ty) => { + let opaque_ty_id = opaque_ty.opaque_ty_id.to_chalk(db); + let substitution = opaque_ty.parameters.to_chalk(db); + chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { + opaque_ty_id, + substitution, + })) + .intern(&Interner) + } + Ty::Unknown => { let substitution = chalk_ir::Substitution::empty(&Interner); let name = TypeName::Error; chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) @@ -98,7 +107,11 @@ impl ToChalk for Ty { let parameters = from_chalk(db, proj.substitution); Ty::Projection(ProjectionTy { associated_ty, parameters }) } - chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), + chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { + let impl_trait_id = from_chalk(db, opaque_ty.opaque_ty_id); + let parameters = from_chalk(db, opaque_ty.substitution); + Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) + } chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { let parameters: Substs = from_chalk(db, substitution); Ty::Apply(ApplicationTy { @@ -204,6 +217,21 @@ impl ToChalk for hir_def::TraitId { } } +impl ToChalk for OpaqueTyId { + type Chalk = chalk_ir::OpaqueTyId; + + fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::OpaqueTyId { + db.intern_impl_trait_id(self).into() + } + + fn from_chalk( + db: &dyn HirDatabase, + opaque_ty_id: chalk_ir::OpaqueTyId, + ) -> OpaqueTyId { + db.lookup_intern_impl_trait_id(opaque_ty_id.into()) + } +} + impl ToChalk for TypeCtor { type Chalk = TypeName; @@ -214,6 +242,11 @@ impl ToChalk for TypeCtor { TypeName::AssociatedType(type_id) } + TypeCtor::OpaqueType(impl_trait_id) => { + let id = impl_trait_id.to_chalk(db); + TypeName::OpaqueType(id) + } + TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), TypeCtor::Char => TypeName::Scalar(Scalar::Char), TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), @@ -252,7 +285,9 @@ impl ToChalk for TypeCtor { match type_name { TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), - TypeName::OpaqueType(_) => unreachable!(), + TypeName::OpaqueType(opaque_type_id) => { + TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) + } TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, TypeName::Scalar(Scalar::Char) => TypeCtor::Char, diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index d88828c7c..556af7098 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs @@ -69,6 +69,11 @@ impl DebugContext<'_> { let name = self.0.type_alias_data(type_alias).name.clone(); write!(f, "{}::{}", trait_name, name)?; } + TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { + crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { + write!(f, "{{impl trait {} of {:?}}}", idx, func)?; + } + }, TypeCtor::Closure { def, expr } => { write!(f, "{{closure {:?} in ", expr.into_raw())?; match def { -- cgit v1.2.3 From bbb40d746368eb6a38498649a723c7ead0ef8136 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 5 Jun 2020 16:45:20 +0200 Subject: Minimize FileLoader interface --- crates/ra_db/src/lib.rs | 53 ++++++++++++++----------------- crates/ra_hir_def/src/test_db.rs | 12 +------ crates/ra_hir_expand/src/builtin_macro.rs | 18 ++++------- crates/ra_hir_expand/src/test_db.rs | 9 +----- crates/ra_hir_ty/src/test_db.rs | 11 +------ crates/ra_ide_db/src/lib.rs | 11 ++----- 6 files changed, 35 insertions(+), 79 deletions(-) (limited to 'crates') diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 2e63cb46e..7354b3832 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -89,14 +89,13 @@ pub const DEFAULT_LRU_CAP: usize = 128; pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; + /// Note that we intentionally accept a `&str` and not a `&Path` here. This + /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such, + /// so the input is guaranteed to be utf-8 string. We might introduce + /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we + /// get by with a `&str` for the time being. fn resolve_path(&self, anchor: FileId, path: &str) -> Option; fn relevant_crates(&self, file_id: FileId) -> Arc>; - - fn resolve_extern_path( - &self, - extern_id: ExternSourceId, - relative_path: &RelativePath, - ) -> Option; } /// Database which stores all significant input facts: source code and project @@ -154,34 +153,30 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { fn file_text(&self, file_id: FileId) -> Arc { SourceDatabaseExt::file_text(self.0, file_id) } - /// Note that we intentionally accept a `&str` and not a `&Path` here. This - /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such, - /// so the input is guaranteed to be utf-8 string. We might introduce - /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we - /// get by with a `&str` for the time being. fn resolve_path(&self, anchor: FileId, path: &str) -> Option { - let rel_path = { - let mut rel_path = self.0.file_relative_path(anchor); - assert!(rel_path.pop()); - rel_path.push(path); - rel_path.normalize() - }; - let source_root = self.0.file_source_root(anchor); - let source_root = self.0.source_root(source_root); - source_root.file_by_relative_path(&rel_path) + // FIXME: this *somehow* should be platform agnostic... + if std::path::Path::new(path).is_absolute() { + let krate = *self.relevant_crates(anchor).get(0)?; + let (extern_source_id, relative_file) = + self.0.crate_graph()[krate].extern_source.extern_path(path)?; + + let source_root = self.0.source_root(SourceRootId(extern_source_id.0)); + source_root.file_by_relative_path(&relative_file) + } else { + let rel_path = { + let mut rel_path = self.0.file_relative_path(anchor); + assert!(rel_path.pop()); + rel_path.push(path); + rel_path.normalize() + }; + let source_root = self.0.file_source_root(anchor); + let source_root = self.0.source_root(source_root); + source_root.file_by_relative_path(&rel_path) + } } fn relevant_crates(&self, file_id: FileId) -> Arc> { let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) } - - fn resolve_extern_path( - &self, - extern_id: ExternSourceId, - relative_path: &RelativePath, - ) -> Option { - let source_root = self.0.source_root(SourceRootId(extern_id.0)); - source_root.file_by_relative_path(&relative_path) - } } diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index e7a5182f0..bcfa66ac9 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -6,9 +6,7 @@ use std::{ }; use hir_expand::db::AstDatabase; -use ra_db::{ - salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath, Upcast, -}; +use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; use crate::db::DefDatabase; @@ -64,14 +62,6 @@ impl FileLoader for TestDB { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - - fn resolve_extern_path( - &self, - extern_id: ExternSourceId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) - } } impl TestDB { diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index eec5fb8eb..7579546d2 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -295,19 +295,13 @@ fn concat_expand( fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option { let call_site = call_id.as_file().original_file(db); - - // Handle trivial case - if let Some(res) = db.resolve_path(call_site, path) { - // Prevent include itself - return if res == call_site { None } else { Some(res) }; + let res = db.resolve_path(call_site, path)?; + // Prevent include itself + if res == call_site { + None + } else { + Some(res) } - - // Extern paths ? - let krate = *db.relevant_crates(call_site).get(0)?; - let (extern_source_id, relative_file) = - db.crate_graph()[krate].extern_source.extern_path(path)?; - - db.resolve_extern_path(extern_source_id, &relative_file) } fn parse_string(tt: &tt::Subtree) -> Result { diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index 765a2f6d1..fdf225f55 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs @@ -5,7 +5,7 @@ use std::{ sync::{Arc, Mutex}, }; -use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; +use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; #[salsa::database( ra_db::SourceDatabaseExtStorage, @@ -47,11 +47,4 @@ impl FileLoader for TestDB { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn resolve_extern_path( - &self, - anchor: ExternSourceId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path) - } } diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 21a3bdfd1..e484968a0 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs @@ -7,9 +7,7 @@ use std::{ use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; -use ra_db::{ - salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase, Upcast, -}; +use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; use stdx::format_to; use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; @@ -78,13 +76,6 @@ impl FileLoader for TestDB { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn resolve_extern_path( - &self, - extern_id: ra_db::ExternSourceId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) - } } impl TestDB { diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 93d5891a0..727d743b5 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -16,8 +16,8 @@ use std::sync::Arc; use hir::db::{AstDatabase, DefDatabase}; use ra_db::{ salsa::{self, Database, Durability}, - Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, - SourceDatabase, SourceRootId, Upcast, + Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, + SourceRootId, Upcast, }; use rustc_hash::FxHashMap; @@ -63,13 +63,6 @@ impl FileLoader for RootDatabase { fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } - fn resolve_extern_path( - &self, - extern_id: ra_db::ExternSourceId, - relative_path: &RelativePath, - ) -> Option { - FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) - } } impl salsa::Database for RootDatabase { -- cgit v1.2.3 From 0d2328f3eaf69c6a50fe6c1e946257bd3503d751 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 5 Jun 2020 17:41:58 +0200 Subject: Review fixes --- crates/ra_hir/src/db.rs | 4 +- crates/ra_hir_ty/src/display.rs | 6 +-- crates/ra_hir_ty/src/lower.rs | 9 ++--- crates/ra_hir_ty/src/tests/traits.rs | 73 ++++++++++++++++++++++++++++-------- crates/ra_ide_db/src/change.rs | 1 + 5 files changed, 68 insertions(+), 25 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index ec931b34f..693cd40cf 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -18,8 +18,8 @@ pub use hir_ty::db::{ GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, - InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery, - TraitSolveQuery, TyQuery, ValueTyQuery, + InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, + TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, }; #[test] diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index 3e63a2415..3c97e1354 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs @@ -4,7 +4,7 @@ use std::fmt; use crate::{ db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, - Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, + Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, }; use hir_def::{ find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, @@ -361,7 +361,7 @@ impl HirDisplay for ApplicationTy { } TypeCtor::OpaqueType(opaque_ty_id) => { let bounds = match opaque_ty_id { - crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { + OpaqueTyId::ReturnTypeImplTrait(func, idx) => { let datas = f.db.return_type_impl_traits(func).expect("impl trait id without data"); let data = (*datas) @@ -448,7 +448,7 @@ impl HirDisplay for Ty { } Ty::Opaque(opaque_ty) => { let bounds = match opaque_ty.opaque_ty_id { - crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { + OpaqueTyId::ReturnTypeImplTrait(func, idx) => { let datas = f.db.return_type_impl_traits(func).expect("impl trait id without data"); let data = (*datas) diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index dfc018b0b..a05cbd7fc 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -21,8 +21,10 @@ use hir_def::{ HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, }; +use hir_expand::name::Name; use ra_arena::map::ArenaMap; use ra_db::CrateId; +use test_utils::mark; use crate::{ db::HirDatabase, @@ -35,7 +37,6 @@ use crate::{ ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; -use hir_expand::name::Name; #[derive(Debug)] pub struct TyLoweringContext<'a> { @@ -220,10 +221,7 @@ impl Ty { let func = match ctx.resolver.generic_def() { Some(GenericDefId::FunctionId(f)) => f, - _ => { - // this shouldn't happen - return (Ty::Unknown, None); - } + _ => panic!("opaque impl trait lowering in non-function"), }; let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx); let generics = generics(ctx.db.upcast(), func.into()); @@ -719,6 +717,7 @@ fn assoc_type_bindings_from_type_bound<'a>( impl ReturnTypeImplTrait { fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { + mark::hit!(lower_rpit); let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { bounds diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index d83dc6d79..0c538a62d 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1160,7 +1160,37 @@ fn test(x: impl Trait, y: &impl Trait) { } #[test] -fn return_pos_impl_trait() { +fn simple_return_pos_impl_trait() { + mark::check!(lower_rpit); + assert_snapshot!( + infer(r#" +trait Trait { + fn foo(&self) -> T; +} +fn bar() -> impl Trait { loop {} } + +fn test() { + let a = bar(); + a.foo(); +} +"#), + @r###" + 30..34 'self': &Self + 72..83 '{ loop {} }': ! + 74..81 'loop {}': ! + 79..81 '{}': () + 95..130 '{ ...o(); }': () + 105..106 'a': impl Trait + 109..112 'bar': fn bar() -> impl Trait + 109..114 'bar()': impl Trait + 120..121 'a': impl Trait + 120..127 'a.foo()': u64 + "### + ); +} + +#[test] +fn more_return_pos_impl_trait() { assert_snapshot!( infer(r#" trait Iterator { @@ -1174,12 +1204,12 @@ fn bar() -> (impl Iterator>, impl Trait) { loop {} } fn baz(t: T) -> (impl Iterator>, impl Trait) { loop {} } fn test() { - // let (a, b) = bar(); - // a.next().foo(); - // b.foo(); + let (a, b) = bar(); + a.next().foo(); + b.foo(); let (c, d) = baz(1u128); - c.next();//.foo(); - // d.foo(); + c.next().foo(); + d.foo(); } "#), @r###" @@ -1192,15 +1222,28 @@ fn test() { 269..280 '{ loop {} }': ({unknown}, {unknown}) 271..278 'loop {}': ! 276..278 '{}': () - 292..429 '{ ...o(); }': () - 368..374 '(c, d)': (impl Iterator>, impl Trait) - 369..370 'c': impl Iterator> - 372..373 'd': impl Trait - 377..380 'baz': fn baz(u128) -> (impl Iterator>, impl Trait) - 377..387 'baz(1u128)': (impl Iterator>, impl Trait) - 381..386 '1u128': u128 - 393..394 'c': impl Iterator> - 393..401 'c.next()': impl Trait + 292..414 '{ ...o(); }': () + 302..308 '(a, b)': (impl Iterator>, impl Trait) + 303..304 'a': impl Iterator> + 306..307 'b': impl Trait + 311..314 'bar': fn bar() -> (impl Iterator>, impl Trait) + 311..316 'bar()': (impl Iterator>, impl Trait) + 322..323 'a': impl Iterator> + 322..330 'a.next()': impl Trait + 322..336 'a.next().foo()': u32 + 342..343 'b': impl Trait + 342..349 'b.foo()': u64 + 359..365 '(c, d)': (impl Iterator>, impl Trait) + 360..361 'c': impl Iterator> + 363..364 'd': impl Trait + 368..371 'baz': fn baz(u128) -> (impl Iterator>, impl Trait) + 368..378 'baz(1u128)': (impl Iterator>, impl Trait) + 372..377 '1u128': u128 + 384..385 'c': impl Iterator> + 384..392 'c.next()': impl Trait + 384..398 'c.next().foo()': u128 + 404..405 'd': impl Trait + 404..411 'd.foo()': u128 "### ); } diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 8446ef88e..1f4d2c076 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -369,6 +369,7 @@ impl RootDatabase { hir::db::ImplDatumQuery hir::db::AssociatedTyValueQuery hir::db::TraitSolveQuery + hir::db::ReturnTypeImplTraitsQuery // SymbolsDatabase crate::symbol_index::FileSymbolsQuery -- cgit v1.2.3 From a4a4a1854ebb53e1cdd7a5e3b308112bbbf3c676 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 29 May 2020 19:14:04 +0200 Subject: Fix type parameter defaults They should not be applied in expression or pattern contexts, unless there are other explicitly given type args. --- .../ra_assists/src/handlers/add_explicit_type.rs | 4 +- crates/ra_hir_ty/src/infer.rs | 4 +- crates/ra_hir_ty/src/infer/path.rs | 3 +- crates/ra_hir_ty/src/lower.rs | 70 ++++++++----- crates/ra_hir_ty/src/tests/display_source_code.rs | 4 +- crates/ra_hir_ty/src/tests/method_resolution.rs | 54 ----------- crates/ra_hir_ty/src/tests/simple.rs | 108 +++++++++++++++++++++ crates/ra_hir_ty/src/tests/traits.rs | 54 +++++------ crates/ra_ide/src/hover.rs | 2 +- crates/ra_ide/src/inlay_hints.rs | 4 +- 10 files changed, 192 insertions(+), 115 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index ab20c6649..90b06a625 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs @@ -195,7 +195,7 @@ struct Test { } fn main() { - let test<|> = Test { t: 23, k: 33 }; + let test<|> = Test { t: 23u8, k: 33 }; }"#, r#" struct Test { @@ -204,7 +204,7 @@ struct Test { } fn main() { - let test: Test = Test { t: 23, k: 33 }; + let test: Test = Test { t: 23u8, k: 33 }; }"#, ); } diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index d9bf3c2f0..2e16e5120 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -439,13 +439,13 @@ impl<'a> InferenceContext<'a> { }; return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { - let substs = Ty::substs_from_path(&ctx, path, strukt.into()); + let substs = Ty::substs_from_path(&ctx, path, strukt.into(), true); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.subst(&substs)); forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) } TypeNs::EnumVariantId(var) => { - let substs = Ty::substs_from_path(&ctx, path, var.into()); + let substs = Ty::substs_from_path(&ctx, path, var.into(), true); let ty = self.db.ty(var.parent.into()); let ty = self.insert_type_vars(ty.subst(&substs)); forbid_unresolved_segments((ty, Some(var.into())), unresolved) diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 1c2e56fb0..1ad0d8397 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -95,7 +95,7 @@ impl<'a> InferenceContext<'a> { // self_subst is just for the parent let parent_substs = self_subst.unwrap_or_else(Substs::empty); let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - let substs = Ty::substs_from_path(&ctx, path, typable); + let substs = Ty::substs_from_path(&ctx, path, typable, true); let full_substs = Substs::builder(substs.len()) .use_parent_substs(&parent_substs) .fill(substs.0[parent_substs.len()..].iter().cloned()) @@ -141,6 +141,7 @@ impl<'a> InferenceContext<'a> { def, resolved_segment, remaining_segments_for_ty, + true, ); if let Ty::Unknown = ty { return None; diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index a05cbd7fc..42713928f 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -323,6 +323,7 @@ impl Ty { resolution: TypeNs, resolved_segment: PathSegment<'_>, remaining_segments: PathSegments<'_>, + infer_args: bool, ) -> (Ty, Option) { let ty = match resolution { TypeNs::TraitId(trait_) => { @@ -400,9 +401,15 @@ impl Ty { ctx.db.ty(adt.into()).subst(&substs) } - TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), - TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), - TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), + TypeNs::AdtId(it) => { + Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) + } + TypeNs::BuiltinType(it) => { + Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) + } + TypeNs::TypeAliasId(it) => { + Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) + } // FIXME: report error TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), }; @@ -428,7 +435,13 @@ impl Ty { ), Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), }; - Ty::from_partly_resolved_hir_path(ctx, resolution, resolved_segment, remaining_segments) + Ty::from_partly_resolved_hir_path( + ctx, + resolution, + resolved_segment, + remaining_segments, + false, + ) } fn select_associated_type( @@ -474,13 +487,14 @@ impl Ty { ctx: &TyLoweringContext<'_>, segment: PathSegment<'_>, typable: TyDefId, + infer_args: bool, ) -> Ty { let generic_def = match typable { TyDefId::BuiltinType(_) => None, TyDefId::AdtId(it) => Some(it.into()), TyDefId::TypeAliasId(it) => Some(it.into()), }; - let substs = substs_from_path_segment(ctx, segment, generic_def, false); + let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); ctx.db.ty(typable).subst(&substs) } @@ -493,6 +507,7 @@ impl Ty { // `ValueTyDefId` is just a convenient way to pass generics and // special-case enum variants resolved: ValueTyDefId, + infer_args: bool, ) -> Substs { let last = path.segments().last().expect("path should have at least one segment"); let (segment, generic_def) = match resolved { @@ -515,22 +530,27 @@ impl Ty { (segment, Some(var.parent.into())) } }; - substs_from_path_segment(ctx, segment, generic_def, false) + substs_from_path_segment(ctx, segment, generic_def, infer_args) } } -pub(super) fn substs_from_path_segment( +fn substs_from_path_segment( ctx: &TyLoweringContext<'_>, segment: PathSegment<'_>, def_generic: Option, - _add_self_param: bool, + infer_args: bool, ) -> Substs { let mut substs = Vec::new(); let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def)); let (parent_params, self_params, type_params, impl_trait_params) = def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); + let total_len = parent_params + self_params + type_params + impl_trait_params; + substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); + + let mut had_explicit_args = false; + if let Some(generic_args) = &segment.args_and_bindings { if !generic_args.has_self_type { substs.extend(iter::repeat(Ty::Unknown).take(self_params)); @@ -542,31 +562,35 @@ pub(super) fn substs_from_path_segment( for arg in generic_args.args.iter().skip(skip).take(expected_num) { match arg { GenericArg::Type(type_ref) => { + had_explicit_args = true; let ty = Ty::from_hir(ctx, type_ref); substs.push(ty); } } } } - let total_len = parent_params + self_params + type_params + impl_trait_params; - // add placeholders for args that were not provided - for _ in substs.len()..total_len { - substs.push(Ty::Unknown); - } - assert_eq!(substs.len(), total_len); - // handle defaults - if let Some(def_generic) = def_generic { - let default_substs = ctx.db.generic_defaults(def_generic); - assert_eq!(substs.len(), default_substs.len()); + // handle defaults. In expression or pattern path segments without + // explicitly specified type arguments, missing type arguments are inferred + // (i.e. defaults aren't used). + if !infer_args || had_explicit_args { + if let Some(def_generic) = def_generic { + let default_substs = ctx.db.generic_defaults(def_generic); + assert_eq!(total_len, default_substs.len()); - for (i, default_ty) in default_substs.iter().enumerate() { - if substs[i] == Ty::Unknown { - substs[i] = default_ty.clone(); + for default_ty in default_substs.iter().skip(substs.len()) { + substs.push(default_ty.clone()); } } } + // add placeholders for args that were not provided + // FIXME: emit diagnostics in contexts where this is not allowed + for _ in substs.len()..total_len { + substs.push(Ty::Unknown); + } + assert_eq!(substs.len(), total_len); + Substs(substs.into()) } @@ -615,9 +639,7 @@ impl TraitRef { segment: PathSegment<'_>, resolved: TraitId, ) -> Substs { - let has_self_param = - segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); - substs_from_path_segment(ctx, segment, Some(resolved.into()), !has_self_param) + substs_from_path_segment(ctx, segment, Some(resolved.into()), false) } pub(crate) fn from_type_bound( diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs index 4088b1d22..5dfa0a014 100644 --- a/crates/ra_hir_ty/src/tests/display_source_code.rs +++ b/crates/ra_hir_ty/src/tests/display_source_code.rs @@ -29,7 +29,7 @@ fn omit_default_type_parameters() { //- /main.rs struct Foo { t: T } fn main() { - let foo = Foo { t: 5 }; + let foo = Foo { t: 5u8 }; foo<|>; } ", @@ -41,7 +41,7 @@ fn omit_default_type_parameters() { //- /main.rs struct Foo { k: K, t: T } fn main() { - let foo = Foo { k: 400, t: 5 }; + let foo = Foo { k: 400, t: 5u8 }; foo<|>; } ", diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 558a70022..804297315 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -183,60 +183,6 @@ fn test() { ); } -#[test] -fn infer_associated_method_generics_with_default_param() { - assert_snapshot!( - infer(r#" -struct Gen { - val: T -} - -impl Gen { - pub fn make() -> Gen { - loop { } - } -} - -fn test() { - let a = Gen::make(); -} -"#), - @r###" - 80..104 '{ ... }': Gen - 90..98 'loop { }': ! - 95..98 '{ }': () - 118..146 '{ ...e(); }': () - 128..129 'a': Gen - 132..141 'Gen::make': fn make() -> Gen - 132..143 'Gen::make()': Gen - "### - ); -} - -#[test] -fn infer_associated_method_generics_with_default_tuple_param() { - let t = type_at( - r#" -//- /main.rs -struct Gen { - val: T -} - -impl Gen { - pub fn make() -> Gen { - loop { } - } -} - -fn test() { - let a = Gen::make(); - a.val<|>; -} -"#, - ); - assert_eq!(t, "()"); -} - #[test] fn infer_associated_method_generics_without_args() { assert_snapshot!( diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 88309157b..8a5031756 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1997,3 +1997,111 @@ fn foo() { "### ); } + +#[test] +fn generic_default() { + assert_snapshot!( + infer(r#" +struct Thing { t: T } +enum OtherThing { + One { t: T }, + Two(T), +} + +fn test(t1: Thing, t2: OtherThing, t3: Thing, t4: OtherThing) { + t1.t; + t3.t; + match t2 { + OtherThing::One { t } => { t; }, + OtherThing::Two(t) => { t; }, + } + match t4 { + OtherThing::One { t } => { t; }, + OtherThing::Two(t) => { t; }, + } +} +"#), + @r###" + 98..100 't1': Thing<()> + 109..111 't2': OtherThing<()> + 125..127 't3': Thing + 141..143 't4': OtherThing + 162..385 '{ ... } }': () + 168..170 't1': Thing<()> + 168..172 't1.t': () + 178..180 't3': Thing + 178..182 't3.t': i32 + 188..283 'match ... }': () + 194..196 't2': OtherThing<()> + 207..228 'OtherT... { t }': OtherThing<()> + 225..226 't': () + 232..238 '{ t; }': () + 234..235 't': () + 248..266 'OtherT...Two(t)': OtherThing<()> + 264..265 't': () + 270..276 '{ t; }': () + 272..273 't': () + 288..383 'match ... }': () + 294..296 't4': OtherThing + 307..328 'OtherT... { t }': OtherThing + 325..326 't': i32 + 332..338 '{ t; }': () + 334..335 't': i32 + 348..366 'OtherT...Two(t)': OtherThing + 364..365 't': i32 + 370..376 '{ t; }': () + 372..373 't': i32 + "### + ); +} + +#[test] +fn generic_default_in_struct_literal() { + assert_snapshot!( + infer(r#" +struct Thing { t: T } +enum OtherThing { + One { t: T }, + Two(T), +} + +fn test() { + let x = Thing { t: loop {} }; + let y = Thing { t: () }; + let z = Thing { t: 1i32 }; + if let Thing { t } = z { + t; + } + + let a = OtherThing::One { t: 1i32 }; + let b = OtherThing::Two(1i32); +} +"#), + @r###" + 100..320 '{ ...32); }': () + 110..111 'x': Thing + 114..134 'Thing ...p {} }': Thing + 125..132 'loop {}': ! + 130..132 '{}': () + 144..145 'y': Thing<()> + 148..163 'Thing { t: () }': Thing<()> + 159..161 '()': () + 173..174 'z': Thing + 177..194 'Thing ...1i32 }': Thing + 188..192 '1i32': i32 + 200..241 'if let... }': () + 207..218 'Thing { t }': Thing + 215..216 't': i32 + 221..222 'z': Thing + 223..241 '{ ... }': () + 233..234 't': i32 + 251..252 'a': OtherThing + 255..282 'OtherT...1i32 }': OtherThing + 276..280 '1i32': i32 + 292..293 'b': OtherThing + 296..311 'OtherThing::Two': Two(i32) -> OtherThing + 296..317 'OtherT...(1i32)': OtherThing + 312..316 '1i32': i32 + "### + ); +} diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 0c538a62d..133fb5f39 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1806,33 +1806,33 @@ fn test() { } "#), @r###" -65..69 'self': &Self -166..170 'self': Self -172..176 'args': Args -240..244 'self': &Foo -255..257 '{}': () -335..336 'f': F -355..357 '{}': () -444..690 '{ ...o(); }': () -454..459 'lazy1': Lazy T> -476..485 'Lazy::new': fn new T>(fn() -> T) -> Lazy T> -476..493 'Lazy::...| Foo)': Lazy T> -486..492 '|| Foo': || -> T -489..492 'Foo': Foo -503..505 'r1': {unknown} -508..513 'lazy1': Lazy T> -508..519 'lazy1.foo()': {unknown} -561..576 'make_foo_fn_ptr': fn() -> Foo -592..603 'make_foo_fn': fn make_foo_fn() -> Foo -613..618 'lazy2': Lazy T> -635..644 'Lazy::new': fn new T>(fn() -> T) -> Lazy T> -635..661 'Lazy::...n_ptr)': Lazy T> -645..660 'make_foo_fn_ptr': fn() -> Foo -671..673 'r2': {unknown} -676..681 'lazy2': Lazy T> -676..687 'lazy2.foo()': {unknown} -550..552 '{}': () -"### + 65..69 'self': &Self + 166..170 'self': Self + 172..176 'args': Args + 240..244 'self': &Foo + 255..257 '{}': () + 335..336 'f': F + 355..357 '{}': () + 444..690 '{ ...o(); }': () + 454..459 'lazy1': Lazy Foo> + 476..485 'Lazy::new': fn new Foo>(|| -> Foo) -> Lazy Foo> + 476..493 'Lazy::...| Foo)': Lazy Foo> + 486..492 '|| Foo': || -> Foo + 489..492 'Foo': Foo + 503..505 'r1': usize + 508..513 'lazy1': Lazy Foo> + 508..519 'lazy1.foo()': usize + 561..576 'make_foo_fn_ptr': fn() -> Foo + 592..603 'make_foo_fn': fn make_foo_fn() -> Foo + 613..618 'lazy2': Lazy Foo> + 635..644 'Lazy::new': fn new Foo>(fn() -> Foo) -> Lazy Foo> + 635..661 'Lazy::...n_ptr)': Lazy Foo> + 645..660 'make_foo_fn_ptr': fn() -> Foo + 671..673 'r2': {unknown} + 676..681 'lazy2': Lazy Foo> + 676..687 'lazy2.foo()': {unknown} + 550..552 '{}': () + "### ); } diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 62df07459..846d8c69b 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -529,7 +529,7 @@ struct Test { } fn main() { - let zz<|> = Test { t: 23, k: 33 }; + let zz<|> = Test { t: 23u8, k: 33 }; }"#, &["Test"], ); diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 49366de98..7eb2cef73 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs @@ -415,7 +415,7 @@ struct Test { } fn main() { - let zz = Test { t: 23, k: 33 }; + let zz = Test { t: 23u8, k: 33 }; let zz_ref = &zz; }"#, ); @@ -428,7 +428,7 @@ fn main() { label: "Test", }, InlayHint { - range: 105..111, + range: 107..113, kind: TypeHint, label: "&Test", }, -- cgit v1.2.3 From de74c0dcab2efd50d68f70d15de3fced718e8c7a Mon Sep 17 00:00:00 2001 From: vsrs Date: Sat, 6 Jun 2020 12:00:46 +0300 Subject: Preliminary runnables refactoring --- crates/ra_ide/src/runnables.rs | 78 +++++++++++++++++++++++ crates/rust-analyzer/src/main_loop/handlers.rs | 86 +++++++++++++------------- crates/rust-analyzer/src/to_proto.rs | 12 +--- 3 files changed, 122 insertions(+), 54 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index f32ce0d22..9f7b5edfd 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs @@ -42,6 +42,42 @@ pub enum RunnableKind { Bin, } +#[derive(Debug, Eq, PartialEq)] +pub struct RunnableAction { + pub run_title: &'static str, + pub debugee: bool, +} + +const TEST: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Test", debugee: true }; +const DOCTEST: RunnableAction = + RunnableAction { run_title: "▶\u{fe0e} Run Doctest", debugee: false }; +const BENCH: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Bench", debugee: true }; +const BIN: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run", debugee: true }; + +impl Runnable { + // test package::module::testname + pub fn label(&self, target: Option) -> String { + match &self.kind { + RunnableKind::Test { test_id, .. } => format!("test {}", test_id), + RunnableKind::TestMod { path } => format!("test-mod {}", path), + RunnableKind::Bench { test_id } => format!("bench {}", test_id), + RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), + RunnableKind::Bin => { + target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) + } + } + } + + pub fn action(&self) -> &'static RunnableAction { + match &self.kind { + RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => &TEST, + RunnableKind::DocTest { .. } => &DOCTEST, + RunnableKind::Bench { .. } => &BENCH, + RunnableKind::Bin => &BIN, + } + } +} + // Feature: Run // // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor @@ -207,6 +243,15 @@ mod tests { use crate::mock_analysis::analysis_and_position; + use super::{Runnable, RunnableAction, BENCH, BIN, DOCTEST, TEST}; + + fn assert_actions(runnables: &[Runnable], actions: &[&RunnableAction]) { + assert_eq!( + actions, + runnables.into_iter().map(|it| it.action()).collect::>().as_slice() + ); + } + #[test] fn test_runnables() { let (analysis, pos) = analysis_and_position( @@ -221,6 +266,9 @@ mod tests { #[test] #[ignore] fn test_foo() {} + + #[bench] + fn bench() {} "#, ); let runnables = analysis.runnables(pos.file_id).unwrap(); @@ -295,9 +343,32 @@ mod tests { }, cfg_exprs: [], }, + Runnable { + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 82..104, + name: "bench", + kind: FN_DEF, + focus_range: Some( + 94..99, + ), + container_name: None, + description: None, + docs: None, + }, + kind: Bench { + test_id: Path( + "bench", + ), + }, + cfg_exprs: [], + }, ] "### ); + assert_actions(&runnables, &[&BIN, &TEST, &TEST, &BENCH]); } #[test] @@ -361,6 +432,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&BIN, &DOCTEST]); } #[test] @@ -427,6 +499,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&BIN, &DOCTEST]); } #[test] @@ -493,6 +566,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&TEST, &TEST]); } #[test] @@ -561,6 +635,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&TEST, &TEST]); } #[test] @@ -631,6 +706,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&TEST, &TEST]); } #[test] @@ -681,6 +757,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&TEST]); } #[test] @@ -739,6 +816,7 @@ mod tests { ] "### ); + assert_actions(&runnables, &[&TEST]); } #[test] diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 3ff779702..da16976d3 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -18,7 +18,7 @@ use lsp_types::{ TextDocumentIdentifier, Url, WorkspaceEdit, }; use ra_ide::{ - FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, RunnableKind, SearchScope, + FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit, }; use ra_prof::profile; @@ -403,16 +403,11 @@ pub fn handle_runnables( if !runnable.nav.full_range().contains_inclusive(offset) { continue; } + } + if is_lib_target(&runnable, cargo_spec.as_ref()) { + continue; } - // Do not suggest binary run on other target than binary - if let RunnableKind::Bin = runnable.kind { - if let Some(spec) = &cargo_spec { - match spec.target_kind { - TargetKind::Bin => {} - _ => continue, - } - } - } + res.push(to_proto::runnable(&snap, file_id, runnable)?); } @@ -817,53 +812,26 @@ pub fn handle_code_lens( if snap.config.lens.runnable() { // Gather runnables for runnable in snap.analysis().runnables(file_id)? { - let (run_title, debugee) = match &runnable.kind { - RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { - ("▶\u{fe0e} Run Test", true) - } - RunnableKind::DocTest { .. } => { - // cargo does not support -no-run for doctests - ("▶\u{fe0e} Run Doctest", false) - } - RunnableKind::Bench { .. } => { - // Nothing wrong with bench debugging - ("Run Bench", true) - } - RunnableKind::Bin => { - // Do not suggest binary run on other target than binary - match &cargo_spec { - Some(spec) => match spec.target_kind { - TargetKind::Bin => ("Run", true), - _ => continue, - }, - None => continue, - } - } - }; + if is_lib_target(&runnable, cargo_spec.as_ref()) { + continue; + } + let action = runnable.action(); let range = to_proto::range(&line_index, runnable.nav.range()); let r = to_proto::runnable(&snap, file_id, runnable)?; if snap.config.lens.run { let lens = CodeLens { range, - command: Some(Command { - title: run_title.to_string(), - command: "rust-analyzer.runSingle".into(), - arguments: Some(vec![to_value(&r).unwrap()]), - }), + command: Some(run_single_command(&r, action.run_title)), data: None, }; lenses.push(lens); } - if debugee && snap.config.lens.debug { + if action.debugee && snap.config.lens.debug { let debug_lens = CodeLens { range, - command: Some(Command { - title: "Debug".into(), - command: "rust-analyzer.debugSingle".into(), - arguments: Some(vec![to_value(r).unwrap()]), - }), + command: Some(debug_single_command(r)), data: None, }; lenses.push(debug_lens); @@ -1169,6 +1137,22 @@ fn show_references_command( } } +fn run_single_command(runnable: &lsp_ext::Runnable, title: &str) -> Command { + Command { + title: title.to_string(), + command: "rust-analyzer.runSingle".into(), + arguments: Some(vec![to_value(runnable).unwrap()]), + } +} + +fn debug_single_command(runnable: lsp_ext::Runnable) -> Command { + Command { + title: "Debug".into(), + command: "rust-analyzer.debugSingle".into(), + arguments: Some(vec![to_value(runnable).unwrap()]), + } +} + fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { lsp_ext::CommandLink { tooltip: Some(tooltip), command } } @@ -1214,3 +1198,17 @@ fn prepare_hover_actions( }) .collect() } + +fn is_lib_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool { + // Do not suggest binary run on other target than binary + if let RunnableKind::Bin = runnable.kind { + if let Some(spec) = cargo_spec { + match spec.target_kind { + TargetKind::Bin => return true, + _ => () + } + } + } + + false +} \ No newline at end of file diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1da4d80ec..710df1fbd 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -4,7 +4,7 @@ use ra_ide::{ Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, - ResolvedAssist, Runnable, RunnableKind, Severity, SourceChange, SourceFileEdit, TextEdit, + ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, }; use ra_syntax::{SyntaxKind, TextRange, TextSize}; use ra_vfs::LineEndings; @@ -662,15 +662,7 @@ pub(crate) fn runnable( let target = spec.as_ref().map(|s| s.target.clone()); let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; - let label = match &runnable.kind { - RunnableKind::Test { test_id, .. } => format!("test {}", test_id), - RunnableKind::TestMod { path } => format!("test-mod {}", path), - RunnableKind::Bench { test_id } => format!("bench {}", test_id), - RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), - RunnableKind::Bin => { - target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) - } - }; + let label = runnable.label(target); let location = location_link(snap, None, runnable.nav)?; Ok(lsp_ext::Runnable { -- cgit v1.2.3 From 3434f1dd2c47fff3df159b9d62115c2df3fd6401 Mon Sep 17 00:00:00 2001 From: vsrs Date: Sat, 6 Jun 2020 14:30:29 +0300 Subject: Add Run|Debug hover actions --- crates/ra_ide/src/hover.rs | 129 ++++++++++++++++++++++++- crates/ra_ide/src/runnables.rs | 14 ++- crates/rust-analyzer/src/config.rs | 2 + crates/rust-analyzer/src/main_loop/handlers.rs | 49 +++++++--- crates/rust-analyzer/src/to_proto.rs | 4 +- 5 files changed, 174 insertions(+), 24 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 846d8c69b..138a7a7a9 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -14,34 +14,42 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs use crate::{ display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, - FilePosition, NavigationTarget, RangeInfo, + runnables::runnable, + FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, }; #[derive(Clone, Debug, PartialEq, Eq)] pub struct HoverConfig { pub implementations: bool, + pub run: bool, + pub debug: bool, } impl Default for HoverConfig { fn default() -> Self { - Self { implementations: true } + Self { implementations: true, run: true, debug: true } } } impl HoverConfig { - pub const NO_ACTIONS: Self = Self { implementations: false }; + pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; pub fn any(&self) -> bool { - self.implementations + self.implementations || self.runnable() } pub fn none(&self) -> bool { !self.any() } + + pub fn runnable(&self) -> bool { + self.run || self.debug + } } #[derive(Debug, Clone)] pub enum HoverAction { + Runnable(Runnable), Implementaion(FilePosition), } @@ -125,6 +133,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option Option, + def: Definition, + file_id: FileId, +) -> Option { + match def { + Definition::ModuleDef(it) => match it { + ModuleDef::Module(it) => match it.definition_source(sema.db).value { + ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) + .map(|it| HoverAction::Runnable(it)), + _ => None, + }, + ModuleDef::Function(it) => { + runnable(&sema, it.source(sema.db).value.syntax().clone(), file_id) + .map(|it| HoverAction::Runnable(it)) + } + _ => None, + }, + _ => None, + } +} + fn hover_text( docs: Option, desc: Option, @@ -292,6 +326,7 @@ fn pick_best(tokens: TokenAtOffset) -> Option { #[cfg(test)] mod tests { use super::*; + use insta::assert_debug_snapshot; use ra_db::FileLoader; use ra_syntax::TextRange; @@ -309,6 +344,7 @@ mod tests { fn assert_impl_action(action: &HoverAction, position: u32) { let offset = match action { HoverAction::Implementaion(pos) => pos.offset, + it => panic!("Unexpected hover action: {:#?}", it), }; assert_eq!(offset, position.into()); } @@ -1176,4 +1212,89 @@ fn func(foo: i32) { if true { <|>foo; }; } ); assert_impl_action(&actions[0], 5); } + + #[test] + fn test_hover_test_has_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + #[test] + fn foo_<|>test() {} + ", + &["fn foo_test()"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + Runnable( + Runnable { + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..24, + name: "foo_test", + kind: FN_DEF, + focus_range: Some( + 11..19, + ), + container_name: None, + description: None, + docs: None, + }, + kind: Test { + test_id: Path( + "foo_test", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg_exprs: [], + }, + ), + ] + "###); + } + + #[test] + fn test_hover_test_mod_has_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + mod tests<|> { + #[test] + fn foo_test() {} + } + ", + &["mod tests"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + Runnable( + Runnable { + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..46, + name: "tests", + kind: MODULE, + focus_range: Some( + 4..9, + ), + container_name: None, + description: None, + docs: None, + }, + kind: TestMod { + path: "tests", + }, + cfg_exprs: [], + }, + ), + ] + "###); + } } diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 9f7b5edfd..fc57dc33d 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs @@ -11,14 +11,14 @@ use ra_syntax::{ use crate::{display::ToNav, FileId, NavigationTarget}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Runnable { pub nav: NavigationTarget, pub kind: RunnableKind, pub cfg_exprs: Vec, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum TestId { Name(String), Path(String), @@ -33,7 +33,7 @@ impl fmt::Display for TestId { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum RunnableKind { Test { test_id: TestId, attr: TestAttr }, TestMod { path: String }, @@ -95,7 +95,11 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() } -fn runnable(sema: &Semantics, item: SyntaxNode, file_id: FileId) -> Option { +pub(crate) fn runnable( + sema: &Semantics, + item: SyntaxNode, + file_id: FileId, +) -> Option { match_ast! { match item { ast::FnDef(it) => runnable_fn(sema, it, file_id), @@ -171,7 +175,7 @@ fn runnable_fn( Some(Runnable { nav, kind, cfg_exprs }) } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct TestAttr { pub ignore: bool, } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8d6efdbe8..17671f89e 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -285,6 +285,8 @@ impl Config { set(value, "/hoverActions/enable", &mut use_hover_actions); if use_hover_actions { set(value, "/hoverActions/implementations", &mut self.hover.implementations); + set(value, "/hoverActions/run", &mut self.hover.run); + set(value, "/hoverActions/debug", &mut self.hover.debug); } else { self.hover = HoverConfig::NO_ACTIONS; } diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index da16976d3..cae447eea 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -18,8 +18,8 @@ use lsp_types::{ TextDocumentIdentifier, Url, WorkspaceEdit, }; use ra_ide::{ - FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind, SearchScope, - TextEdit, + FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind, + SearchScope, TextEdit, }; use ra_prof::profile; use ra_project_model::TargetKind; @@ -403,12 +403,12 @@ pub fn handle_runnables( if !runnable.nav.full_range().contains_inclusive(offset) { continue; } - } + } if is_lib_target(&runnable, cargo_spec.as_ref()) { continue; } - res.push(to_proto::runnable(&snap, file_id, runnable)?); + res.push(to_proto::runnable(&snap, file_id, &runnable)?); } // Add `cargo check` and `cargo test` for the whole package @@ -550,7 +550,7 @@ pub fn handle_hover( }), range: Some(range), }, - actions: prepare_hover_actions(&snap, info.info.actions()), + actions: prepare_hover_actions(&snap, position.file_id, info.info.actions()), }; Ok(Some(hover)) @@ -818,7 +818,7 @@ pub fn handle_code_lens( let action = runnable.action(); let range = to_proto::range(&line_index, runnable.nav.range()); - let r = to_proto::runnable(&snap, file_id, runnable)?; + let r = to_proto::runnable(&snap, file_id, &runnable)?; if snap.config.lens.run { let lens = CodeLens { range, @@ -829,11 +829,8 @@ pub fn handle_code_lens( } if action.debugee && snap.config.lens.debug { - let debug_lens = CodeLens { - range, - command: Some(debug_single_command(r)), - data: None, - }; + let debug_lens = + CodeLens { range, command: Some(debug_single_command(r)), data: None }; lenses.push(debug_lens); } } @@ -1183,8 +1180,33 @@ fn show_impl_command_link( None } +fn to_runnable_action( + snap: &GlobalStateSnapshot, + file_id: FileId, + runnable: &Runnable, +) -> Option { + to_proto::runnable(snap, file_id, runnable).ok().map(|r| { + let mut group = lsp_ext::CommandLinkGroup::default(); + + let action = runnable.action(); + if snap.config.hover.run { + let run_command = run_single_command(&r, action.run_title); + group.commands.push(to_command_link(run_command, r.label.clone())); + } + + if snap.config.hover.debug { + let hint = r.label.clone(); + let dbg_command = debug_single_command(r); + group.commands.push(to_command_link(dbg_command, hint)); + } + + group + }) +} + fn prepare_hover_actions( snap: &GlobalStateSnapshot, + file_id: FileId, actions: &[HoverAction], ) -> Vec { if snap.config.hover.none() || !snap.config.client_caps.hover_actions { @@ -1195,6 +1217,7 @@ fn prepare_hover_actions( .iter() .filter_map(|it| match it { HoverAction::Implementaion(position) => show_impl_command_link(snap, position), + HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r), }) .collect() } @@ -1205,10 +1228,10 @@ fn is_lib_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> b if let Some(spec) = cargo_spec { match spec.target_kind { TargetKind::Bin => return true, - _ => () + _ => (), } } } false -} \ No newline at end of file +} diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 710df1fbd..5daf037da 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -656,14 +656,14 @@ pub(crate) fn resolved_code_action( pub(crate) fn runnable( snap: &GlobalStateSnapshot, file_id: FileId, - runnable: Runnable, + runnable: &Runnable, ) -> Result { let spec = CargoTargetSpec::for_file(snap, file_id)?; let target = spec.as_ref().map(|s| s.target.clone()); let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; let label = runnable.label(target); - let location = location_link(snap, None, runnable.nav)?; + let location = location_link(snap, None, runnable.nav.clone())?; Ok(lsp_ext::Runnable { label, -- cgit v1.2.3 From d66daee84906358c0119ed2eb29386454f5e4350 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 6 Jun 2020 17:52:00 +0200 Subject: Clean up handling of int/float literal types 'Unknown' int/float types actually never exist as such, they get replaced by type variables immediately. So the whole `Uncertain` thing was unnecessary and just led to a bunch of match branches that were never hit. --- crates/ra_hir_ty/src/infer.rs | 13 ++----- crates/ra_hir_ty/src/infer/expr.rs | 28 +++++++-------- crates/ra_hir_ty/src/lib.rs | 6 ++-- crates/ra_hir_ty/src/method_resolution.rs | 12 +++---- crates/ra_hir_ty/src/primitive.rs | 54 ---------------------------- crates/ra_hir_ty/src/traits/chalk/mapping.rs | 24 ++++++------- 6 files changed, 33 insertions(+), 104 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 2e16e5120..f965eb2b5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -39,8 +39,7 @@ use ra_syntax::SmolStr; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, - TypeWalk, Uncertain, + InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; use crate::{ db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, @@ -312,12 +311,6 @@ impl<'a> InferenceContext<'a> { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { Ty::Unknown => self.table.new_type_var(), - Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { - self.table.new_integer_var() - } - Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { - self.table.new_float_var() - } _ => ty, } } @@ -664,8 +657,8 @@ impl InferTy { fn fallback_value(self) -> Ty { match self { InferTy::TypeVar(..) => Ty::Unknown, - InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))), - InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))), + InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(IntTy::i32())), + InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(FloatTy::f64())), InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), } } diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 4a98e2deb..9fd310f69 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -18,7 +18,7 @@ use crate::{ traits::InEnvironment, utils::{generics, variant_data, Generics}, ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, - TraitRef, Ty, TypeCtor, Uncertain, + TraitRef, Ty, TypeCtor, }; use super::{ @@ -426,15 +426,7 @@ impl<'a> InferenceContext<'a> { match &inner_ty { // Fast path for builtins Ty::Apply(ApplicationTy { - ctor: - TypeCtor::Int(Uncertain::Known(IntTy { - signedness: Signedness::Signed, - .. - })), - .. - }) - | Ty::Apply(ApplicationTy { - ctor: TypeCtor::Int(Uncertain::Unknown), + ctor: TypeCtor::Int(IntTy { signedness: Signedness::Signed, .. }), .. }) | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) @@ -577,9 +569,7 @@ impl<'a> InferenceContext<'a> { ); self.infer_expr( *repeat, - &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( - IntTy::usize(), - )))), + &Expectation::has_type(Ty::simple(TypeCtor::Int(IntTy::usize()))), ); } } @@ -592,13 +582,19 @@ impl<'a> InferenceContext<'a> { Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) } Literal::ByteString(..) => { - let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); + let byte_type = Ty::simple(TypeCtor::Int(IntTy::u8())); let array_type = Ty::apply_one(TypeCtor::Array, byte_type); Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) } Literal::Char(..) => Ty::simple(TypeCtor::Char), - Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), - Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float((*ty).into())), + Literal::Int(_v, ty) => match ty { + Some(int_ty) => Ty::simple(TypeCtor::Int((*int_ty).into())), + None => self.table.new_integer_var(), + }, + Literal::Float(_v, ty) => match ty { + Some(float_ty) => Ty::simple(TypeCtor::Float((*float_ty).into())), + None => self.table.new_float_var(), + }, }, }; // use a new type variable if we got Ty::Unknown here diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 135976fcd..2b9372b4b 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -58,7 +58,7 @@ use ra_db::{impl_intern_key, salsa, CrateId}; use crate::{ db::HirDatabase, - primitive::{FloatTy, IntTy, Uncertain}, + primitive::{FloatTy, IntTy}, utils::{generics, make_mut_slice, Generics}, }; use display::HirDisplay; @@ -87,10 +87,10 @@ pub enum TypeCtor { Char, /// A primitive integer type. For example, `i32`. - Int(Uncertain), + Int(IntTy), /// A primitive floating-point type. For example, `f64`. - Float(Uncertain), + Float(FloatTy), /// Structures, enumerations and unions. Adt(AdtId), diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index e19628fdf..e83b39456 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -16,12 +16,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; use super::Substs; use crate::{ - autoderef, - db::HirDatabase, - primitive::{FloatBitness, Uncertain}, - utils::all_super_traits, - ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, - TypeCtor, TypeWalk, + autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, + Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; /// This is used as a key for indexing impls. @@ -147,12 +143,12 @@ impl Ty { } TypeCtor::Bool => lang_item_crate!("bool"), TypeCtor::Char => lang_item_crate!("char"), - TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { + TypeCtor::Float(f) => match f.bitness { // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), }, - TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()), + TypeCtor::Int(i) => lang_item_crate!(i.ty_to_string()), TypeCtor::Str => lang_item_crate!("str_alloc", "str"), TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), diff --git a/crates/ra_hir_ty/src/primitive.rs b/crates/ra_hir_ty/src/primitive.rs index 02a8179d9..37966b709 100644 --- a/crates/ra_hir_ty/src/primitive.rs +++ b/crates/ra_hir_ty/src/primitive.rs @@ -7,42 +7,6 @@ use std::fmt; pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, FloatBitness, IntBitness, Signedness}; -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub enum Uncertain { - Unknown, - Known(T), -} - -impl From for Uncertain { - fn from(ty: IntTy) -> Self { - Uncertain::Known(ty) - } -} - -impl fmt::Display for Uncertain { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Uncertain::Unknown => write!(f, "{{integer}}"), - Uncertain::Known(ty) => write!(f, "{}", ty), - } - } -} - -impl From for Uncertain { - fn from(ty: FloatTy) -> Self { - Uncertain::Known(ty) - } -} - -impl fmt::Display for Uncertain { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Uncertain::Unknown => write!(f, "{{float}}"), - Uncertain::Known(ty) => write!(f, "{}", ty), - } - } -} - #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct IntTy { pub signedness: Signedness, @@ -173,21 +137,3 @@ impl From for FloatTy { FloatTy { bitness: t.bitness } } } - -impl From> for Uncertain { - fn from(t: Option) -> Self { - match t { - None => Uncertain::Unknown, - Some(t) => Uncertain::Known(t.into()), - } - } -} - -impl From> for Uncertain { - fn from(t: Option) -> Self { - match t { - None => Uncertain::Unknown, - Some(t) => Uncertain::Known(t.into()), - } - } -} diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 28a5fbe3e..18e5c9c16 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -14,7 +14,7 @@ use ra_db::salsa::InternKey; use crate::{ db::HirDatabase, - primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, + primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, @@ -249,11 +249,11 @@ impl ToChalk for TypeCtor { TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), TypeCtor::Char => TypeName::Scalar(Scalar::Char), - TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), - TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => { + TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)), + TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) => { TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) } - TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => { + TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) => { TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) } @@ -268,9 +268,7 @@ impl ToChalk for TypeCtor { } TypeCtor::Never => TypeName::Never, - TypeCtor::Int(Uncertain::Unknown) - | TypeCtor::Float(Uncertain::Unknown) - | TypeCtor::Adt(_) + TypeCtor::Adt(_) | TypeCtor::Array | TypeCtor::FnPtr { .. } | TypeCtor::Closure { .. } => { @@ -291,19 +289,19 @@ impl ToChalk for TypeCtor { TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, TypeName::Scalar(Scalar::Char) => TypeCtor::Char, - TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { + TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(IntTy { signedness: Signedness::Signed, bitness: bitness_from_chalk_int(int_ty), - })), - TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { + }), + TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(IntTy { signedness: Signedness::Unsigned, bitness: bitness_from_chalk_uint(uint_ty), - })), + }), TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { - TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) + TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) } TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { - TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) + TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) } TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), -- cgit v1.2.3 From 46084f8a96dc94cad06c269d93269e7c5f7e4fad Mon Sep 17 00:00:00 2001 From: vsrs Date: Sat, 6 Jun 2020 20:10:36 +0300 Subject: Disable runnables lookup in macro-generated code. --- crates/ra_ide/src/hover.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 138a7a7a9..bbff5e81a 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -200,7 +200,16 @@ fn runnable_action( _ => None, }, ModuleDef::Function(it) => { - runnable(&sema, it.source(sema.db).value.syntax().clone(), file_id) + let src = it.source(sema.db); + if src.file_id != file_id.into() { + // Don't try to find runnables in a macro generated code. + // See tests below: + // test_hover_macro_generated_struct_fn_doc_comment + // test_hover_macro_generated_struct_fn_doc_attr + return None; + } + + runnable(&sema, src.value.syntax().clone(), file_id) .map(|it| HoverAction::Runnable(it)) } _ => None, -- cgit v1.2.3 From 9b4256dc4d9e0b633b73f5c07e6e0721bc1e9108 Mon Sep 17 00:00:00 2001 From: vsrs Date: Sat, 6 Jun 2020 22:11:17 +0300 Subject: Add lib target filtering. --- crates/rust-analyzer/src/main_loop/handlers.rs | 29 ++++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index cae447eea..eaa43f2bd 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -404,7 +404,7 @@ pub fn handle_runnables( continue; } } - if is_lib_target(&runnable, cargo_spec.as_ref()) { + if should_skip_target(&runnable, cargo_spec.as_ref()) { continue; } @@ -812,7 +812,7 @@ pub fn handle_code_lens( if snap.config.lens.runnable() { // Gather runnables for runnable in snap.analysis().runnables(file_id)? { - if is_lib_target(&runnable, cargo_spec.as_ref()) { + if should_skip_target(&runnable, cargo_spec.as_ref()) { continue; } @@ -1185,6 +1185,11 @@ fn to_runnable_action( file_id: FileId, runnable: &Runnable, ) -> Option { + let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; + if should_skip_target(runnable, cargo_spec.as_ref()) { + return None; + } + to_proto::runnable(snap, file_id, runnable).ok().map(|r| { let mut group = lsp_ext::CommandLinkGroup::default(); @@ -1222,16 +1227,18 @@ fn prepare_hover_actions( .collect() } -fn is_lib_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool { - // Do not suggest binary run on other target than binary - if let RunnableKind::Bin = runnable.kind { - if let Some(spec) = cargo_spec { - match spec.target_kind { - TargetKind::Bin => return true, - _ => (), +fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool { + match runnable.kind { + RunnableKind::Bin => { + // Do not suggest binary run on other target than binary + match &cargo_spec { + Some(spec) => match spec.target_kind { + TargetKind::Bin => false, + _ => true, + }, + None => true, } } + _ => false, } - - false } -- cgit v1.2.3 From 73684a4ae2ff5251bbff35109d2c9ad40fe4ef01 Mon Sep 17 00:00:00 2001 From: unexge Date: Sat, 6 Jun 2020 22:16:59 +0300 Subject: Add goto def for enum variant field --- crates/ra_ide/src/goto_definition.rs | 19 +++++++++++++++++++ crates/ra_ide_db/src/defs.rs | 6 ++++++ 2 files changed, 25 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index a6c86e99c..693344c31 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs @@ -886,4 +886,23 @@ mod tests { "x", ) } + + #[test] + fn goto_def_for_enum_variant_field() { + check_goto( + " + //- /lib.rs + enum Foo { + Bar { x: i32 } + } + fn baz(foo: Foo) { + match foo { + Foo::Bar { x<|> } => x + }; + } + ", + "x RECORD_FIELD_DEF FileId(1) 21..27 21..22", + "x: i32|x", + ); + } } diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 1db60b87f..52233937c 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -126,6 +126,12 @@ fn classify_name_inner(sema: &Semantics, name: &ast::Name) -> Opti Some(name_ref_class.definition()) }, ast::BindPat(it) => { + if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { + return Some(Definition::Field( + sema.resolve_record_field_pat(&record_field_pat)? + )); + } + let local = sema.to_def(&it)?; Some(Definition::Local(local)) }, -- cgit v1.2.3 From 65943c058583f912175f2cfde64ff2a0d92809b6 Mon Sep 17 00:00:00 2001 From: Leander Tentrup Date: Sun, 7 Jun 2020 14:50:02 +0200 Subject: Remove redundancy in syntax highlighting tests --- crates/ra_ide/src/syntax_highlighting/tests.rs | 59 ++++++++++++-------------- 1 file changed, 27 insertions(+), 32 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 36a1aa419..5e42c5b55 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -7,9 +7,21 @@ use crate::{ FileRange, TextRange, }; +/// Highlights the code given by the `ra_fixture` argument, renders the +/// result as HTML, and compares it with the HTML file given as `snapshot`. +/// Note that the `snapshot` file is overwritten by the rendered HTML. +fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { + let (analysis, file_id) = single_file(ra_fixture); + let dst_file = project_dir().join(snapshot); + let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); + let expected_html = &read_text(&dst_file); + fs::write(dst_file, &actual_html).unwrap(); + assert_eq_text!(expected_html, actual_html); +} + #[test] fn test_highlighting() { - let (analysis, file_id) = single_file( + check_highlighting( r#" #[derive(Clone, Debug)] struct Foo { @@ -84,17 +96,14 @@ impl Option { } "# .trim(), + "crates/ra_ide/src/snapshots/highlighting.html", + false, ); - let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html"); - let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); } #[test] fn test_rainbow_highlighting() { - let (analysis, file_id) = single_file( + check_highlighting( r#" fn main() { let hello = "hello"; @@ -110,12 +119,9 @@ fn bar() { } "# .trim(), + "crates/ra_ide/src/snapshots/rainbow_highlighting.html", + true, ); - let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html"); - let actual_html = &analysis.highlight_as_html(file_id, true).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); } #[test] @@ -153,7 +159,7 @@ fn test_ranges() { #[test] fn test_flattening() { - let (analysis, file_id) = single_file( + check_highlighting( r##" fn fixture(ra_fixture: &str) {} @@ -167,13 +173,9 @@ fn main() { ); }"## .trim(), + "crates/ra_ide/src/snapshots/highlight_injection.html", + false, ); - - let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_injection.html"); - let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); } #[test] @@ -192,7 +194,7 @@ macro_rules! test {} fn test_string_highlighting() { // The format string detection is based on macro-expansion, // thus, we have to copy the macro definition from `std` - let (analysis, file_id) = single_file( + check_highlighting( r#" macro_rules! println { ($($arg:tt)*) => ({ @@ -250,18 +252,14 @@ fn main() { println!("{ничоси}", ничоси = 92); }"# .trim(), + "crates/ra_ide/src/snapshots/highlight_strings.html", + false, ); - - let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_strings.html"); - let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); } #[test] fn test_unsafe_highlighting() { - let (analysis, file_id) = single_file( + check_highlighting( r#" unsafe fn unsafe_fn() {} @@ -282,10 +280,7 @@ fn main() { } "# .trim(), + "crates/ra_ide/src/snapshots/highlight_unsafe.html", + false, ); - let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html"); - let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); } -- cgit v1.2.3 From 3937b225e7918ae6d75849a0959754af43fbf08c Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 7 Jun 2020 10:29:03 -0400 Subject: Change management of test cfg to better support json projects --- crates/ra_project_model/src/lib.rs | 13 +++++++------ crates/rust-analyzer/src/cli/load_cargo.rs | 1 - crates/rust-analyzer/src/global_state.rs | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 7ad941279..ef443fc09 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -349,11 +349,7 @@ impl ProjectWorkspace { let file_id = load(&sysroot[krate].root)?; // Crates from sysroot have `cfg(test)` disabled - let cfg_options = { - let mut opts = default_cfg_options.clone(); - opts.remove_atom("test"); - opts - }; + let cfg_options = default_cfg_options.clone(); let env = Env::default(); let extern_source = ExternSource::default(); @@ -404,7 +400,12 @@ impl ProjectWorkspace { if let Some(file_id) = load(root) { let edition = cargo[pkg].edition; let cfg_options = { - let mut opts = default_cfg_options.clone(); + let mut opts = { + let mut opts = default_cfg_options.clone(); + opts.insert_atom("test".into()); + opts + }; + for feature in cargo[pkg].features.iter() { opts.insert_key_value("feature".into(), feature.into()); } diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index c7e86fe0c..46181b677 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -151,7 +151,6 @@ pub(crate) fn load( // FIXME: cfg options? let default_cfg_options = { let mut opts = get_rustc_cfg_options(None); - opts.insert_atom("test".into()); opts.insert_atom("debug_assertion".into()); opts }; diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 0bebb5bf6..4d871aa34 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -138,7 +138,6 @@ impl GlobalState { // FIXME: Read default cfgs from config let default_cfg_options = { let mut opts = get_rustc_cfg_options(config.cargo.target.as_ref()); - opts.insert_atom("test".into()); opts.insert_atom("debug_assertion".into()); opts }; -- cgit v1.2.3 From 3aaaf924cb649ecc3b1a59653f47d1735fa7cb5d Mon Sep 17 00:00:00 2001 From: Leander Tentrup Date: Sun, 7 Jun 2020 22:57:24 +0200 Subject: Fix bug in lexer for format specifier where the `type` and `width` were not correctly distinguished --- crates/ra_ide/src/snapshots/highlight_strings.html | 2 +- crates/ra_syntax/src/ast/tokens.rs | 37 ++++++++++++++-------- 2 files changed, 24 insertions(+), 15 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index e97192b61..6a5cf0e74 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html @@ -63,7 +63,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd println!("Hello {:^5}!", "x"); println!("Hello {:>5}!", "x"); println!("Hello {:+}!", 5); - println!("{:#x}!", 27); + println!("{:#x}!", 27); println!("Hello {:05}!", 5); println!("Hello {:05}!", -5); println!("{:#010x}!", 27); diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 04b0a4480..56378385a 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs @@ -335,16 +335,26 @@ pub trait HasFormatSpecifier: AstToken { } c if c == '_' || c.is_alphabetic() => { read_identifier(&mut chars, &mut callback); - if chars.peek().and_then(|next| next.1.as_ref().ok()).copied() - != Some('$') - { - continue; - } - skip_char_and_emit( - &mut chars, - FormatSpecifier::DollarSign, - &mut callback, - ); + // can be either width (indicated by dollar sign, or type in which case + // the next sign has to be `}`) + let next = + chars.peek().and_then(|next| next.1.as_ref().ok()).copied(); + match next { + Some('$') => skip_char_and_emit( + &mut chars, + FormatSpecifier::DollarSign, + &mut callback, + ), + Some('}') => { + skip_char_and_emit( + &mut chars, + FormatSpecifier::Close, + &mut callback, + ); + continue; + } + _ => continue, + }; } _ => {} } @@ -416,12 +426,11 @@ pub trait HasFormatSpecifier: AstToken { } } - let mut cloned = chars.clone().take(2); - let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); - if first != Some('}') { + if let Some((_, Ok('}'))) = chars.peek() { + skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); + } else { continue; } - skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); } _ => { while let Some((_, Ok(next_char))) = chars.peek() { -- cgit v1.2.3 From b7db9f058ad51b7ba47db02b581a76b6756d74e8 Mon Sep 17 00:00:00 2001 From: vsrs Date: Mon, 8 Jun 2020 13:56:31 +0300 Subject: Apply suggestions from code review --- crates/ra_ide/src/hover.rs | 12 ++++++++---- crates/rust-analyzer/src/main_loop/handlers.rs | 26 +++++++++++--------------- crates/rust-analyzer/src/to_proto.rs | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index bbff5e81a..ad78b7671 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -17,6 +17,7 @@ use crate::{ runnables::runnable, FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, }; +use test_utils::mark; #[derive(Clone, Debug, PartialEq, Eq)] pub struct HoverConfig { @@ -202,10 +203,9 @@ fn runnable_action( ModuleDef::Function(it) => { let src = it.source(sema.db); if src.file_id != file_id.into() { - // Don't try to find runnables in a macro generated code. - // See tests below: - // test_hover_macro_generated_struct_fn_doc_comment - // test_hover_macro_generated_struct_fn_doc_attr + mark::hit!(hover_macro_generated_struct_fn_doc_comment); + mark::hit!(hover_macro_generated_struct_fn_doc_attr); + return None; } @@ -1121,6 +1121,8 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_macro_generated_struct_fn_doc_comment() { + mark::check!(hover_macro_generated_struct_fn_doc_comment); + check_hover_result( r#" //- /lib.rs @@ -1147,6 +1149,8 @@ fn func(foo: i32) { if true { <|>foo; }; } #[test] fn test_hover_macro_generated_struct_fn_doc_attr() { + mark::check!(hover_macro_generated_struct_fn_doc_attr); + check_hover_result( r#" //- /lib.rs diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index eaa43f2bd..a41adf8b0 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -408,7 +408,7 @@ pub fn handle_runnables( continue; } - res.push(to_proto::runnable(&snap, file_id, &runnable)?); + res.push(to_proto::runnable(&snap, file_id, runnable)?); } // Add `cargo check` and `cargo test` for the whole package @@ -818,7 +818,7 @@ pub fn handle_code_lens( let action = runnable.action(); let range = to_proto::range(&line_index, runnable.nav.range()); - let r = to_proto::runnable(&snap, file_id, &runnable)?; + let r = to_proto::runnable(&snap, file_id, runnable)?; if snap.config.lens.run { let lens = CodeLens { range, @@ -830,7 +830,7 @@ pub fn handle_code_lens( if action.debugee && snap.config.lens.debug { let debug_lens = - CodeLens { range, command: Some(debug_single_command(r)), data: None }; + CodeLens { range, command: Some(debug_single_command(&r)), data: None }; lenses.push(debug_lens); } } @@ -1142,7 +1142,7 @@ fn run_single_command(runnable: &lsp_ext::Runnable, title: &str) -> Command { } } -fn debug_single_command(runnable: lsp_ext::Runnable) -> Command { +fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command { Command { title: "Debug".into(), command: "rust-analyzer.debugSingle".into(), @@ -1183,26 +1183,25 @@ fn show_impl_command_link( fn to_runnable_action( snap: &GlobalStateSnapshot, file_id: FileId, - runnable: &Runnable, + runnable: Runnable, ) -> Option { let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; - if should_skip_target(runnable, cargo_spec.as_ref()) { + if should_skip_target(&runnable, cargo_spec.as_ref()) { return None; } + let action: &'static _ = runnable.action(); to_proto::runnable(snap, file_id, runnable).ok().map(|r| { let mut group = lsp_ext::CommandLinkGroup::default(); - let action = runnable.action(); if snap.config.hover.run { let run_command = run_single_command(&r, action.run_title); group.commands.push(to_command_link(run_command, r.label.clone())); } if snap.config.hover.debug { - let hint = r.label.clone(); - let dbg_command = debug_single_command(r); - group.commands.push(to_command_link(dbg_command, hint)); + let dbg_command = debug_single_command(&r); + group.commands.push(to_command_link(dbg_command, r.label)); } group @@ -1222,7 +1221,7 @@ fn prepare_hover_actions( .iter() .filter_map(|it| match it { HoverAction::Implementaion(position) => show_impl_command_link(snap, position), - HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r), + HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r.clone()), }) .collect() } @@ -1232,10 +1231,7 @@ fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) RunnableKind::Bin => { // Do not suggest binary run on other target than binary match &cargo_spec { - Some(spec) => match spec.target_kind { - TargetKind::Bin => false, - _ => true, - }, + Some(spec) => spec.target_kind != TargetKind::Bin, None => true, } } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 5daf037da..710df1fbd 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -656,14 +656,14 @@ pub(crate) fn resolved_code_action( pub(crate) fn runnable( snap: &GlobalStateSnapshot, file_id: FileId, - runnable: &Runnable, + runnable: Runnable, ) -> Result { let spec = CargoTargetSpec::for_file(snap, file_id)?; let target = spec.as_ref().map(|s| s.target.clone()); let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; let label = runnable.label(target); - let location = location_link(snap, None, runnable.nav.clone())?; + let location = location_link(snap, None, runnable.nav)?; Ok(lsp_ext::Runnable { label, -- cgit v1.2.3 From c5d5d2185816d90ad1420fe544d93150cb9c9a48 Mon Sep 17 00:00:00 2001 From: unexge Date: Mon, 8 Jun 2020 14:46:58 +0300 Subject: Add `FieldShorthand` variant to `NameClass` --- crates/ra_ide/src/goto_definition.rs | 2 +- crates/ra_ide/src/syntax_highlighting.rs | 1 + crates/ra_ide_db/src/defs.rs | 56 +++++++++++++++++--------------- 3 files changed, 32 insertions(+), 27 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 693344c31..620d2dedd 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs @@ -39,7 +39,7 @@ pub(crate) fn goto_definition( reference_definition(&sema, &name_ref).to_vec() }, ast::Name(name) => { - let def = classify_name(&sema, &name)?.definition(); + let def = classify_name(&sema, &name)?.into_definition()?; let nav = def.try_to_nav(sema.db)?; vec![nav] }, diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 19ecd54d6..f6b52c35d 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -363,6 +363,7 @@ fn highlight_element( highlight_name(db, def) | HighlightModifier::Definition } Some(NameClass::ConstReference(def)) => highlight_name(db, def), + Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(), None => highlight_name_by_syntax(name) | HighlightModifier::Definition, } } diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 52233937c..853d856e7 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -82,6 +82,10 @@ pub enum NameClass { Definition(Definition), /// `None` in `if let None = Some(82) {}` ConstReference(Definition), + FieldShorthand { + local: Local, + field: Definition, + }, } impl NameClass { @@ -89,12 +93,14 @@ impl NameClass { match self { NameClass::Definition(it) => Some(it), NameClass::ConstReference(_) => None, + NameClass::FieldShorthand { local: _, field } => Some(field), } } pub fn definition(self) -> Definition { match self { NameClass::Definition(it) | NameClass::ConstReference(it) => it, + NameClass::FieldShorthand { local, field: _ } => Definition::Local(local), } } } @@ -102,18 +108,14 @@ impl NameClass { pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option { let _p = profile("classify_name"); - if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) { + let parent = name.syntax().parent()?; + + if let Some(bind_pat) = ast::BindPat::cast(parent.clone()) { if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { return Some(NameClass::ConstReference(Definition::ModuleDef(def))); } } - classify_name_inner(sema, name).map(NameClass::Definition) -} - -fn classify_name_inner(sema: &Semantics, name: &ast::Name) -> Option { - let parent = name.syntax().parent()?; - match_ast! { match parent { ast::Alias(it) => { @@ -123,69 +125,71 @@ fn classify_name_inner(sema: &Semantics, name: &ast::Name) -> Opti let name_ref = path_segment.name_ref()?; let name_ref_class = classify_name_ref(sema, &name_ref)?; - Some(name_ref_class.definition()) + Some(NameClass::Definition(name_ref_class.definition())) }, ast::BindPat(it) => { + let local = sema.to_def(&it)?; + if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { - return Some(Definition::Field( - sema.resolve_record_field_pat(&record_field_pat)? - )); + if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { + let field = Definition::Field(field); + return Some(NameClass::FieldShorthand { local, field }); + } } - let local = sema.to_def(&it)?; - Some(Definition::Local(local)) + Some(NameClass::Definition(Definition::Local(local))) }, ast::RecordFieldDef(it) => { let field: hir::Field = sema.to_def(&it)?; - Some(Definition::Field(field)) + Some(NameClass::Definition(Definition::Field(field))) }, ast::Module(it) => { let def = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::StructDef(it) => { let def: hir::Struct = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::UnionDef(it) => { let def: hir::Union = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::EnumDef(it) => { let def: hir::Enum = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::TraitDef(it) => { let def: hir::Trait = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::StaticDef(it) => { let def: hir::Static = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::EnumVariant(it) => { let def: hir::EnumVariant = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::FnDef(it) => { let def: hir::Function = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::ConstDef(it) => { let def: hir::Const = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::TypeAliasDef(it) => { let def: hir::TypeAlias = sema.to_def(&it)?; - Some(Definition::ModuleDef(def.into())) + Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, ast::MacroCall(it) => { let def = sema.to_def(&it)?; - Some(Definition::Macro(def)) + Some(NameClass::Definition(Definition::Macro(def))) }, ast::TypeParam(it) => { let def = sema.to_def(&it)?; - Some(Definition::TypeParam(def)) + Some(NameClass::Definition(Definition::TypeParam(def))) }, _ => None, } -- cgit v1.2.3 From 4a2efb2f42494f62891ac801e0a27d246bd36684 Mon Sep 17 00:00:00 2001 From: Leander Tentrup Date: Tue, 28 Apr 2020 11:01:51 +0200 Subject: Implement syntax highlighting for doctests --- crates/ra_ide/src/snapshots/highlight_doctest.html | 70 +++++++++ crates/ra_ide/src/syntax_highlighting.rs | 126 ++++++++++------ crates/ra_ide/src/syntax_highlighting/injection.rs | 168 +++++++++++++++++++++ crates/ra_ide/src/syntax_highlighting/tests.rs | 50 ++++++ 4 files changed, 368 insertions(+), 46 deletions(-) create mode 100644 crates/ra_ide/src/snapshots/highlight_doctest.html create mode 100644 crates/ra_ide/src/syntax_highlighting/injection.rs (limited to 'crates') diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html new file mode 100644 index 000000000..2f2d8c900 --- /dev/null +++ b/crates/ra_ide/src/snapshots/highlight_doctest.html @@ -0,0 +1,70 @@ + + +
impl Foo {
+    /// Constructs a new `Foo`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![allow(unused_mut)]
+    /// let mut foo: Foo = Foo::new();
+    /// ```
+    pub const fn new() -> Foo {
+        Foo { }
+    }
+
+    /// `bar` method on `Foo`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let foo = Foo::new();
+    ///
+    /// // calls bar on foo
+    /// assert!(foo.bar());
+    ///
+    /// /* multi-line
+    ///        comment */
+    ///
+    /// let multi_line_string = "Foo
+    ///   bar
+    ///          ";
+    ///
+    /// ```
+    ///
+    /// ```
+    /// let foobar = Foo::new().bar();
+    /// ```
+    pub fn foo(&self) -> bool {
+        true
+    }
+}
\ No newline at end of file diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 19ecd54d6..6903403b2 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -1,5 +1,6 @@ mod tags; mod html; +mod injection; #[cfg(test)] mod tests; @@ -10,14 +11,14 @@ use ra_ide_db::{ }; use ra_prof::profile; use ra_syntax::{ - ast::{self, HasFormatSpecifier, HasQuotes, HasStringValue}, + ast::{self, HasFormatSpecifier}, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind::*, - SyntaxToken, TextRange, WalkEvent, T, + TextRange, WalkEvent, T, }; use rustc_hash::FxHashMap; -use crate::{call_info::ActiveParameter, Analysis, FileId}; +use crate::FileId; use ast::FormatSpecifier; pub(crate) use html::highlight_as_html; @@ -123,6 +124,23 @@ pub(crate) fn highlight( _ => (), } + // Check for Rust code in documentation + match &event { + WalkEvent::Leave(NodeOrToken::Node(node)) => { + if let Some((doctest, range_mapping, new_comments)) = + injection::extract_doc_comments(node) + { + injection::highlight_doc_comment( + doctest, + range_mapping, + new_comments, + &mut stack, + ); + } + } + _ => (), + } + let element = match event { WalkEvent::Enter(it) => it, WalkEvent::Leave(_) => continue, @@ -173,7 +191,7 @@ pub(crate) fn highlight( if let Some(token) = element.as_token().cloned().and_then(ast::RawString::cast) { let expanded = element_to_highlight.as_token().unwrap().clone(); - if highlight_injection(&mut stack, &sema, token, expanded).is_some() { + if injection::highlight_injection(&mut stack, &sema, token, expanded).is_some() { continue; } } @@ -259,9 +277,8 @@ impl HighlightedRangeStack { let mut parent = prev.pop().unwrap(); for ele in children { assert!(parent.range.contains_range(ele.range)); - let mut cloned = parent.clone(); - parent.range = TextRange::new(parent.range.start(), ele.range.start()); - cloned.range = TextRange::new(ele.range.end(), cloned.range.end()); + + let cloned = Self::intersect(&mut parent, &ele); if !parent.range.is_empty() { prev.push(parent); } @@ -274,6 +291,62 @@ impl HighlightedRangeStack { } } + /// Intersects the `HighlightedRange` `parent` with `child`. + /// `parent` is mutated in place, becoming the range before `child`. + /// Returns the range (of the same type as `parent`) *after* `child`. + fn intersect(parent: &mut HighlightedRange, child: &HighlightedRange) -> HighlightedRange { + assert!(parent.range.contains_range(child.range)); + + let mut cloned = parent.clone(); + parent.range = TextRange::new(parent.range.start(), child.range.start()); + cloned.range = TextRange::new(child.range.end(), cloned.range.end()); + + cloned + } + + /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`) + /// can only modify the last range currently on the stack. + /// Can be used to do injections that span multiple ranges, like the + /// doctest injection below. + /// If `delete` is set to true, the parent range is deleted instead of + /// intersected. + /// + /// Note that `pop` can be simulated by `pop_and_inject(false)` but the + /// latter is computationally more expensive. + fn pop_and_inject(&mut self, delete: bool) { + let mut children = self.stack.pop().unwrap(); + let prev = self.stack.last_mut().unwrap(); + children.sort_by_key(|range| range.range.start()); + prev.sort_by_key(|range| range.range.start()); + + for child in children { + if let Some(idx) = + prev.iter().position(|parent| parent.range.contains_range(child.range)) + { + let cloned = Self::intersect(&mut prev[idx], &child); + let insert_idx = if delete || prev[idx].range.is_empty() { + prev.remove(idx); + idx + } else { + idx + 1 + }; + prev.insert(insert_idx, child); + if !delete && !cloned.range.is_empty() { + prev.insert(insert_idx + 1, cloned); + } + } else if let Some(_idx) = + prev.iter().position(|parent| parent.range.contains(child.range.start())) + { + unreachable!("child range should be completely contained in parent range"); + } else { + let idx = prev + .binary_search_by_key(&child.range.start(), |range| range.range.start()) + .unwrap_or_else(|x| x); + prev.insert(idx, child); + } + } + } + fn add(&mut self, range: HighlightedRange) { self.stack .last_mut() @@ -539,42 +612,3 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { tag.into() } - -fn highlight_injection( - acc: &mut HighlightedRangeStack, - sema: &Semantics, - literal: ast::RawString, - expanded: SyntaxToken, -) -> Option<()> { - let active_parameter = ActiveParameter::at_token(&sema, expanded)?; - if !active_parameter.name.starts_with("ra_fixture") { - return None; - } - let value = literal.value()?; - let (analysis, tmp_file_id) = Analysis::from_single_file(value); - - if let Some(range) = literal.open_quote_text_range() { - acc.add(HighlightedRange { - range, - highlight: HighlightTag::StringLiteral.into(), - binding_hash: None, - }) - } - - for mut h in analysis.highlight(tmp_file_id).unwrap() { - if let Some(r) = literal.map_range_up(h.range) { - h.range = r; - acc.add(h) - } - } - - if let Some(range) = literal.close_quote_text_range() { - acc.add(HighlightedRange { - range, - highlight: HighlightTag::StringLiteral.into(), - binding_hash: None, - }) - } - - Some(()) -} diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs new file mode 100644 index 000000000..3575a0fc6 --- /dev/null +++ b/crates/ra_ide/src/syntax_highlighting/injection.rs @@ -0,0 +1,168 @@ +//! Syntax highlighting injections such as highlighting of documentation tests. + +use std::{collections::BTreeMap, convert::TryFrom}; + +use ast::{HasQuotes, HasStringValue}; +use hir::Semantics; +use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; +use stdx::SepBy; + +use crate::{call_info::ActiveParameter, Analysis, HighlightTag, HighlightedRange, RootDatabase}; + +use super::HighlightedRangeStack; + +pub(super) fn highlight_injection( + acc: &mut HighlightedRangeStack, + sema: &Semantics, + literal: ast::RawString, + expanded: SyntaxToken, +) -> Option<()> { + let active_parameter = ActiveParameter::at_token(&sema, expanded)?; + if !active_parameter.name.starts_with("ra_fixture") { + return None; + } + let value = literal.value()?; + let (analysis, tmp_file_id) = Analysis::from_single_file(value); + + if let Some(range) = literal.open_quote_text_range() { + acc.add(HighlightedRange { + range, + highlight: HighlightTag::StringLiteral.into(), + binding_hash: None, + }) + } + + for mut h in analysis.highlight(tmp_file_id).unwrap() { + if let Some(r) = literal.map_range_up(h.range) { + h.range = r; + acc.add(h) + } + } + + if let Some(range) = literal.close_quote_text_range() { + acc.add(HighlightedRange { + range, + highlight: HighlightTag::StringLiteral.into(), + binding_hash: None, + }) + } + + Some(()) +} + +/// Mapping from extracted documentation code to original code +type RangesMap = BTreeMap; + +/// Extracts Rust code from documentation comments as well as a mapping from +/// the extracted source code back to the original source ranges. +/// Lastly, a vector of new comment highlight ranges (spanning only the +/// comment prefix) is returned which is used in the syntax highlighting +/// injection to replace the previous (line-spanning) comment ranges. +pub(super) fn extract_doc_comments( + node: &SyntaxNode, +) -> Option<(String, RangesMap, Vec)> { + // wrap the doctest into function body to get correct syntax highlighting + let prefix = "fn doctest() {\n"; + let suffix = "}\n"; + // Mapping from extracted documentation code to original code + let mut range_mapping: RangesMap = BTreeMap::new(); + let mut line_start = TextSize::try_from(prefix.len()).unwrap(); + let mut is_doctest = false; + // Replace the original, line-spanning comment ranges by new, only comment-prefix + // spanning comment ranges. + let mut new_comments = Vec::new(); + let doctest = node + .children_with_tokens() + .filter_map(|el| el.into_token().and_then(ast::Comment::cast)) + .filter(|comment| comment.kind().doc.is_some()) + .filter(|comment| { + if comment.text().contains("```") { + is_doctest = !is_doctest; + false + } else { + is_doctest + } + }) + .map(|comment| { + let prefix_len = comment.prefix().len(); + let line: &str = comment.text().as_str(); + let range = comment.syntax().text_range(); + + // whitespace after comment is ignored + let pos = if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) { + prefix_len + ws.len_utf8() + } else { + prefix_len + }; + + // lines marked with `#` should be ignored in output, we skip the `#` char + let pos = if let Some(ws) = line.chars().nth(pos).filter(|&c| c == '#') { + pos + ws.len_utf8() + } else { + pos + }; + + range_mapping.insert(line_start, range.start() + TextSize::try_from(pos).unwrap()); + new_comments.push(HighlightedRange { + range: TextRange::new( + range.start(), + range.start() + TextSize::try_from(pos).unwrap(), + ), + highlight: HighlightTag::Comment.into(), + binding_hash: None, + }); + line_start += range.len() - TextSize::try_from(pos).unwrap(); + line_start += TextSize::try_from('\n'.len_utf8()).unwrap(); + + line[pos..].to_owned() + }) + .sep_by("\n") + .to_string(); + + if doctest.is_empty() { + return None; + } + + let doctest = format!("{}{}{}", prefix, doctest, suffix); + Some((doctest, range_mapping, new_comments)) +} + +/// Injection of syntax highlighting of doctests. +pub(super) fn highlight_doc_comment( + text: String, + range_mapping: RangesMap, + new_comments: Vec, + stack: &mut HighlightedRangeStack, +) { + let (analysis, tmp_file_id) = Analysis::from_single_file(text); + + stack.push(); + for mut h in analysis.highlight(tmp_file_id).unwrap() { + // Determine start offset and end offset in case of multi-line ranges + let mut start_offset = None; + let mut end_offset = None; + for (line_start, orig_line_start) in range_mapping.range(..h.range.end()).rev() { + if line_start <= &h.range.start() { + start_offset.get_or_insert(orig_line_start - line_start); + break; + } else { + end_offset.get_or_insert(orig_line_start - line_start); + } + } + if let Some(start_offset) = start_offset { + h.range = TextRange::new( + h.range.start() + start_offset, + h.range.end() + end_offset.unwrap_or(start_offset), + ); + stack.add(h); + } + } + + // Inject the comment prefix highlight ranges + stack.push(); + for comment in new_comments { + stack.add(comment); + } + stack.pop_and_inject(false); + stack.pop_and_inject(true); +} diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 5e42c5b55..ba345d90a 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -284,3 +284,53 @@ fn main() { false, ); } + +#[test] +fn test_highlight_doctest() { + check_highlighting( + r#" +impl Foo { + /// Constructs a new `Foo`. + /// + /// # Examples + /// + /// ``` + /// # #![allow(unused_mut)] + /// let mut foo: Foo = Foo::new(); + /// ``` + pub const fn new() -> Foo { + Foo { } + } + + /// `bar` method on `Foo`. + /// + /// # Examples + /// + /// ``` + /// let foo = Foo::new(); + /// + /// // calls bar on foo + /// assert!(foo.bar()); + /// + /// /* multi-line + /// comment */ + /// + /// let multi_line_string = "Foo + /// bar + /// "; + /// + /// ``` + /// + /// ``` + /// let foobar = Foo::new().bar(); + /// ``` + pub fn foo(&self) -> bool { + true + } +} +"# + .trim(), + "crates/ra_ide/src/snapshots/highlight_doctest.html", + false, + ) +} -- cgit v1.2.3 From 4edf736eb23c2d94a8c65a83a83201590e847b3f Mon Sep 17 00:00:00 2001 From: unexge Date: Mon, 8 Jun 2020 15:37:12 +0300 Subject: Swap `into_definition` and `definition` semantics for `FieldShorthand` variant --- crates/ra_ide_db/src/defs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 853d856e7..1826f3ac6 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -93,14 +93,14 @@ impl NameClass { match self { NameClass::Definition(it) => Some(it), NameClass::ConstReference(_) => None, - NameClass::FieldShorthand { local: _, field } => Some(field), + NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)), } } pub fn definition(self) -> Definition { match self { NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::FieldShorthand { local, field: _ } => Definition::Local(local), + NameClass::FieldShorthand { local: _, field } => field, } } } -- cgit v1.2.3 From 48b6dd0b332d43268796b30128502e618b5b975e Mon Sep 17 00:00:00 2001 From: unexge Date: Mon, 8 Jun 2020 15:38:10 +0300 Subject: Use explicit match for extracting def from `classify_name` --- crates/ra_ide/src/goto_definition.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 620d2dedd..0798d2c36 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs @@ -1,6 +1,6 @@ use hir::Semantics; use ra_ide_db::{ - defs::{classify_name, classify_name_ref}, + defs::{classify_name, classify_name_ref, NameClass}, symbol_index, RootDatabase, }; use ra_syntax::{ @@ -39,7 +39,10 @@ pub(crate) fn goto_definition( reference_definition(&sema, &name_ref).to_vec() }, ast::Name(name) => { - let def = classify_name(&sema, &name)?.into_definition()?; + let def = match classify_name(&sema, &name)? { + NameClass::Definition(def) | NameClass::ConstReference(def) => def, + NameClass::FieldShorthand { local: _, field } => field, + }; let nav = def.try_to_nav(sema.db)?; vec![nav] }, -- cgit v1.2.3 From c476f71bdf83e930ebe5c2ad2754f24ee0925c32 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 8 Jun 2020 15:03:14 +0200 Subject: Highlight only the unsafe operator itself --- crates/ra_ide/src/syntax_highlighting.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 9ff7356c9..ab45c364a 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -480,12 +480,8 @@ fn highlight_element( _ => h, } } - PREFIX_EXPR => { - let prefix_expr = element.into_node().and_then(ast::PrefixExpr::cast)?; - match prefix_expr.op_kind() { - Some(ast::PrefixOp::Deref) => {} - _ => return None, - } + T![*] => { + let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; let expr = prefix_expr.expr()?; let ty = sema.type_of_expr(&expr)?; -- cgit v1.2.3 From 3b4d000250ae142288408cfe2abe7c10d4495c92 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 8 Jun 2020 15:23:03 +0200 Subject: Better unsafe highlihgting tests --- crates/ra_ide/src/snapshots/highlight_doctest.html | 3 ++- crates/ra_ide/src/snapshots/highlight_injection.html | 3 ++- crates/ra_ide/src/snapshots/highlight_strings.html | 3 ++- crates/ra_ide/src/snapshots/highlight_unsafe.html | 5 +++-- crates/ra_ide/src/snapshots/highlighting.html | 3 ++- crates/ra_ide/src/snapshots/rainbow_highlighting.html | 3 ++- crates/ra_ide/src/syntax_highlighting/html.rs | 3 ++- crates/ra_ide/src/syntax_highlighting/tests.rs | 2 +- 8 files changed, 16 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html index 2f2d8c900..0ae8c7efc 100644 --- a/crates/ra_ide/src/snapshots/highlight_doctest.html +++ b/crates/ra_ide/src/snapshots/highlight_doctest.html @@ -10,7 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html index fcdc98201..dec06eb51 100644 --- a/crates/ra_ide/src/snapshots/highlight_injection.html +++ b/crates/ra_ide/src/snapshots/highlight_injection.html @@ -10,7 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 6a5cf0e74..849eb3b73 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html @@ -10,7 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/src/snapshots/highlight_unsafe.html index 17ffc727c..bd24e6e38 100644 --- a/crates/ra_ide/src/snapshots/highlight_unsafe.html +++ b/crates/ra_ide/src/snapshots/highlight_unsafe.html @@ -10,7 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } @@ -42,7 +43,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd unsafe { unsafe_fn(); HasUnsafeFn.unsafe_method(); - let y = *x; + let y = *(x); let z = -x; } } \ No newline at end of file diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 42c5f3e55..e34ff5a7d 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html @@ -10,7 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 2dd61d20d..1ab06182c 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html @@ -10,7 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index 7d946c98d..5bada6252 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs @@ -69,7 +69,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } -.operator.unsafe { color: #E28C14; } +.function.unsafe { color: #BC8383; } +.operator.unsafe { color: #BC8383; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index ba345d90a..021f8e7e2 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -274,7 +274,7 @@ fn main() { unsafe { unsafe_fn(); HasUnsafeFn.unsafe_method(); - let y = *x; + let y = *(x); let z = -x; } } -- cgit v1.2.3 From 9c35f135b9c872e904ee1e838cfa69fc5745c45f Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Mon, 8 Jun 2020 10:23:20 -0400 Subject: Remove default_cfg_options, pass target instead so it can be used for building cargo workspaces --- crates/ra_project_model/src/lib.rs | 26 +++++++++++++------------- crates/rust-analyzer/src/cli/load_cargo.rs | 20 ++++---------------- crates/rust-analyzer/src/global_state.rs | 11 ++--------- 3 files changed, 19 insertions(+), 38 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index ef443fc09..4ef2e6f85 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -250,7 +250,7 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, - default_cfg_options: &CfgOptions, + target: Option<&String>, extern_source_roots: &FxHashMap, proc_macro_client: &ProcMacroClient, load: &mut dyn FnMut(&Path) -> Option, @@ -269,7 +269,7 @@ impl ProjectWorkspace { json_project::Edition::Edition2018 => Edition::Edition2018, }; let cfg_options = { - let mut opts = default_cfg_options.clone(); + let mut opts = CfgOptions::default(); for cfg in &krate.cfg { match cfg.find('=') { None => opts.insert_atom(cfg.into()), @@ -343,14 +343,13 @@ impl ProjectWorkspace { } } ProjectWorkspace::Cargo { cargo, sysroot } => { + let mut cfg_options = get_rustc_cfg_options(target); + let sysroot_crates: FxHashMap<_, _> = sysroot .crates() .filter_map(|krate| { let file_id = load(&sysroot[krate].root)?; - // Crates from sysroot have `cfg(test)` disabled - let cfg_options = default_cfg_options.clone(); - let env = Env::default(); let extern_source = ExternSource::default(); let proc_macro = vec![]; @@ -361,7 +360,7 @@ impl ProjectWorkspace { file_id, Edition::Edition2018, Some(crate_name), - cfg_options, + cfg_options.clone(), env, extern_source, proc_macro, @@ -392,6 +391,10 @@ impl ProjectWorkspace { let mut pkg_to_lib_crate = FxHashMap::default(); let mut pkg_crates = FxHashMap::default(); + + // Add test cfg for non-sysroot crates + cfg_options.insert_atom("test".into()); + // Next, create crates for each package, target pair for pkg in cargo.packages() { let mut lib_tgt = None; @@ -400,12 +403,7 @@ impl ProjectWorkspace { if let Some(file_id) = load(root) { let edition = cargo[pkg].edition; let cfg_options = { - let mut opts = { - let mut opts = default_cfg_options.clone(); - opts.insert_atom("test".into()); - opts - }; - + let mut opts = cfg_options.clone(); for feature in cargo[pkg].features.iter() { opts.insert_key_value("feature".into(), feature.into()); } @@ -562,7 +560,7 @@ impl ProjectWorkspace { } } -pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { +fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { let mut cfg_options = CfgOptions::default(); // Some nightly-only cfgs, which are required for stdlib @@ -602,6 +600,8 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), } + cfg_options.insert_atom("debug_assertion".into()); + cfg_options } diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 46181b677..8f2aeac77 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -8,8 +8,7 @@ use crossbeam_channel::{unbounded, Receiver}; use ra_db::{ExternSourceId, FileId, SourceRootId}; use ra_ide::{AnalysisChange, AnalysisHost}; use ra_project_model::{ - get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, - ProjectWorkspace, + CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, }; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -148,25 +147,14 @@ pub(crate) fn load( } } - // FIXME: cfg options? - let default_cfg_options = { - let mut opts = get_rustc_cfg_options(None); - opts.insert_atom("debug_assertion".into()); - opts - }; - - let crate_graph = ws.to_crate_graph( - &default_cfg_options, - &extern_source_roots, - proc_macro_client, - &mut |path: &Path| { + let crate_graph = + ws.to_crate_graph(None, &extern_source_roots, proc_macro_client, &mut |path: &Path| { // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs let path = path.canonicalize().ok()?; let vfs_file = vfs.load(&path); log::debug!("vfs file {:?} -> {:?}", path, vfs_file); vfs_file.map(vfs_file_to_id) - }, - ); + }); log::debug!("crate graph: {:?}", crate_graph); analysis_change.set_crate_graph(crate_graph); diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 4d871aa34..0b52030cf 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -15,7 +15,7 @@ use ra_flycheck::{Flycheck, FlycheckConfig}; use ra_ide::{ Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, }; -use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace}; +use ra_project_model::{ProcMacroClient, ProjectWorkspace}; use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; use relative_path::RelativePathBuf; use stdx::format_to; @@ -135,13 +135,6 @@ impl GlobalState { } } - // FIXME: Read default cfgs from config - let default_cfg_options = { - let mut opts = get_rustc_cfg_options(config.cargo.target.as_ref()); - opts.insert_atom("debug_assertion".into()); - opts - }; - let proc_macro_client = match &config.proc_macro_srv { None => ProcMacroClient::dummy(), Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { @@ -167,7 +160,7 @@ impl GlobalState { }; for ws in workspaces.iter() { crate_graph.extend(ws.to_crate_graph( - &default_cfg_options, + config.cargo.target.as_ref(), &extern_source_roots, &proc_macro_client, &mut load, -- cgit v1.2.3 From dbceaf522b717bd0dda89f6af1684ebd8e033aee Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Mon, 8 Jun 2020 12:10:23 -0400 Subject: Use Option<&str> for target instead of Option<&String> --- crates/ra_project_model/src/lib.rs | 6 +++--- crates/rust-analyzer/src/global_state.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 4ef2e6f85..fe03b509e 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -250,7 +250,7 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, - target: Option<&String>, + target: Option<&str>, extern_source_roots: &FxHashMap, proc_macro_client: &ProcMacroClient, load: &mut dyn FnMut(&Path) -> Option, @@ -560,7 +560,7 @@ impl ProjectWorkspace { } } -fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { +fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { let mut cfg_options = CfgOptions::default(); // Some nightly-only cfgs, which are required for stdlib @@ -578,7 +578,7 @@ fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { let mut cmd = Command::new(ra_toolchain::rustc()); cmd.args(&["--print", "cfg", "-O"]); if let Some(target) = target { - cmd.args(&["--target", target.as_str()]); + cmd.args(&["--target", target]); } let output = output(cmd)?; Ok(String::from_utf8(output.stdout)?) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 0b52030cf..73b0f881d 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -160,7 +160,7 @@ impl GlobalState { }; for ws in workspaces.iter() { crate_graph.extend(ws.to_crate_graph( - config.cargo.target.as_ref(), + config.cargo.target.as_deref(), &extern_source_roots, &proc_macro_client, &mut load, -- cgit v1.2.3 From 2a42904680041664621034c22c3f600a47107a5a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 8 Jun 2020 21:44:42 +0200 Subject: Simplify --- crates/ra_ide/src/diagnostics.rs | 4 ++-- crates/ra_ide/src/lib.rs | 2 +- crates/ra_ide/src/references/rename.rs | 6 +++--- crates/ra_ide/src/typing.rs | 6 +++--- crates/ra_ide_db/src/source_change.rs | 23 +++++++---------------- 5 files changed, 16 insertions(+), 25 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 15dc50cf1..bf14a467f 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -21,7 +21,7 @@ use ra_syntax::{ }; use ra_text_edit::{TextEdit, TextEditBuilder}; -use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceChange, SourceFileEdit}; +use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; #[derive(Debug, Copy, Clone)] pub enum Severity { @@ -115,7 +115,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec let node = d.ast(db); let replacement = format!("Ok({})", node.syntax()); let edit = TextEdit::replace(node.syntax().text_range(), replacement); - let source_change = SourceChange::source_file_edit_from(file_id, edit); + let source_change = SourceFileEdit { file_id, edit }.into(); let fix = Fix::new("Wrap with ok", source_change); res.borrow_mut().push(Diagnostic { range: sema.diagnostics_range(d).range, diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index a56718d3f..28f686767 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -503,7 +503,7 @@ impl Analysis { ) -> Cancelable> { self.with_db(|db| { let edits = ssr::parse_search_replace(query, parse_only, db)?; - Ok(SourceChange::source_file_edits(edits)) + Ok(SourceChange::from(edits)) }) } diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index 28c6349b1..915d4f4d3 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs @@ -171,7 +171,7 @@ fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option Option { diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs index e713f4b7e..f40ae8304 100644 --- a/crates/ra_ide_db/src/source_change.rs +++ b/crates/ra_ide_db/src/source_change.rs @@ -22,17 +22,6 @@ impl SourceChange { ) -> Self { SourceChange { source_file_edits, file_system_edits, is_snippet: false } } - - /// Creates a new SourceChange with the given label, - /// containing only the given `SourceFileEdits`. - pub fn source_file_edits(edits: Vec) -> Self { - SourceChange { source_file_edits: edits, file_system_edits: vec![], is_snippet: false } - } - /// Creates a new SourceChange with the given label - /// from the given `FileId` and `TextEdit` - pub fn source_file_edit_from(file_id: FileId, edit: TextEdit) -> Self { - SourceFileEdit { file_id, edit }.into() - } } #[derive(Debug, Clone)] @@ -43,11 +32,13 @@ pub struct SourceFileEdit { impl From for SourceChange { fn from(edit: SourceFileEdit) -> SourceChange { - SourceChange { - source_file_edits: vec![edit], - file_system_edits: Vec::new(), - is_snippet: false, - } + vec![edit].into() + } +} + +impl From> for SourceChange { + fn from(source_file_edits: Vec) -> SourceChange { + SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false } } } -- cgit v1.2.3 From e38685cb48a44c3321922f5f7228072b503d2973 Mon Sep 17 00:00:00 2001 From: Avi Dessauer Date: Mon, 8 Jun 2020 17:49:06 -0400 Subject: Parse default unsafe fn --- crates/ra_parser/src/grammar/items.rs | 8 ++++- .../parser/inline/ok/0163_default_unsafe_fn.rast | 40 ++++++++++++++++++++++ .../parser/inline/ok/0163_default_unsafe_fn.rs | 3 ++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 9c14b954a..56cfb509d 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -121,7 +121,13 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul T![unsafe] => { // test default_unsafe_impl // default unsafe impl Foo {} - if p.nth(2) == T![impl] { + + // test default_unsafe_fn + // impl T for Foo { + // default unsafe fn foo() {} + // } + let sk = p.nth(2); + if sk == T![impl] || sk == T![fn] { p.bump_remap(T![default]); p.bump(T![unsafe]); has_mods = true; diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast new file mode 100644 index 000000000..adb6159f4 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast @@ -0,0 +1,40 @@ +SOURCE_FILE@0..50 + IMPL_DEF@0..49 + IMPL_KW@0..4 "impl" + WHITESPACE@4..5 " " + PATH_TYPE@5..6 + PATH@5..6 + PATH_SEGMENT@5..6 + NAME_REF@5..6 + IDENT@5..6 "T" + WHITESPACE@6..7 " " + FOR_KW@7..10 "for" + WHITESPACE@10..11 " " + PATH_TYPE@11..14 + PATH@11..14 + PATH_SEGMENT@11..14 + NAME_REF@11..14 + IDENT@11..14 "Foo" + WHITESPACE@14..15 " " + ITEM_LIST@15..49 + L_CURLY@15..16 "{" + WHITESPACE@16..21 "\n " + FN_DEF@21..47 + DEFAULT_KW@21..28 "default" + WHITESPACE@28..29 " " + UNSAFE_KW@29..35 "unsafe" + WHITESPACE@35..36 " " + FN_KW@36..38 "fn" + WHITESPACE@38..39 " " + NAME@39..42 + IDENT@39..42 "foo" + PARAM_LIST@42..44 + L_PAREN@42..43 "(" + R_PAREN@43..44 ")" + WHITESPACE@44..45 " " + BLOCK_EXPR@45..47 + L_CURLY@45..46 "{" + R_CURLY@46..47 "}" + WHITESPACE@47..48 "\n" + R_CURLY@48..49 "}" + WHITESPACE@49..50 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs new file mode 100644 index 000000000..12926cd8a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs @@ -0,0 +1,3 @@ +impl T for Foo { + default unsafe fn foo() {} +} -- cgit v1.2.3 From 38fa4d17fb9622044ee0f0bc50d6c71d5aa46dd1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 00:01:40 +0200 Subject: Simplify API --- crates/ra_assists/src/assist_context.rs | 99 ++++++---------------- crates/ra_assists/src/handlers/add_function.rs | 2 +- .../handlers/extract_struct_from_enum_variant.rs | 58 ++++++------- crates/ra_assists/src/handlers/fix_visibility.rs | 4 +- 4 files changed, 56 insertions(+), 107 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 1925db8b2..edd8255f4 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -1,5 +1,7 @@ //! See `AssistContext` +use std::mem; + use algo::find_covering_element; use hir::Semantics; use ra_db::{FileId, FileRange}; @@ -19,7 +21,6 @@ use crate::{ assist_config::{AssistConfig, SnippetCap}, Assist, AssistId, GroupLabel, ResolvedAssist, }; -use rustc_hash::FxHashMap; /// `AssistContext` allows to apply an assist or check if it could be applied. /// @@ -139,16 +140,6 @@ impl Assists { let label = Assist::new(id, label.into(), None, target); self.add_impl(label, f) } - pub(crate) fn add_in_multiple_files( - &mut self, - id: AssistId, - label: impl Into, - target: TextRange, - f: impl FnOnce(&mut AssistDirector), - ) -> Option<()> { - let label = Assist::new(id, label.into(), None, target); - self.add_impl_multiple_files(label, f) - } pub(crate) fn add_group( &mut self, group: &GroupLabel, @@ -173,31 +164,6 @@ impl Assists { Some(()) } - fn add_impl_multiple_files( - &mut self, - label: Assist, - f: impl FnOnce(&mut AssistDirector), - ) -> Option<()> { - if !self.resolve { - self.buf.push((label, None)); - return None; - } - let mut director = AssistDirector::default(); - f(&mut director); - let changes = director.finish(); - let file_edits: Vec = - changes.into_iter().map(|mut change| change.source_file_edits.pop().unwrap()).collect(); - - let source_change = SourceChange { - source_file_edits: file_edits, - file_system_edits: vec![], - is_snippet: false, - }; - - self.buf.push((label, Some(source_change))); - Some(()) - } - fn finish(mut self) -> Vec<(Assist, Option)> { self.buf.sort_by_key(|(label, _edit)| label.target.len()); self.buf @@ -206,13 +172,32 @@ impl Assists { pub(crate) struct AssistBuilder { edit: TextEditBuilder, - file: FileId, + file_id: FileId, is_snippet: bool, + edits: Vec, } impl AssistBuilder { - pub(crate) fn new(file: FileId) -> AssistBuilder { - AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false } + pub(crate) fn new(file_id: FileId) -> AssistBuilder { + AssistBuilder { + edit: TextEditBuilder::default(), + file_id, + is_snippet: false, + edits: Vec::new(), + } + } + + pub(crate) fn edit_file(&mut self, file_id: FileId) { + self.file_id = file_id; + } + + fn commit(&mut self) { + let edit = mem::take(&mut self.edit).finish(); + if !edit.is_empty() { + let new_edit = SourceFileEdit { file_id: self.file_id, edit }; + assert!(!self.edits.iter().any(|it| it.file_id == new_edit.file_id)); + self.edits.push(new_edit); + } } /// Remove specified `range` of text. @@ -270,48 +255,18 @@ impl AssistBuilder { algo::diff(&node, &new).into_text_edit(&mut self.edit) } - // FIXME: better API - pub(crate) fn set_file(&mut self, assist_file: FileId) { - self.file = assist_file; - } - // FIXME: kill this API /// Get access to the raw `TextEditBuilder`. pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { &mut self.edit } - fn finish(self) -> SourceChange { - let edit = self.edit.finish(); - let source_file_edit = SourceFileEdit { file_id: self.file, edit }; - let mut res: SourceChange = source_file_edit.into(); + fn finish(mut self) -> SourceChange { + self.commit(); + let mut res: SourceChange = mem::take(&mut self.edits).into(); if self.is_snippet { res.is_snippet = true; } res } } - -pub(crate) struct AssistDirector { - builders: FxHashMap, -} - -impl AssistDirector { - pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { - let mut builder = self.builders.entry(file_id).or_insert(AssistBuilder::new(file_id)); - f(&mut builder); - } - - fn finish(self) -> Vec { - self.builders - .into_iter() - .map(|(_, builder)| builder.finish()) - .collect::>() - } -} - -impl Default for AssistDirector { - fn default() -> Self { - AssistDirector { builders: FxHashMap::default() } - } -} diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index 24f931a85..1cfbd75aa 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs @@ -64,7 +64,7 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let target = call.syntax().text_range(); acc.add(AssistId("add_function"), "Add function", target, |builder| { let function_template = function_builder.render(); - builder.set_file(function_template.file); + builder.edit_file(function_template.file); let new_fn = function_template.to_string(ctx.config.snippet_cap); match ctx.config.snippet_cap { Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 2c455a1fd..44db7917a 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -1,20 +1,17 @@ +use hir::{EnumVariant, Module, ModuleDef, Name}; +use ra_db::FileId; +use ra_fmt::leading_indent; use ra_ide_db::{defs::Definition, search::Reference, RootDatabase}; use ra_syntax::{ algo::find_node_at_offset, - ast::{self, AstNode, NameOwner}, + ast::{self, ArgListOwner, AstNode, NameOwner, VisibilityOwner}, SourceFile, SyntaxNode, TextRange, TextSize, }; +use rustc_hash::FxHashSet; use crate::{ - assist_context::{AssistBuilder, AssistDirector}, - utils::insert_use_statement, - AssistContext, AssistId, Assists, + assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId, Assists, }; -use ast::{ArgListOwner, VisibilityOwner}; -use hir::{EnumVariant, Module, ModuleDef, Name}; -use ra_db::FileId; -use ra_fmt::leading_indent; -use rustc_hash::FxHashSet; // Assist: extract_struct_from_enum_variant // @@ -50,11 +47,11 @@ pub(crate) fn extract_struct_from_enum_variant( let enum_module_def = ModuleDef::from(enum_hir); let current_module = enum_hir.module(ctx.db); let target = variant.syntax().text_range(); - acc.add_in_multiple_files( + acc.add( AssistId("extract_struct_from_enum_variant"), "Extract struct from enum variant", target, - |edit| { + |builder| { let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); let res = definition.find_usages(&ctx.db, None); let start_offset = variant.parent_enum().syntax().text_range().start(); @@ -64,7 +61,7 @@ pub(crate) fn extract_struct_from_enum_variant( let source_file = ctx.sema.parse(reference.file_range.file_id); update_reference( ctx, - edit, + builder, reference, &source_file, &enum_module_def, @@ -73,7 +70,7 @@ pub(crate) fn extract_struct_from_enum_variant( ); } extract_struct_def( - edit, + builder, enum_ast.syntax(), &variant_name, &field_list.to_string(), @@ -82,7 +79,7 @@ pub(crate) fn extract_struct_from_enum_variant( &visibility, ); let list_range = field_list.syntax().text_range(); - update_variant(edit, &variant_name, ctx.frange.file_id, list_range); + update_variant(builder, &variant_name, ctx.frange.file_id, list_range); }, ) } @@ -115,7 +112,7 @@ fn insert_import( } fn extract_struct_def( - edit: &mut AssistDirector, + builder: &mut AssistBuilder, enum_ast: &SyntaxNode, variant_name: &str, variant_list: &str, @@ -142,14 +139,13 @@ fn extract_struct_def( list_with_visibility(variant_list), indent ); - edit.perform(file_id, |builder| { - builder.insert(start_offset, struct_def); - }); + builder.edit_file(file_id); + builder.insert(start_offset, struct_def); Some(()) } fn update_variant( - edit: &mut AssistDirector, + builder: &mut AssistBuilder, variant_name: &str, file_id: FileId, list_range: TextRange, @@ -158,15 +154,14 @@ fn update_variant( list_range.start().checked_add(TextSize::from(1))?, list_range.end().checked_sub(TextSize::from(1))?, ); - edit.perform(file_id, |builder| { - builder.replace(inside_variant_range, variant_name); - }); + builder.edit_file(file_id); + builder.replace(inside_variant_range, variant_name); Some(()) } fn update_reference( ctx: &AssistContext, - edit: &mut AssistDirector, + builder: &mut AssistBuilder, reference: Reference, source_file: &SourceFile, enum_module_def: &ModuleDef, @@ -186,16 +181,15 @@ fn update_reference( list_range.start().checked_add(TextSize::from(1))?, list_range.end().checked_sub(TextSize::from(1))?, ); - edit.perform(reference.file_range.file_id, |builder| { - if !visited_modules_set.contains(&module) { - if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name) - .is_some() - { - visited_modules_set.insert(module); - } + builder.edit_file(reference.file_range.file_id); + if !visited_modules_set.contains(&module) { + if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name) + .is_some() + { + visited_modules_set.insert(module); } - builder.replace(inside_list_range, format!("{}{}", segment, list)); - }); + } + builder.replace(inside_list_range, format!("{}{}", segment, list)); Some(()) } diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs index 9ec42f568..531b3560f 100644 --- a/crates/ra_assists/src/handlers/fix_visibility.rs +++ b/crates/ra_assists/src/handlers/fix_visibility.rs @@ -63,7 +63,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O }; acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { - builder.set_file(target_file); + builder.edit_file(target_file); match ctx.config.snippet_cap { Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), None => builder.insert(offset, format!("{} ", missing_visibility)), @@ -106,7 +106,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { - builder.set_file(target_file); + builder.edit_file(target_file); match ctx.config.snippet_cap { Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), None => builder.insert(offset, format!("{} ", missing_visibility)), -- cgit v1.2.3 From 055b9b64bce2808ed31eb4547cea16ec282d6897 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Wed, 3 Jun 2020 14:54:05 -0700 Subject: Finish transition to cfgs from the separate atoms and features. --- crates/ra_project_model/src/json_project.rs | 42 +---------------------------- crates/ra_project_model/src/lib.rs | 6 ----- 2 files changed, 1 insertion(+), 47 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs index 09c06fef9..ee2de4c25 100644 --- a/crates/ra_project_model/src/json_project.rs +++ b/crates/ra_project_model/src/json_project.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashSet; use serde::Deserialize; /// Roots and crates that compose this Rust project. @@ -28,16 +28,9 @@ pub struct Crate { pub(crate) edition: Edition, pub(crate) deps: Vec, - // This is the preferred method of providing cfg options. #[serde(default)] pub(crate) cfg: FxHashSet, - // These two are here for transition only. - #[serde(default)] - pub(crate) atom_cfgs: FxHashSet, - #[serde(default)] - pub(crate) key_value_cfgs: FxHashMap, - pub(crate) out_dir: Option, pub(crate) proc_macro_dylib_path: Option, } @@ -99,37 +92,4 @@ mod tests { assert!(krate.cfg.contains(&"feature=feature_2".to_string())); assert!(krate.cfg.contains(&"other=value".to_string())); } - - #[test] - fn test_crate_deserialization_old_json() { - let raw_json = json!( { - "crate_id": 2, - "root_module": "this/is/a/file/path.rs", - "deps": [ - { - "crate": 1, - "name": "some_dep_crate" - }, - ], - "edition": "2015", - "atom_cfgs": [ - "atom_1", - "atom_2", - ], - "key_value_cfgs": { - "feature": "feature_1", - "feature": "feature_2", - "other": "value", - }, - }); - - let krate: Crate = serde_json::from_value(raw_json).unwrap(); - - assert!(krate.atom_cfgs.contains(&"atom_1".to_string())); - assert!(krate.atom_cfgs.contains(&"atom_2".to_string())); - assert!(krate.key_value_cfgs.contains_key(&"feature".to_string())); - assert_eq!(krate.key_value_cfgs.get("feature"), Some(&"feature_2".to_string())); - assert!(krate.key_value_cfgs.contains_key(&"other".to_string())); - assert_eq!(krate.key_value_cfgs.get("other"), Some(&"value".to_string())); - } } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index fe03b509e..47fa34ddf 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -280,12 +280,6 @@ impl ProjectWorkspace { } } } - for name in &krate.atom_cfgs { - opts.insert_atom(name.into()); - } - for (key, value) in &krate.key_value_cfgs { - opts.insert_key_value(key.into(), value.into()); - } opts }; -- cgit v1.2.3 From 2785362a1f9a3436072152e5499ac5d7c4d98cc4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 10:50:25 +0200 Subject: Update crates/ra_parser/src/grammar/items.rs --- crates/ra_parser/src/grammar/items.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 56cfb509d..97642bc24 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -126,8 +126,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // impl T for Foo { // default unsafe fn foo() {} // } - let sk = p.nth(2); - if sk == T![impl] || sk == T![fn] { + if p.nth(2) == T![impl] || p.nth(2) == T![fn] { p.bump_remap(T![default]); p.bump(T![unsafe]); has_mods = true; -- cgit v1.2.3 From 5233766ce51d7593bb02d041bd63fa3aad44f666 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 11:33:28 +0200 Subject: Simplify unwrapping of blocks --- crates/ra_assists/src/handlers/unwrap_block.rs | 128 ++++++++++--------------- 1 file changed, 49 insertions(+), 79 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 8440c7d0f..c48ecaae8 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs @@ -1,8 +1,5 @@ use ra_fmt::unwrap_trivial_block; -use ra_syntax::{ - ast::{self, ElseBranch, Expr, LoopBodyOwner}, - match_ast, AstNode, TextRange, T, -}; +use ra_syntax::{ast, AstNode, TextRange, T}; use crate::{AssistContext, AssistId, Assists}; @@ -29,89 +26,62 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let parent = block.syntax().parent()?; let assist_id = AssistId("unwrap_block"); let assist_label = "Unwrap block"; - - let (expr, expr_to_unwrap) = match_ast! { - match parent { - ast::ForExpr(for_expr) => { - let block_expr = for_expr.loop_body()?; - let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; - (ast::Expr::ForExpr(for_expr), expr_to_unwrap) - }, - ast::WhileExpr(while_expr) => { - let block_expr = while_expr.loop_body()?; - let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; - (ast::Expr::WhileExpr(while_expr), expr_to_unwrap) - }, - ast::LoopExpr(loop_expr) => { - let block_expr = loop_expr.loop_body()?; - let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; - (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap) - }, - ast::IfExpr(if_expr) => { - let mut resp = None; - - let then_branch = if_expr.then_branch()?; - if then_branch.l_curly_token()?.text_range().contains_range(ctx.frange.range) { - if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { - // For `else if` blocks - let ancestor_then_branch = ancestor.then_branch()?; - let l_curly_token = then_branch.l_curly_token()?; - - let target = then_branch.syntax().text_range(); - return acc.add(assist_id, assist_label, target, |edit| { - let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); - let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); - - edit.delete(range_to_del_rest); - edit.delete(range_to_del_else_if); - edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); - }); - } else { - resp = Some((ast::Expr::IfExpr(if_expr.clone()), Expr::BlockExpr(then_branch))); - } - } else if let Some(else_branch) = if_expr.else_branch() { - match else_branch { - ElseBranch::Block(else_block) => { - let l_curly_token = else_block.l_curly_token()?; - if l_curly_token.text_range().contains_range(ctx.frange.range) { - let target = else_block.syntax().text_range(); - return acc.add(assist_id, assist_label, target, |edit| { - let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); - - edit.delete(range_to_del); - edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); - }); - } - }, - ElseBranch::IfExpr(_) => {}, - } + let parent = ast::Expr::cast(parent)?; + + match parent.clone() { + ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (), + ast::Expr::IfExpr(if_expr) => { + let then_branch = if_expr.then_branch()?; + if then_branch == block { + if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { + // For `else if` blocks + let ancestor_then_branch = ancestor.then_branch()?; + + let target = then_branch.syntax().text_range(); + return acc.add(assist_id, assist_label, target, |edit| { + let range_to_del_else_if = TextRange::new( + ancestor_then_branch.syntax().text_range().end(), + l_curly_token.text_range().start(), + ); + let range_to_del_rest = TextRange::new( + then_branch.syntax().text_range().end(), + if_expr.syntax().text_range().end(), + ); + + edit.delete(range_to_del_rest); + edit.delete(range_to_del_else_if); + edit.replace( + target, + update_expr_string(then_branch.to_string(), &[' ', '{']), + ); + }); } - - resp? - }, - _ => return None, + } else { + let target = block.syntax().text_range(); + return acc.add(assist_id, assist_label, target, |edit| { + let range_to_del = TextRange::new( + then_branch.syntax().text_range().end(), + l_curly_token.text_range().start(), + ); + + edit.delete(range_to_del); + edit.replace(target, update_expr_string(block.to_string(), &[' ', '{'])); + }); + } } + _ => return None, }; - let target = expr_to_unwrap.syntax().text_range(); - acc.add(assist_id, assist_label, target, |edit| { - edit.replace( - expr.syntax().text_range(), - update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), + let unwrapped = unwrap_trivial_block(block); + let target = unwrapped.syntax().text_range(); + acc.add(assist_id, assist_label, target, |builder| { + builder.replace( + parent.syntax().text_range(), + update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']), ); }) } -fn extract_expr(cursor_range: TextRange, block: ast::BlockExpr) -> Option { - let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range); - - if cursor_in_range { - Some(unwrap_trivial_block(block)) - } else { - None - } -} - fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { let expr_string = expr_str.trim_start_matches(trim_start_pat); let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); -- cgit v1.2.3 From 53cc2c16e7a53660fb7322d96284ef199699e250 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 11:52:45 +0200 Subject: Unwrap block works with match arms --- crates/ra_assists/src/handlers/unwrap_block.rs | 44 +++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index c48ecaae8..1fb13f481 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs @@ -1,5 +1,11 @@ use ra_fmt::unwrap_trivial_block; -use ra_syntax::{ast, AstNode, TextRange, T}; +use ra_syntax::{ + ast::{ + self, + edit::{AstNodeEdit, IndentLevel}, + }, + AstNode, TextRange, T, +}; use crate::{AssistContext, AssistId, Assists}; @@ -21,15 +27,21 @@ use crate::{AssistContext, AssistId, Assists}; // } // ``` pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let l_curly_token = ctx.find_token_at_offset(T!['{'])?; - let block = ast::BlockExpr::cast(l_curly_token.parent())?; - let parent = block.syntax().parent()?; let assist_id = AssistId("unwrap_block"); let assist_label = "Unwrap block"; + + let l_curly_token = ctx.find_token_at_offset(T!['{'])?; + let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; + let mut parent = block.syntax().parent()?; + if ast::MatchArm::can_cast(parent.kind()) { + parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))? + } + let parent = ast::Expr::cast(parent)?; match parent.clone() { ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (), + ast::Expr::MatchExpr(_) => block = block.dedent(IndentLevel(1)), ast::Expr::IfExpr(if_expr) => { let then_branch = if_expr.then_branch()?; if then_branch == block { @@ -459,6 +471,30 @@ mod tests { ); } + #[test] + fn unwrap_match_arm() { + check_assist( + unwrap_block, + r#" +fn main() { + match rel_path { + Ok(rel_path) => {<|> + let rel_path = RelativePathBuf::from_path(rel_path).ok()?; + Some((*id, rel_path)) + } + Err(_) => None, + } +} +"#, + r#" +fn main() { + let rel_path = RelativePathBuf::from_path(rel_path).ok()?; + Some((*id, rel_path)) +} +"#, + ); + } + #[test] fn simple_if_in_while_bad_cursor_position() { check_assist_not_applicable( -- cgit v1.2.3 From 8cad7d1a2b2546986aa8f42207875b1c8eed948a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 12:38:47 +0200 Subject: Use correct indent when replacing with match --- crates/ra_assists/src/handlers/early_return.rs | 2 +- .../src/handlers/replace_if_let_with_match.rs | 37 ++++++++++++++++++++-- crates/ra_syntax/src/ast/edit.rs | 13 +++++--- 3 files changed, 45 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 4cc75a7ce..dfade7432 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs @@ -154,7 +154,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) parent_block: &ast::BlockExpr, if_expr: &ast::IfExpr, ) -> SyntaxNode { - let then_block_items = then_block.dedent(IndentLevel::from(1)); + let then_block_items = then_block.dedent(IndentLevel(1)); let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); let end_of_then = if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index e016f51c3..dfcd787de 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs @@ -51,6 +51,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { let match_expr = { let then_arm = { + let then_block = then_block.reset_indent().indent(IndentLevel(1)); let then_expr = unwrap_trivial_block(then_block); make::match_arm(vec![pat.clone()], then_expr) }; @@ -64,8 +65,8 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) let else_expr = unwrap_trivial_block(else_block); make::match_arm(vec![pattern], else_expr) }; - make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) - .indent(IndentLevel::from_node(if_expr.syntax())) + let match_expr = make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])); + match_expr.indent(IndentLevel::from_node(if_expr.syntax())) }; edit.replace_ast::(if_expr.into(), match_expr); @@ -213,4 +214,36 @@ fn foo(x: Result) { "#, ); } + + #[test] + fn nested_indent() { + check_assist( + replace_if_let_with_match, + r#" +fn main() { + if true { + <|>if let Ok(rel_path) = path.strip_prefix(root_path) { + let rel_path = RelativePathBuf::from_path(rel_path).ok()?; + Some((*id, rel_path)) + } else { + None + } + } +} +"#, + r#" +fn main() { + if true { + match path.strip_prefix(root_path) { + Ok(rel_path) => { + let rel_path = RelativePathBuf::from_path(rel_path).ok()?; + Some((*id, rel_path)) + } + _ => None, + } + } +} +"#, + ) + } } diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 29eb3fcb9..2ef173a03 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs @@ -579,12 +579,17 @@ pub trait AstNodeEdit: AstNode + Clone + Sized { rewriter.rewrite_ast(self) } #[must_use] - fn indent(&self, indent: IndentLevel) -> Self { - Self::cast(indent.increase_indent(self.syntax().clone())).unwrap() + fn indent(&self, level: IndentLevel) -> Self { + Self::cast(level.increase_indent(self.syntax().clone())).unwrap() } #[must_use] - fn dedent(&self, indent: IndentLevel) -> Self { - Self::cast(indent.decrease_indent(self.syntax().clone())).unwrap() + fn dedent(&self, level: IndentLevel) -> Self { + Self::cast(level.decrease_indent(self.syntax().clone())).unwrap() + } + #[must_use] + fn reset_indent(&self) -> Self { + let level = IndentLevel::from_node(self.syntax()); + self.dedent(level) } } -- cgit v1.2.3 From d8571e076c0bbb3219fb3ed250279b158d75e683 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 13:17:22 +0200 Subject: Simplify --- crates/ra_db/src/input.rs | 12 ++++-------- crates/ra_db/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 4d2d3b48a..a8d6466ea 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -337,15 +337,11 @@ impl Env { } impl ExternSource { - pub fn extern_path(&self, path: impl AsRef) -> Option<(ExternSourceId, RelativePathBuf)> { - let path = path.as_ref(); + pub fn extern_path(&self, path: &Path) -> Option<(ExternSourceId, RelativePathBuf)> { self.extern_paths.iter().find_map(|(root_path, id)| { - if let Ok(rel_path) = path.strip_prefix(root_path) { - let rel_path = RelativePathBuf::from_path(rel_path).ok()?; - Some((*id, rel_path)) - } else { - None - } + let rel_path = path.strip_prefix(root_path).ok()?; + let rel_path = RelativePathBuf::from_path(rel_path).ok()?; + Some((*id, rel_path)) }) } diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 91e0ee619..2ab314884 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -158,7 +158,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { if std::path::Path::new(path).is_absolute() { let krate = *self.relevant_crates(anchor).get(0)?; let (extern_source_id, relative_file) = - self.0.crate_graph()[krate].extern_source.extern_path(path)?; + self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; let source_root = self.0.source_root(SourceRootId(extern_source_id.0)); source_root.file_by_relative_path(&relative_file) -- cgit v1.2.3 From 16943e533c68427e3381e03b49de29e0d6c0450c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 13:36:08 +0200 Subject: Minor, use `T!` --- crates/ra_parser/src/grammar/paths.rs | 2 +- crates/ra_parser/src/grammar/patterns.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs index 332acc1a0..428aa711e 100644 --- a/crates/ra_parser/src/grammar/paths.rs +++ b/crates/ra_parser/src/grammar/paths.rs @@ -3,7 +3,7 @@ use super::*; pub(super) const PATH_FIRST: TokenSet = - token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLON, L_ANGLE]; + token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]]; pub(super) fn is_path_start(p: &Parser) -> bool { is_use_path_start(p) || p.at(T![<]) diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 68fb2fc73..264cf262e 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs @@ -4,7 +4,7 @@ use super::*; pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST .union(paths::PATH_FIRST) - .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS, DOT]); + .union(token_set![T![box], T![ref], T![mut], T!['('], T!['['], T![&], T![_], T![-], T![.]]); pub(crate) fn pattern(p: &mut Parser) { pattern_r(p, PAT_RECOVERY_SET); -- cgit v1.2.3 From e8d50578ab2702ff5f0955285c979c6923f14f80 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 9 Jun 2020 13:45:18 +0200 Subject: Correctly parse <_> paths in patterns closes #3659 --- crates/ra_parser/src/grammar/patterns.rs | 6 +- .../parser/err/0024_many_type_parens.rast | 74 +++++++++++----------- .../inline/ok/0164_type_path_in_pattern.rast | 38 +++++++++++ .../parser/inline/ok/0164_type_path_in_pattern.rs | 1 + 4 files changed, 80 insertions(+), 39 deletions(-) create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast create mode 100644 crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 264cf262e..427c0eb49 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs @@ -88,7 +88,9 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option { _ => bind_pat(p, true), }, - _ if paths::is_use_path_start(p) => path_or_macro_pat(p), + // test type_path_in_pattern + // fn main() { let <_>::Foo = (); } + _ if paths::is_path_start(p) => path_or_macro_pat(p), _ if is_literal_pat_start(p) => literal_pat(p), T![.] if p.at(T![..]) => dot_dot_pat(p), @@ -138,7 +140,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker { // let Bar(..) = (); // } fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker { - assert!(paths::is_use_path_start(p)); + assert!(paths::is_path_start(p)); let m = p.start(); paths::expr_path(p); let kind = match p.current() { diff --git a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast index 7c957fdde..48610a5eb 100644 --- a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast +++ b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast @@ -180,44 +180,45 @@ SOURCE_FILE@0..240 EXPR_STMT@150..180 TUPLE_EXPR@150..180 L_PAREN@150..151 "(" - BIN_EXPR@151..180 - BIN_EXPR@151..178 - BIN_EXPR@151..169 - BIN_EXPR@151..167 - BIN_EXPR@151..164 - FOR_EXPR@151..157 - FOR_KW@151..154 "for" - ERROR@154..155 - L_ANGLE@154..155 "<" - ERROR@155..157 - LIFETIME@155..157 "\'a" - R_ANGLE@157..158 ">" - WHITESPACE@158..159 " " + FOR_EXPR@151..180 + FOR_KW@151..154 "for" + PATH_PAT@154..158 + PATH@154..158 + PATH_SEGMENT@154..158 + L_ANGLE@154..155 "<" + ERROR@155..157 + LIFETIME@155..157 "\'a" + R_ANGLE@157..158 ">" + WHITESPACE@158..159 " " + BIN_EXPR@159..180 + BIN_EXPR@159..178 + BIN_EXPR@159..169 + BIN_EXPR@159..167 PATH_EXPR@159..164 PATH@159..164 PATH_SEGMENT@159..164 NAME_REF@159..164 IDENT@159..164 "Trait" - L_ANGLE@164..165 "<" - ERROR@165..167 - LIFETIME@165..167 "\'a" - R_ANGLE@167..168 ">" - ERROR@168..169 - R_PAREN@168..169 ")" - WHITESPACE@169..170 " " - PLUS@170..171 "+" - WHITESPACE@171..172 " " - PAREN_EXPR@172..178 - L_PAREN@172..173 "(" - PATH_EXPR@173..177 - PATH@173..177 - PATH_SEGMENT@173..177 - NAME_REF@173..177 - IDENT@173..177 "Copy" - R_PAREN@177..178 ")" - R_ANGLE@178..179 ">" - ERROR@179..180 - SEMICOLON@179..180 ";" + L_ANGLE@164..165 "<" + ERROR@165..167 + LIFETIME@165..167 "\'a" + R_ANGLE@167..168 ">" + ERROR@168..169 + R_PAREN@168..169 ")" + WHITESPACE@169..170 " " + PLUS@170..171 "+" + WHITESPACE@171..172 " " + PAREN_EXPR@172..178 + L_PAREN@172..173 "(" + PATH_EXPR@173..177 + PATH@173..177 + PATH_SEGMENT@173..177 + NAME_REF@173..177 + IDENT@173..177 "Copy" + R_PAREN@177..178 ")" + R_ANGLE@178..179 ">" + ERROR@179..180 + SEMICOLON@179..180 ";" WHITESPACE@180..185 "\n " LET_STMT@185..235 LET_KW@185..188 "let" @@ -302,13 +303,12 @@ error 146..146: expected expression error 147..147: expected SEMICOLON error 148..148: expected expression error 149..149: expected SEMICOLON -error 154..154: expected pattern -error 155..155: expected IN_KW -error 155..155: expected expression -error 157..157: expected a block +error 155..155: expected type +error 158..158: expected IN_KW error 165..165: expected expression error 168..168: expected expression error 179..179: expected expression +error 180..180: expected a block error 180..180: expected COMMA error 180..180: expected expression error 180..180: expected R_PAREN diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast new file mode 100644 index 000000000..868899275 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast @@ -0,0 +1,38 @@ +SOURCE_FILE@0..33 + FN_DEF@0..32 + FN_KW@0..2 "fn" + WHITESPACE@2..3 " " + NAME@3..7 + IDENT@3..7 "main" + PARAM_LIST@7..9 + L_PAREN@7..8 "(" + R_PAREN@8..9 ")" + WHITESPACE@9..10 " " + BLOCK_EXPR@10..32 + L_CURLY@10..11 "{" + WHITESPACE@11..12 " " + LET_STMT@12..30 + LET_KW@12..15 "let" + WHITESPACE@15..16 " " + PATH_PAT@16..24 + PATH@16..24 + PATH@16..19 + PATH_SEGMENT@16..19 + L_ANGLE@16..17 "<" + PLACEHOLDER_TYPE@17..18 + UNDERSCORE@17..18 "_" + R_ANGLE@18..19 ">" + COLON2@19..21 "::" + PATH_SEGMENT@21..24 + NAME_REF@21..24 + IDENT@21..24 "Foo" + WHITESPACE@24..25 " " + EQ@25..26 "=" + WHITESPACE@26..27 " " + TUPLE_EXPR@27..29 + L_PAREN@27..28 "(" + R_PAREN@28..29 ")" + SEMICOLON@29..30 ";" + WHITESPACE@30..31 " " + R_CURLY@31..32 "}" + WHITESPACE@32..33 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs new file mode 100644 index 000000000..ebe26834d --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs @@ -0,0 +1 @@ +fn main() { let <_>::Foo = (); } -- cgit v1.2.3 From 684b6fa1b8cd41b03ba485084690f78991820645 Mon Sep 17 00:00:00 2001 From: Clemens Wasser Date: Tue, 9 Jun 2020 21:47:54 +0200 Subject: flycheck now uses the configured features --- crates/ra_flycheck/src/lib.rs | 24 +++++++++++++++++++++--- crates/rust-analyzer/src/config.rs | 4 +++- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'crates') diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index 041e38a9f..6c4170529 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs @@ -18,8 +18,17 @@ pub use cargo_metadata::diagnostic::{ #[derive(Clone, Debug, PartialEq, Eq)] pub enum FlycheckConfig { - CargoCommand { command: String, all_targets: bool, all_features: bool, extra_args: Vec }, - CustomCommand { command: String, args: Vec }, + CargoCommand { + command: String, + all_targets: bool, + all_features: bool, + features: Vec, + extra_args: Vec, + }, + CustomCommand { + command: String, + args: Vec, + }, } /// Flycheck wraps the shared state and communication machinery used for @@ -188,7 +197,13 @@ impl FlycheckThread { self.check_process = None; let mut cmd = match &self.config { - FlycheckConfig::CargoCommand { command, all_targets, all_features, extra_args } => { + FlycheckConfig::CargoCommand { + command, + all_targets, + all_features, + extra_args, + features, + } => { let mut cmd = Command::new(ra_toolchain::cargo()); cmd.arg(command); cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) @@ -198,6 +213,9 @@ impl FlycheckThread { } if *all_features { cmd.arg("--all-features"); + } else if !features.is_empty() { + cmd.arg("--features"); + cmd.arg(features.join(" ")); } cmd.args(extra_args); cmd diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 17671f89e..5d5f7d66a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -147,6 +147,7 @@ impl Default for Config { all_targets: true, all_features: false, extra_args: Vec::new(), + features: Vec::new(), }), inlay_hints: InlayHintsConfig { @@ -234,13 +235,14 @@ impl Config { } // otherwise configure command customizations _ => { - if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets, all_features }) + if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets, all_features, features }) = &mut self.check { set(value, "/checkOnSave/extraArgs", extra_args); set(value, "/checkOnSave/command", command); set(value, "/checkOnSave/allTargets", all_targets); set(value, "/checkOnSave/allFeatures", all_features); + *features = self.cargo.features.clone(); } } }; -- cgit v1.2.3 From f4ed2da966d1e568a67a7cae68880b2eb717c2cd Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Tue, 9 Jun 2020 19:58:39 -0700 Subject: Correct "debug_assertion" to "debug_assertions" to match the cfg option that the rust debug assert macros use. --- crates/ra_project_model/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index fe03b509e..6604f5092 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -600,7 +600,7 @@ fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), } - cfg_options.insert_atom("debug_assertion".into()); + cfg_options.insert_atom("debug_assertions".into()); cfg_options } -- cgit v1.2.3 From 47ef544fa57ca1833b466e491315e54a88780b4d Mon Sep 17 00:00:00 2001 From: Clemens Wasser Date: Wed, 10 Jun 2020 08:51:11 +0200 Subject: Added the rust-analyzer.checkOnSave.features option. --- crates/rust-analyzer/src/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 5d5f7d66a..320414ecf 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -242,7 +242,10 @@ impl Config { set(value, "/checkOnSave/command", command); set(value, "/checkOnSave/allTargets", all_targets); set(value, "/checkOnSave/allFeatures", all_features); - *features = self.cargo.features.clone(); + set(value, "/checkOnSave/features", features); + if features.is_empty() && !self.cargo.features.is_empty() { + *features = self.cargo.features.clone(); + } } } }; -- cgit v1.2.3 From 33b905883819038ad67476fe14b7b48212a73f93 Mon Sep 17 00:00:00 2001 From: Clemens Wasser Date: Wed, 10 Jun 2020 09:27:25 +0200 Subject: Most of the checkOnSafe options now default to the cargo equivalent. --- crates/rust-analyzer/src/config.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 320414ecf..617612dc3 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -241,7 +241,11 @@ impl Config { set(value, "/checkOnSave/extraArgs", extra_args); set(value, "/checkOnSave/command", command); set(value, "/checkOnSave/allTargets", all_targets); - set(value, "/checkOnSave/allFeatures", all_features); + if let Some(new_all_features) = get(value, "/checkOnSave/allFeatures") { + *all_features = new_all_features; + } else { + *all_features = self.cargo.all_features; + } set(value, "/checkOnSave/features", features); if features.is_empty() && !self.cargo.features.is_empty() { *features = self.cargo.features.clone(); -- cgit v1.2.3 From fe21fc2d259cbe2a32bfee3432f2c51ade079083 Mon Sep 17 00:00:00 2001 From: Clemens Wasser Date: Wed, 10 Jun 2020 09:37:26 +0200 Subject: checkOnSafe.features and checkOnSafe.allFeatures now work identically. --- crates/rust-analyzer/src/config.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 617612dc3..1253db836 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -241,15 +241,8 @@ impl Config { set(value, "/checkOnSave/extraArgs", extra_args); set(value, "/checkOnSave/command", command); set(value, "/checkOnSave/allTargets", all_targets); - if let Some(new_all_features) = get(value, "/checkOnSave/allFeatures") { - *all_features = new_all_features; - } else { - *all_features = self.cargo.all_features; - } - set(value, "/checkOnSave/features", features); - if features.is_empty() && !self.cargo.features.is_empty() { - *features = self.cargo.features.clone(); - } + *all_features = get(value, "/checkOnSave/allFeatures").unwrap_or(self.cargo.all_features); + *features = get(value, "/checkOnSave/features").unwrap_or(self.cargo.features.clone()); } } }; -- cgit v1.2.3 From 27ebe5d33e08d92c1a032dc27f19094571bd19cd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 10 Jun 2020 12:08:35 +0200 Subject: Reduce OUT_DIR special casing --- crates/ra_project_model/src/lib.rs | 20 ++++++---------- crates/rust-analyzer/src/cli/load_cargo.rs | 38 +++++++++++++++--------------- crates/rust-analyzer/src/global_state.rs | 35 +++++++++++++-------------- 3 files changed, 43 insertions(+), 50 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index c1f7e3ac5..cb0e27dce 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -47,17 +47,21 @@ pub struct PackageRoot { path: PathBuf, /// Is a member of the current workspace is_member: bool, + out_dir: Option, } impl PackageRoot { pub fn new_member(path: PathBuf) -> PackageRoot { - Self { path, is_member: true } + Self { path, is_member: true, out_dir: None } } pub fn new_non_member(path: PathBuf) -> PackageRoot { - Self { path, is_member: false } + Self { path, is_member: false, out_dir: None } } pub fn path(&self) -> &Path { &self.path } + pub fn out_dir(&self) -> Option<&Path> { + self.out_dir.as_deref() + } pub fn is_member(&self) -> bool { self.is_member } @@ -204,6 +208,7 @@ impl ProjectWorkspace { .map(|pkg| PackageRoot { path: cargo[pkg].root().to_path_buf(), is_member: cargo[pkg].is_member, + out_dir: cargo[pkg].out_dir.clone(), }) .chain(sysroot.crates().map(|krate| { PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) @@ -212,17 +217,6 @@ impl ProjectWorkspace { } } - pub fn out_dirs(&self) -> Vec { - match self { - ProjectWorkspace::Json { project } => { - project.crates.iter().filter_map(|krate| krate.out_dir.as_ref()).cloned().collect() - } - ProjectWorkspace::Cargo { cargo, sysroot: _ } => { - cargo.packages().filter_map(|pkg| cargo[pkg].out_dir.as_ref()).cloned().collect() - } - } - } - pub fn proc_macro_dylib_paths(&self) -> Vec { match self { ProjectWorkspace::Json { project } => project diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 8f2aeac77..45af96317 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -36,28 +36,28 @@ pub fn load_cargo( )?; let mut extern_dirs = FxHashSet::default(); - extern_dirs.extend(ws.out_dirs()); - - let mut project_roots = ws.to_roots(); - project_roots.extend(extern_dirs.iter().cloned().map(PackageRoot::new_non_member)); let (sender, receiver) = unbounded(); let sender = Box::new(move |t| sender.send(t).unwrap()); - let (mut vfs, roots) = Vfs::new( - project_roots - .iter() - .map(|pkg_root| { - RootEntry::new( - pkg_root.path().to_owned(), - RustPackageFilterBuilder::default() - .set_member(pkg_root.is_member()) - .into_vfs_filter(), - ) - }) - .collect(), - sender, - Watch(false), - ); + + let mut roots = Vec::new(); + let project_roots = ws.to_roots(); + for root in &project_roots { + roots.push(RootEntry::new( + root.path().to_owned(), + RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(), + )); + + if let Some(out_dir) = root.out_dir() { + extern_dirs.insert(out_dir.to_path_buf()); + roots.push(RootEntry::new( + out_dir.to_owned(), + RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(), + )) + } + } + + let (mut vfs, roots) = Vfs::new(roots, sender, Watch(false)); let source_roots = roots .into_iter() diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 73b0f881d..96d91b12d 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -89,8 +89,7 @@ impl GlobalState { ) -> GlobalState { let mut change = AnalysisChange::new(); - let extern_dirs: FxHashSet<_> = - workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); + let mut extern_dirs: FxHashSet = FxHashSet::default(); let mut local_roots = Vec::new(); let roots: Vec<_> = { @@ -100,22 +99,22 @@ impl GlobalState { .exclude(exclude_globs.iter().cloned()) .into_vfs_filter() }; - workspaces - .iter() - .flat_map(ProjectWorkspace::to_roots) - .map(|pkg_root| { - let path = pkg_root.path().to_owned(); - if pkg_root.is_member() { - local_roots.push(path.clone()); - } - RootEntry::new(path, create_filter(pkg_root.is_member())) - }) - .chain( - extern_dirs - .iter() - .map(|path| RootEntry::new(path.to_owned(), create_filter(false))), - ) - .collect() + let mut roots = Vec::new(); + for root in workspaces.iter().flat_map(ProjectWorkspace::to_roots) { + let path = root.path().to_owned(); + if root.is_member() { + local_roots.push(path.clone()); + } + roots.push(RootEntry::new(path, create_filter(root.is_member()))); + if let Some(out_dir) = root.out_dir() { + extern_dirs.insert(out_dir.to_path_buf()); + roots.push(RootEntry::new( + out_dir.to_path_buf(), + create_filter(root.is_member()), + )) + } + } + roots }; let (task_sender, task_receiver) = unbounded(); -- cgit v1.2.3 From 506e1ddbfa5213f254923da9bbf0efddc6f1fc34 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 10 Jun 2020 11:30:48 +0100 Subject: Separating parsing of `for` in predicates and types --- crates/ra_parser/src/grammar/type_params.rs | 22 +- crates/ra_parser/src/grammar/types.rs | 15 +- crates/ra_syntax/src/ast.rs | 6 +- crates/ra_syntax/src/ast/generated/nodes.rs | 2 + .../parser/err/0027_incomplere_where_for.rast | 15 +- .../parser/err/0044_unexpected_for_type.rast | 88 +++++ .../parser/err/0044_unexpected_for_type.rs | 3 + .../parser/inline/ok/0003_where_pred_for.rast | 367 +++++++++++++++++---- .../parser/inline/ok/0003_where_pred_for.rs | 18 +- .../test_data/parser/inline/ok/0081_for_type.rast | 256 +++----------- .../test_data/parser/inline/ok/0081_for_type.rs | 4 +- 11 files changed, 506 insertions(+), 290 deletions(-) create mode 100644 crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast create mode 100644 crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index 50e4900c3..b3508c732 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs @@ -191,10 +191,30 @@ fn where_predicate(p: &mut Parser) { } _ => { // test where_pred_for - // fn test() + // fn for_trait() // where // for<'a> F: Fn(&'a str) // { } + // fn for_ref() + // where + // for<'a> &'a F: Debug + // { } + // fn for_parens() + // where + // for<'a> (&'a F): Fn(&'a str) + // { } + // fn for_slice() + // where + // for<'a> [&'a F]: Eq + // { } + // fn for_qpath(_t: &T) + // where + // for<'a> <&'a T as Baz>::Foo: Iterator + // { } + if p.at(T![for]) { + types::for_binder(p); + } + types::type_(p); if p.at(T![:]) { diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index fe1a039cb..63dd3774f 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs @@ -216,19 +216,20 @@ pub(super) fn for_binder(p: &mut Parser) { // test for_type // type A = for<'a> fn() -> (); -// fn foo(_t: &T) where for<'a> &'a T: Iterator {} -// fn bar(_t: &T) where for<'a> &'a mut T: Iterator {} -// fn baz(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {} +// type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); pub(super) fn for_type(p: &mut Parser) { assert!(p.at(T![for])); let m = p.start(); for_binder(p); match p.current() { - T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), - T![&] => reference_type(p), - _ if paths::is_path_start(p) => path_type_(p, false), - _ => p.error("expected a path"), + T![fn] | T![unsafe] | T![extern] => {} + // OK: legacy trait object format + _ if paths::is_use_path_start(p) => {} + _ => { + p.error("expected a function pointer or path"); + } } + type_no_bounds(p); m.complete(p, FOR_TYPE); } diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index eddc807d5..9d02aeef3 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -285,6 +285,8 @@ where let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); + assert!(pred.for_token().is_none()); + assert!(pred.type_param_list().is_none()); assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string()); assert_bound("Clone", bounds.next()); assert_bound("Copy", bounds.next()); @@ -322,6 +324,8 @@ where let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); - assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string()); + assert!(pred.for_token().is_some()); + assert_eq!("<'a>", pred.type_param_list().unwrap().syntax().text().to_string()); + assert_eq!("F", pred.type_ref().unwrap().syntax().text().to_string()); assert_bound("Fn(&'a str)", bounds.next()); } diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index cb430ca01..40081ebb1 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs @@ -2052,6 +2052,8 @@ pub struct WherePred { } impl ast::TypeBoundsOwner for WherePred {} impl WherePred { + pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } + pub fn type_param_list(&self) -> Option { support::child(&self.syntax) } pub fn lifetime_token(&self) -> Option { support::token(&self.syntax, T![lifetime]) } diff --git a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast index 568a4cc02..4d6461d1e 100644 --- a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast +++ b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast @@ -12,17 +12,16 @@ SOURCE_FILE@0..30 WHERE_KW@13..18 "where" WHITESPACE@18..19 " " WHERE_PRED@19..26 - FOR_TYPE@19..26 - FOR_KW@19..22 "for" - TYPE_PARAM_LIST@22..26 - L_ANGLE@22..23 "<" - LIFETIME_PARAM@23..25 - LIFETIME@23..25 "\'a" - R_ANGLE@25..26 ">" + FOR_KW@19..22 "for" + TYPE_PARAM_LIST@22..26 + L_ANGLE@22..23 "<" + LIFETIME_PARAM@23..25 + LIFETIME@23..25 "\'a" + R_ANGLE@25..26 ">" WHITESPACE@26..27 "\n" BLOCK_EXPR@27..29 L_CURLY@27..28 "{" R_CURLY@28..29 "}" WHITESPACE@29..30 "\n" -error 26..26: expected a path +error 26..26: expected type error 26..26: expected colon diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast new file mode 100644 index 000000000..3400beff0 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast @@ -0,0 +1,88 @@ +SOURCE_FILE@0..79 + TYPE_ALIAS_DEF@0..25 + TYPE_KW@0..4 "type" + WHITESPACE@4..5 " " + NAME@5..6 + IDENT@5..6 "A" + WHITESPACE@6..7 " " + EQ@7..8 "=" + WHITESPACE@8..9 " " + FOR_TYPE@9..24 + FOR_KW@9..12 "for" + TYPE_PARAM_LIST@12..16 + L_ANGLE@12..13 "<" + LIFETIME_PARAM@13..15 + LIFETIME@13..15 "\'a" + R_ANGLE@15..16 ">" + WHITESPACE@16..17 " " + REFERENCE_TYPE@17..24 + AMP@17..18 "&" + LIFETIME@18..20 "\'a" + WHITESPACE@20..21 " " + PATH_TYPE@21..24 + PATH@21..24 + PATH_SEGMENT@21..24 + NAME_REF@21..24 + IDENT@21..24 "u32" + SEMICOLON@24..25 ";" + WHITESPACE@25..26 "\n" + TYPE_ALIAS_DEF@26..54 + TYPE_KW@26..30 "type" + WHITESPACE@30..31 " " + NAME@31..32 + IDENT@31..32 "B" + WHITESPACE@32..33 " " + EQ@33..34 "=" + WHITESPACE@34..35 " " + FOR_TYPE@35..53 + FOR_KW@35..38 "for" + TYPE_PARAM_LIST@38..42 + L_ANGLE@38..39 "<" + LIFETIME_PARAM@39..41 + LIFETIME@39..41 "\'a" + R_ANGLE@41..42 ">" + WHITESPACE@42..43 " " + TUPLE_TYPE@43..53 + L_PAREN@43..44 "(" + REFERENCE_TYPE@44..51 + AMP@44..45 "&" + LIFETIME@45..47 "\'a" + WHITESPACE@47..48 " " + PATH_TYPE@48..51 + PATH@48..51 + PATH_SEGMENT@48..51 + NAME_REF@48..51 + IDENT@48..51 "u32" + COMMA@51..52 "," + R_PAREN@52..53 ")" + SEMICOLON@53..54 ";" + WHITESPACE@54..55 "\n" + TYPE_ALIAS_DEF@55..78 + TYPE_KW@55..59 "type" + WHITESPACE@59..60 " " + NAME@60..61 + IDENT@60..61 "B" + WHITESPACE@61..62 " " + EQ@62..63 "=" + WHITESPACE@63..64 " " + FOR_TYPE@64..77 + FOR_KW@64..67 "for" + TYPE_PARAM_LIST@67..71 + L_ANGLE@67..68 "<" + LIFETIME_PARAM@68..70 + LIFETIME@68..70 "\'a" + R_ANGLE@70..71 ">" + WHITESPACE@71..72 " " + SLICE_TYPE@72..77 + L_BRACK@72..73 "[" + PATH_TYPE@73..76 + PATH@73..76 + PATH_SEGMENT@73..76 + NAME_REF@73..76 + IDENT@73..76 "u32" + R_BRACK@76..77 "]" + SEMICOLON@77..78 ";" + WHITESPACE@78..79 "\n" +error 16..16: expected a function pointer or path +error 42..42: expected a function pointer or path +error 71..71: expected a function pointer or path diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs new file mode 100644 index 000000000..f34ac7fc5 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs @@ -0,0 +1,3 @@ +type A = for<'a> &'a u32; +type B = for<'a> (&'a u32,); +type B = for<'a> [u32]; diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast index 9dc473e43..4f88bfe43 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast @@ -1,61 +1,310 @@ -SOURCE_FILE@0..49 - FN_DEF@0..48 +SOURCE_FILE@0..292 + FN_DEF@0..53 FN_KW@0..2 "fn" WHITESPACE@2..3 " " - NAME@3..7 - IDENT@3..7 "test" - TYPE_PARAM_LIST@7..10 - L_ANGLE@7..8 "<" - TYPE_PARAM@8..9 - NAME@8..9 - IDENT@8..9 "F" - R_ANGLE@9..10 ">" - PARAM_LIST@10..12 - L_PAREN@10..11 "(" - R_PAREN@11..12 ")" - WHITESPACE@12..13 "\n" - WHERE_CLAUSE@13..44 - WHERE_KW@13..18 "where" - WHITESPACE@18..22 "\n " - WHERE_PRED@22..44 - FOR_TYPE@22..31 - FOR_KW@22..25 "for" - TYPE_PARAM_LIST@25..29 - L_ANGLE@25..26 "<" - LIFETIME_PARAM@26..28 - LIFETIME@26..28 "\'a" - R_ANGLE@28..29 ">" - WHITESPACE@29..30 " " - PATH_TYPE@30..31 - PATH@30..31 - PATH_SEGMENT@30..31 - NAME_REF@30..31 - IDENT@30..31 "F" - COLON@31..32 ":" - WHITESPACE@32..33 " " - TYPE_BOUND_LIST@33..44 - TYPE_BOUND@33..44 - PATH_TYPE@33..44 - PATH@33..44 - PATH_SEGMENT@33..44 - NAME_REF@33..35 - IDENT@33..35 "Fn" - PARAM_LIST@35..44 - L_PAREN@35..36 "(" - PARAM@36..43 - REFERENCE_TYPE@36..43 - AMP@36..37 "&" - LIFETIME@37..39 "\'a" - WHITESPACE@39..40 " " - PATH_TYPE@40..43 - PATH@40..43 - PATH_SEGMENT@40..43 - NAME_REF@40..43 - IDENT@40..43 "str" - R_PAREN@43..44 ")" - WHITESPACE@44..45 "\n" - BLOCK_EXPR@45..48 - L_CURLY@45..46 "{" - WHITESPACE@46..47 " " - R_CURLY@47..48 "}" - WHITESPACE@48..49 "\n" + NAME@3..12 + IDENT@3..12 "for_trait" + TYPE_PARAM_LIST@12..15 + L_ANGLE@12..13 "<" + TYPE_PARAM@13..14 + NAME@13..14 + IDENT@13..14 "F" + R_ANGLE@14..15 ">" + PARAM_LIST@15..17 + L_PAREN@15..16 "(" + R_PAREN@16..17 ")" + WHITESPACE@17..18 "\n" + WHERE_CLAUSE@18..49 + WHERE_KW@18..23 "where" + WHITESPACE@23..27 "\n " + WHERE_PRED@27..49 + FOR_KW@27..30 "for" + TYPE_PARAM_LIST@30..34 + L_ANGLE@30..31 "<" + LIFETIME_PARAM@31..33 + LIFETIME@31..33 "\'a" + R_ANGLE@33..34 ">" + WHITESPACE@34..35 " " + PATH_TYPE@35..36 + PATH@35..36 + PATH_SEGMENT@35..36 + NAME_REF@35..36 + IDENT@35..36 "F" + COLON@36..37 ":" + WHITESPACE@37..38 " " + TYPE_BOUND_LIST@38..49 + TYPE_BOUND@38..49 + PATH_TYPE@38..49 + PATH@38..49 + PATH_SEGMENT@38..49 + NAME_REF@38..40 + IDENT@38..40 "Fn" + PARAM_LIST@40..49 + L_PAREN@40..41 "(" + PARAM@41..48 + REFERENCE_TYPE@41..48 + AMP@41..42 "&" + LIFETIME@42..44 "\'a" + WHITESPACE@44..45 " " + PATH_TYPE@45..48 + PATH@45..48 + PATH_SEGMENT@45..48 + NAME_REF@45..48 + IDENT@45..48 "str" + R_PAREN@48..49 ")" + WHITESPACE@49..50 "\n" + BLOCK_EXPR@50..53 + L_CURLY@50..51 "{" + WHITESPACE@51..52 " " + R_CURLY@52..53 "}" + WHITESPACE@53..54 "\n" + FN_DEF@54..103 + FN_KW@54..56 "fn" + WHITESPACE@56..57 " " + NAME@57..64 + IDENT@57..64 "for_ref" + TYPE_PARAM_LIST@64..67 + L_ANGLE@64..65 "<" + TYPE_PARAM@65..66 + NAME@65..66 + IDENT@65..66 "F" + R_ANGLE@66..67 ">" + PARAM_LIST@67..69 + L_PAREN@67..68 "(" + R_PAREN@68..69 ")" + WHITESPACE@69..70 "\n" + WHERE_CLAUSE@70..99 + WHERE_KW@70..75 "where" + WHITESPACE@75..79 "\n " + WHERE_PRED@79..99 + FOR_KW@79..82 "for" + TYPE_PARAM_LIST@82..86 + L_ANGLE@82..83 "<" + LIFETIME_PARAM@83..85 + LIFETIME@83..85 "\'a" + R_ANGLE@85..86 ">" + WHITESPACE@86..87 " " + REFERENCE_TYPE@87..92 + AMP@87..88 "&" + LIFETIME@88..90 "\'a" + WHITESPACE@90..91 " " + PATH_TYPE@91..92 + PATH@91..92 + PATH_SEGMENT@91..92 + NAME_REF@91..92 + IDENT@91..92 "F" + COLON@92..93 ":" + WHITESPACE@93..94 " " + TYPE_BOUND_LIST@94..99 + TYPE_BOUND@94..99 + PATH_TYPE@94..99 + PATH@94..99 + PATH_SEGMENT@94..99 + NAME_REF@94..99 + IDENT@94..99 "Debug" + WHITESPACE@99..100 "\n" + BLOCK_EXPR@100..103 + L_CURLY@100..101 "{" + WHITESPACE@101..102 " " + R_CURLY@102..103 "}" + WHITESPACE@103..104 "\n" + FN_DEF@104..164 + FN_KW@104..106 "fn" + WHITESPACE@106..107 " " + NAME@107..117 + IDENT@107..117 "for_parens" + TYPE_PARAM_LIST@117..120 + L_ANGLE@117..118 "<" + TYPE_PARAM@118..119 + NAME@118..119 + IDENT@118..119 "F" + R_ANGLE@119..120 ">" + PARAM_LIST@120..122 + L_PAREN@120..121 "(" + R_PAREN@121..122 ")" + WHITESPACE@122..123 "\n" + WHERE_CLAUSE@123..160 + WHERE_KW@123..128 "where" + WHITESPACE@128..132 "\n " + WHERE_PRED@132..160 + FOR_KW@132..135 "for" + TYPE_PARAM_LIST@135..139 + L_ANGLE@135..136 "<" + LIFETIME_PARAM@136..138 + LIFETIME@136..138 "\'a" + R_ANGLE@138..139 ">" + WHITESPACE@139..140 " " + PAREN_TYPE@140..147 + L_PAREN@140..141 "(" + REFERENCE_TYPE@141..146 + AMP@141..142 "&" + LIFETIME@142..144 "\'a" + WHITESPACE@144..145 " " + PATH_TYPE@145..146 + PATH@145..146 + PATH_SEGMENT@145..146 + NAME_REF@145..146 + IDENT@145..146 "F" + R_PAREN@146..147 ")" + COLON@147..148 ":" + WHITESPACE@148..149 " " + TYPE_BOUND_LIST@149..160 + TYPE_BOUND@149..160 + PATH_TYPE@149..160 + PATH@149..160 + PATH_SEGMENT@149..160 + NAME_REF@149..151 + IDENT@149..151 "Fn" + PARAM_LIST@151..160 + L_PAREN@151..152 "(" + PARAM@152..159 + REFERENCE_TYPE@152..159 + AMP@152..153 "&" + LIFETIME@153..155 "\'a" + WHITESPACE@155..156 " " + PATH_TYPE@156..159 + PATH@156..159 + PATH_SEGMENT@156..159 + NAME_REF@156..159 + IDENT@156..159 "str" + R_PAREN@159..160 ")" + WHITESPACE@160..161 "\n" + BLOCK_EXPR@161..164 + L_CURLY@161..162 "{" + WHITESPACE@162..163 " " + R_CURLY@163..164 "}" + WHITESPACE@164..165 "\n" + FN_DEF@165..215 + FN_KW@165..167 "fn" + WHITESPACE@167..168 " " + NAME@168..177 + IDENT@168..177 "for_slice" + TYPE_PARAM_LIST@177..180 + L_ANGLE@177..178 "<" + TYPE_PARAM@178..179 + NAME@178..179 + IDENT@178..179 "F" + R_ANGLE@179..180 ">" + PARAM_LIST@180..182 + L_PAREN@180..181 "(" + R_PAREN@181..182 ")" + WHITESPACE@182..183 "\n" + WHERE_CLAUSE@183..211 + WHERE_KW@183..188 "where" + WHITESPACE@188..192 "\n " + WHERE_PRED@192..211 + FOR_KW@192..195 "for" + TYPE_PARAM_LIST@195..199 + L_ANGLE@195..196 "<" + LIFETIME_PARAM@196..198 + LIFETIME@196..198 "\'a" + R_ANGLE@198..199 ">" + WHITESPACE@199..200 " " + SLICE_TYPE@200..207 + L_BRACK@200..201 "[" + REFERENCE_TYPE@201..206 + AMP@201..202 "&" + LIFETIME@202..204 "\'a" + WHITESPACE@204..205 " " + PATH_TYPE@205..206 + PATH@205..206 + PATH_SEGMENT@205..206 + NAME_REF@205..206 + IDENT@205..206 "F" + R_BRACK@206..207 "]" + COLON@207..208 ":" + WHITESPACE@208..209 " " + TYPE_BOUND_LIST@209..211 + TYPE_BOUND@209..211 + PATH_TYPE@209..211 + PATH@209..211 + PATH_SEGMENT@209..211 + NAME_REF@209..211 + IDENT@209..211 "Eq" + WHITESPACE@211..212 "\n" + BLOCK_EXPR@212..215 + L_CURLY@212..213 "{" + WHITESPACE@213..214 " " + R_CURLY@214..215 "}" + WHITESPACE@215..216 "\n" + FN_DEF@216..291 + FN_KW@216..218 "fn" + WHITESPACE@218..219 " " + NAME@219..228 + IDENT@219..228 "for_qpath" + TYPE_PARAM_LIST@228..231 + L_ANGLE@228..229 "<" + TYPE_PARAM@229..230 + NAME@229..230 + IDENT@229..230 "T" + R_ANGLE@230..231 ">" + PARAM_LIST@231..239 + L_PAREN@231..232 "(" + PARAM@232..238 + BIND_PAT@232..234 + NAME@232..234 + IDENT@232..234 "_t" + COLON@234..235 ":" + WHITESPACE@235..236 " " + REFERENCE_TYPE@236..238 + AMP@236..237 "&" + PATH_TYPE@237..238 + PATH@237..238 + PATH_SEGMENT@237..238 + NAME_REF@237..238 + IDENT@237..238 "T" + R_PAREN@238..239 ")" + WHITESPACE@239..240 "\n" + WHERE_CLAUSE@240..287 + WHERE_KW@240..245 "where" + WHITESPACE@245..250 "\n " + WHERE_PRED@250..287 + FOR_KW@250..253 "for" + TYPE_PARAM_LIST@253..257 + L_ANGLE@253..254 "<" + LIFETIME_PARAM@254..256 + LIFETIME@254..256 "\'a" + R_ANGLE@256..257 ">" + WHITESPACE@257..258 " " + PATH_TYPE@258..277 + PATH@258..277 + PATH@258..272 + PATH_SEGMENT@258..272 + L_ANGLE@258..259 "<" + REFERENCE_TYPE@259..264 + AMP@259..260 "&" + LIFETIME@260..262 "\'a" + WHITESPACE@262..263 " " + PATH_TYPE@263..264 + PATH@263..264 + PATH_SEGMENT@263..264 + NAME_REF@263..264 + IDENT@263..264 "T" + WHITESPACE@264..265 " " + AS_KW@265..267 "as" + WHITESPACE@267..268 " " + PATH_TYPE@268..271 + PATH@268..271 + PATH_SEGMENT@268..271 + NAME_REF@268..271 + IDENT@268..271 "Baz" + R_ANGLE@271..272 ">" + COLON2@272..274 "::" + PATH_SEGMENT@274..277 + NAME_REF@274..277 + IDENT@274..277 "Foo" + COLON@277..278 ":" + WHITESPACE@278..279 " " + TYPE_BOUND_LIST@279..287 + TYPE_BOUND@279..287 + PATH_TYPE@279..287 + PATH@279..287 + PATH_SEGMENT@279..287 + NAME_REF@279..287 + IDENT@279..287 "Iterator" + WHITESPACE@287..288 "\n" + BLOCK_EXPR@288..291 + L_CURLY@288..289 "{" + WHITESPACE@289..290 " " + R_CURLY@290..291 "}" + WHITESPACE@291..292 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs index b448c6178..2d47596be 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs @@ -1,4 +1,20 @@ -fn test() +fn for_trait() where for<'a> F: Fn(&'a str) { } +fn for_ref() +where + for<'a> &'a F: Debug +{ } +fn for_parens() +where + for<'a> (&'a F): Fn(&'a str) +{ } +fn for_slice() +where + for<'a> [&'a F]: Eq +{ } +fn for_qpath(_t: &T) +where + for<'a> <&'a T as Baz>::Foo: Iterator +{ } diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast index dfb8d57ad..26a80017a 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast @@ -1,4 +1,4 @@ -SOURCE_FILE@0..200 +SOURCE_FILE@0..82 TYPE_ALIAS_DEF@0..28 TYPE_KW@0..4 "type" WHITESPACE@4..5 " " @@ -29,212 +29,48 @@ SOURCE_FILE@0..200 R_PAREN@26..27 ")" SEMICOLON@27..28 ";" WHITESPACE@28..29 "\n" - FN_DEF@29..79 - FN_KW@29..31 "fn" - WHITESPACE@31..32 " " - NAME@32..35 - IDENT@32..35 "foo" - TYPE_PARAM_LIST@35..38 - L_ANGLE@35..36 "<" - TYPE_PARAM@36..37 - NAME@36..37 - IDENT@36..37 "T" - R_ANGLE@37..38 ">" - PARAM_LIST@38..46 - L_PAREN@38..39 "(" - PARAM@39..45 - BIND_PAT@39..41 - NAME@39..41 - IDENT@39..41 "_t" - COLON@41..42 ":" - WHITESPACE@42..43 " " - REFERENCE_TYPE@43..45 - AMP@43..44 "&" - PATH_TYPE@44..45 - PATH@44..45 - PATH_SEGMENT@44..45 - NAME_REF@44..45 - IDENT@44..45 "T" - R_PAREN@45..46 ")" - WHITESPACE@46..47 " " - WHERE_CLAUSE@47..76 - WHERE_KW@47..52 "where" - WHITESPACE@52..53 " " - WHERE_PRED@53..76 - FOR_TYPE@53..66 - FOR_KW@53..56 "for" - TYPE_PARAM_LIST@56..60 - L_ANGLE@56..57 "<" - LIFETIME_PARAM@57..59 - LIFETIME@57..59 "\'a" - R_ANGLE@59..60 ">" - WHITESPACE@60..61 " " - REFERENCE_TYPE@61..66 - AMP@61..62 "&" - LIFETIME@62..64 "\'a" - WHITESPACE@64..65 " " - PATH_TYPE@65..66 - PATH@65..66 - PATH_SEGMENT@65..66 - NAME_REF@65..66 - IDENT@65..66 "T" - COLON@66..67 ":" - WHITESPACE@67..68 " " - TYPE_BOUND_LIST@68..76 - TYPE_BOUND@68..76 - PATH_TYPE@68..76 - PATH@68..76 - PATH_SEGMENT@68..76 - NAME_REF@68..76 - IDENT@68..76 "Iterator" - WHITESPACE@76..77 " " - BLOCK_EXPR@77..79 - L_CURLY@77..78 "{" - R_CURLY@78..79 "}" - WHITESPACE@79..80 "\n" - FN_DEF@80..134 - FN_KW@80..82 "fn" - WHITESPACE@82..83 " " - NAME@83..86 - IDENT@83..86 "bar" - TYPE_PARAM_LIST@86..89 - L_ANGLE@86..87 "<" - TYPE_PARAM@87..88 - NAME@87..88 - IDENT@87..88 "T" - R_ANGLE@88..89 ">" - PARAM_LIST@89..97 - L_PAREN@89..90 "(" - PARAM@90..96 - BIND_PAT@90..92 - NAME@90..92 - IDENT@90..92 "_t" - COLON@92..93 ":" - WHITESPACE@93..94 " " - REFERENCE_TYPE@94..96 - AMP@94..95 "&" - PATH_TYPE@95..96 - PATH@95..96 - PATH_SEGMENT@95..96 - NAME_REF@95..96 - IDENT@95..96 "T" - R_PAREN@96..97 ")" - WHITESPACE@97..98 " " - WHERE_CLAUSE@98..131 - WHERE_KW@98..103 "where" - WHITESPACE@103..104 " " - WHERE_PRED@104..131 - FOR_TYPE@104..121 - FOR_KW@104..107 "for" - TYPE_PARAM_LIST@107..111 - L_ANGLE@107..108 "<" - LIFETIME_PARAM@108..110 - LIFETIME@108..110 "\'a" - R_ANGLE@110..111 ">" - WHITESPACE@111..112 " " - REFERENCE_TYPE@112..121 - AMP@112..113 "&" - LIFETIME@113..115 "\'a" - WHITESPACE@115..116 " " - MUT_KW@116..119 "mut" - WHITESPACE@119..120 " " - PATH_TYPE@120..121 - PATH@120..121 - PATH_SEGMENT@120..121 - NAME_REF@120..121 - IDENT@120..121 "T" - COLON@121..122 ":" - WHITESPACE@122..123 " " - TYPE_BOUND_LIST@123..131 - TYPE_BOUND@123..131 - PATH_TYPE@123..131 - PATH@123..131 - PATH_SEGMENT@123..131 - NAME_REF@123..131 - IDENT@123..131 "Iterator" - WHITESPACE@131..132 " " - BLOCK_EXPR@132..134 - L_CURLY@132..133 "{" - R_CURLY@133..134 "}" - WHITESPACE@134..135 "\n" - FN_DEF@135..199 - FN_KW@135..137 "fn" - WHITESPACE@137..138 " " - NAME@138..141 - IDENT@138..141 "baz" - TYPE_PARAM_LIST@141..144 - L_ANGLE@141..142 "<" - TYPE_PARAM@142..143 - NAME@142..143 - IDENT@142..143 "T" - R_ANGLE@143..144 ">" - PARAM_LIST@144..152 - L_PAREN@144..145 "(" - PARAM@145..151 - BIND_PAT@145..147 - NAME@145..147 - IDENT@145..147 "_t" - COLON@147..148 ":" - WHITESPACE@148..149 " " - REFERENCE_TYPE@149..151 - AMP@149..150 "&" - PATH_TYPE@150..151 - PATH@150..151 - PATH_SEGMENT@150..151 - NAME_REF@150..151 - IDENT@150..151 "T" - R_PAREN@151..152 ")" - WHITESPACE@152..153 " " - WHERE_CLAUSE@153..196 - WHERE_KW@153..158 "where" - WHITESPACE@158..159 " " - WHERE_PRED@159..196 - FOR_TYPE@159..186 - FOR_KW@159..162 "for" - TYPE_PARAM_LIST@162..166 - L_ANGLE@162..163 "<" - LIFETIME_PARAM@163..165 - LIFETIME@163..165 "\'a" - R_ANGLE@165..166 ">" - WHITESPACE@166..167 " " - PATH_TYPE@167..186 - PATH@167..186 - PATH@167..181 - PATH_SEGMENT@167..181 - L_ANGLE@167..168 "<" - REFERENCE_TYPE@168..173 - AMP@168..169 "&" - LIFETIME@169..171 "\'a" - WHITESPACE@171..172 " " - PATH_TYPE@172..173 - PATH@172..173 - PATH_SEGMENT@172..173 - NAME_REF@172..173 - IDENT@172..173 "T" - WHITESPACE@173..174 " " - AS_KW@174..176 "as" - WHITESPACE@176..177 " " - PATH_TYPE@177..180 - PATH@177..180 - PATH_SEGMENT@177..180 - NAME_REF@177..180 - IDENT@177..180 "Baz" - R_ANGLE@180..181 ">" - COLON2@181..183 "::" - PATH_SEGMENT@183..186 - NAME_REF@183..186 - IDENT@183..186 "Foo" - COLON@186..187 ":" - WHITESPACE@187..188 " " - TYPE_BOUND_LIST@188..196 - TYPE_BOUND@188..196 - PATH_TYPE@188..196 - PATH@188..196 - PATH_SEGMENT@188..196 - NAME_REF@188..196 - IDENT@188..196 "Iterator" - WHITESPACE@196..197 " " - BLOCK_EXPR@197..199 - L_CURLY@197..198 "{" - R_CURLY@198..199 "}" - WHITESPACE@199..200 "\n" + TYPE_ALIAS_DEF@29..81 + TYPE_KW@29..33 "type" + WHITESPACE@33..34 " " + NAME@34..35 + IDENT@34..35 "B" + WHITESPACE@35..36 " " + EQ@36..37 "=" + WHITESPACE@37..38 " " + FOR_TYPE@38..80 + FOR_KW@38..41 "for" + TYPE_PARAM_LIST@41..45 + L_ANGLE@41..42 "<" + LIFETIME_PARAM@42..44 + LIFETIME@42..44 "\'a" + R_ANGLE@44..45 ">" + WHITESPACE@45..46 " " + FN_POINTER_TYPE@46..80 + UNSAFE_KW@46..52 "unsafe" + WHITESPACE@52..53 " " + ABI@53..63 + EXTERN_KW@53..59 "extern" + WHITESPACE@59..60 " " + STRING@60..63 "\"C\"" + WHITESPACE@63..64 " " + FN_KW@64..66 "fn" + PARAM_LIST@66..74 + L_PAREN@66..67 "(" + PARAM@67..73 + REFERENCE_TYPE@67..73 + AMP@67..68 "&" + LIFETIME@68..70 "\'a" + WHITESPACE@70..71 " " + TUPLE_TYPE@71..73 + L_PAREN@71..72 "(" + R_PAREN@72..73 ")" + R_PAREN@73..74 ")" + WHITESPACE@74..75 " " + RET_TYPE@75..80 + THIN_ARROW@75..77 "->" + WHITESPACE@77..78 " " + TUPLE_TYPE@78..80 + L_PAREN@78..79 "(" + R_PAREN@79..80 ")" + SEMICOLON@80..81 ";" + WHITESPACE@81..82 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs index d6774d438..457e8744f 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs @@ -1,4 +1,2 @@ type A = for<'a> fn() -> (); -fn foo(_t: &T) where for<'a> &'a T: Iterator {} -fn bar(_t: &T) where for<'a> &'a mut T: Iterator {} -fn baz(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {} +type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); -- cgit v1.2.3 From db1cadd4447f7c580c5436a4368a4de3c67fa37a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 10 Jun 2020 12:34:23 +0200 Subject: In field patterns, don't highlight local binding as a field --- crates/ra_ide/src/snapshots/highlighting.html | 4 +++- crates/ra_ide/src/syntax_highlighting/tests.rs | 26 ++++++++++++++------------ crates/ra_ide_db/src/defs.rs | 9 ++++++--- 3 files changed, 23 insertions(+), 16 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index e34ff5a7d..33548d43c 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html @@ -84,7 +84,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd let y = &mut x; let z = &y; - y; + let Foo { x: z, y } = Foo { x: z, y }; + + y; } enum Option<T> { diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 021f8e7e2..949bf59a0 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -7,18 +7,6 @@ use crate::{ FileRange, TextRange, }; -/// Highlights the code given by the `ra_fixture` argument, renders the -/// result as HTML, and compares it with the HTML file given as `snapshot`. -/// Note that the `snapshot` file is overwritten by the rendered HTML. -fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { - let (analysis, file_id) = single_file(ra_fixture); - let dst_file = project_dir().join(snapshot); - let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); -} - #[test] fn test_highlighting() { check_highlighting( @@ -77,6 +65,8 @@ fn main() { let y = &mut x; let z = &y; + let Foo { x: z, y } = Foo { x: z, y }; + y; } @@ -334,3 +324,15 @@ impl Foo { false, ) } + +/// Highlights the code given by the `ra_fixture` argument, renders the +/// result as HTML, and compares it with the HTML file given as `snapshot`. +/// Note that the `snapshot` file is overwritten by the rendered HTML. +fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { + let (analysis, file_id) = single_file(ra_fixture); + let dst_file = project_dir().join(snapshot); + let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); + let expected_html = &read_text(&dst_file); + fs::write(dst_file, &actual_html).unwrap(); + assert_eq_text!(expected_html, actual_html); +} diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 1826f3ac6..3ef5e74b6 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -78,6 +78,7 @@ impl Definition { } } +#[derive(Debug)] pub enum NameClass { Definition(Definition), /// `None` in `if let None = Some(82) {}` @@ -131,9 +132,11 @@ pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option let local = sema.to_def(&it)?; if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { - if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { - let field = Definition::Field(field); - return Some(NameClass::FieldShorthand { local, field }); + if record_field_pat.name_ref().is_none() { + if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { + let field = Definition::Field(field); + return Some(NameClass::FieldShorthand { local, field }); + } } } -- cgit v1.2.3 From d50a1a0fe9055bf03b9746cb341b251af8e7b326 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 8 Jun 2020 13:00:31 +0200 Subject: Profile `world_symbols` --- crates/ra_ide_db/src/symbol_index.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index acc31fe3b..299b47c6a 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -132,6 +132,8 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc // | VS Code | kbd:[Ctrl+T] // |=== pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { + let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); + /// Need to wrap Snapshot to provide `Clone` impl for `map_with` struct Snap(salsa::Snapshot); impl Clone for Snap { -- cgit v1.2.3 From 54936e8aa212ea5fdf737d8e1b0a02c231ed89eb Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 8 Jun 2020 13:00:53 +0200 Subject: Fix the symbol query limit --- crates/ra_ide_db/src/symbol_index.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index 299b47c6a..78c714356 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -300,9 +300,6 @@ impl Query { let mut stream = op.union(); let mut res = Vec::new(); while let Some((_, indexed_values)) = stream.next() { - if res.len() >= self.limit { - break; - } for indexed_value in indexed_values { let symbol_index = &indices[indexed_value.index]; let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); @@ -314,6 +311,10 @@ impl Query { if self.exact && symbol.name != self.query { continue; } + + if res.len() >= self.limit { + return res; + } res.push(symbol.clone()); } } -- cgit v1.2.3 From 4bcf8c8c68bd791f295aa06ef7903c006be3f356 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Jun 2020 17:32:42 +0200 Subject: Add an FST index to `ImportMap` --- crates/ra_hir_def/Cargo.toml | 2 + crates/ra_hir_def/src/import_map.rs | 253 +++++++++++++++++++++++++++++++++++- crates/ra_hir_expand/src/name.rs | 7 + 3 files changed, 259 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index b85358308..bd69abfc7 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -14,6 +14,8 @@ rustc-hash = "1.1.0" either = "1.5.3" anymap = "0.12.1" drop_bomb = "0.1.4" +fst = { version = "0.4", default-features = false } +itertools = "0.9.0" stdx = { path = "../stdx" } diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 4284a0a91..e9b2fe26e 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -1,7 +1,10 @@ //! A map of all publicly exported items in a crate. +use std::cmp::Ordering; use std::{collections::hash_map::Entry, fmt, sync::Arc}; +use fst::{self, Streamer}; +use itertools::Itertools; use ra_db::CrateId; use rustc_hash::FxHashMap; @@ -21,9 +24,17 @@ use crate::{ /// /// Note that all paths are relative to the containing crate's root, so the crate name still needs /// to be prepended to the `ModPath` before the path is valid. -#[derive(Eq, PartialEq)] pub struct ImportMap { map: FxHashMap, + + /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the + /// values returned by running `fst`. + /// + /// Since a path can refer to multiple items due to namespacing, we store all items with the + /// same path right after each other. This allows us to find all items after the FST gives us + /// the index of the first one. + importables: Vec, + fst: fst::Map>, } impl ImportMap { @@ -88,7 +99,34 @@ impl ImportMap { } } - Arc::new(Self { map: import_map }) + let mut importables = import_map.iter().collect::>(); + + importables.sort_by(cmp); + + // Build the FST, taking care not to insert duplicate values. + + let mut builder = fst::MapBuilder::memory(); + let mut last_batch_start = 0; + + for idx in 0..importables.len() { + if let Some(next_item) = importables.get(idx + 1) { + if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { + continue; + } + } + + let start = last_batch_start; + last_batch_start = idx + 1; + + let key: String = fst_path(&importables[start].1).collect(); + + builder.insert(key, start as u64).unwrap(); + } + + let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); + let importables = importables.iter().map(|(item, _)| **item).collect(); + + Arc::new(Self { map: import_map, fst, importables }) } /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. @@ -97,6 +135,14 @@ impl ImportMap { } } +impl PartialEq for ImportMap { + fn eq(&self, other: &Self) -> bool { + self.importables == other.importables + } +} + +impl Eq for ImportMap {} + impl fmt::Debug for ImportMap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut importable_paths: Vec<_> = self @@ -117,13 +163,97 @@ impl fmt::Debug for ImportMap { } } +fn fst_path(path: &ModPath) -> impl Iterator + '_ { + path.segments + .iter() + .map(|name| name.as_text().unwrap()) + .intersperse("::") + .flat_map(|s| s.chars().map(|c| c.to_ascii_lowercase())) +} + +fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Ordering { + let lhs_chars = fst_path(lhs); + let rhs_chars = fst_path(rhs); + lhs_chars.cmp(rhs_chars) +} + +#[derive(Debug)] +pub struct Query { + query: String, + anchor_end: bool, +} + +impl Query { + pub fn new(query: impl AsRef) -> Self { + Self { query: query.as_ref().to_lowercase(), anchor_end: false } + } + + /// Only returns items whose paths end with the (case-insensitive) query string as their last + /// segment. + pub fn anchor_end(self) -> Self { + Self { anchor_end: true, ..self } + } +} + +/// Searches dependencies of `krate` for an importable path matching `query`. +/// +/// This returns all items that could be imported from within `krate`, excluding paths inside +/// `krate` itself. +pub fn search_dependencies<'a>( + db: &'a dyn DefDatabase, + krate: CrateId, + query: Query, +) -> Vec { + let _p = ra_prof::profile("import_map::global_search").detail(|| format!("{:?}", query)); + + let graph = db.crate_graph(); + let import_maps: Vec<_> = + graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); + + let automaton = fst::automaton::Subsequence::new(&query.query); + + let mut op = fst::map::OpBuilder::new(); + for map in &import_maps { + op = op.add(map.fst.search(&automaton)); + } + + let mut stream = op.union(); + let mut res = Vec::new(); + while let Some((_, indexed_values)) = stream.next() { + for indexed_value in indexed_values { + let import_map = &import_maps[indexed_value.index]; + let importables = &import_map.importables[indexed_value.value as usize..]; + + // Path shared by the importable items in this group. + let path = &import_map.map[&importables[0]]; + + if query.anchor_end { + // Last segment must match query. + let last = path.segments.last().unwrap().to_string(); + if last.to_lowercase() != query.query { + continue; + } + } + + // Add the items from this `ModPath` group. Those are all subsequent items in + // `importables` whose paths match `path`. + res.extend(importables.iter().copied().take_while(|item| { + let item_path = &import_map.map[item]; + fst_path(item_path).eq(fst_path(path)) + })); + } + } + + res +} + #[cfg(test)] mod tests { use super::*; use crate::test_db::TestDB; use insta::assert_snapshot; use ra_db::fixture::WithFixture; - use ra_db::SourceDatabase; + use ra_db::{SourceDatabase, Upcast}; fn import_map(ra_fixture: &str) -> String { let db = TestDB::with_files(ra_fixture); @@ -144,6 +274,40 @@ mod tests { import_maps.join("\n") } + fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { + let db = TestDB::with_files(ra_fixture); + let crate_graph = db.crate_graph(); + let krate = crate_graph + .iter() + .find(|krate| { + crate_graph[*krate].display_name.as_ref().map(|n| n.to_string()) + == Some(krate_name.to_string()) + }) + .unwrap(); + + search_dependencies(db.upcast(), krate, query) + .into_iter() + .filter_map(|item| { + let mark = match item { + ItemInNs::Types(_) => "t", + ItemInNs::Values(_) => "v", + ItemInNs::Macros(_) => "m", + }; + item.krate(db.upcast()).map(|krate| { + let map = db.import_map(krate); + let path = map.path_of(item).unwrap(); + format!( + "{}::{} ({})", + crate_graph[krate].display_name.as_ref().unwrap(), + path, + mark + ) + }) + }) + .collect::>() + .join("\n") + } + #[test] fn smoke() { let map = import_map( @@ -328,4 +492,87 @@ mod tests { lib: "###); } + + #[test] + fn namespacing() { + let map = import_map( + r" + //- /lib.rs crate:lib + pub struct Thing; // t + v + #[macro_export] + macro_rules! Thing { // m + () => {}; + } + ", + ); + + assert_snapshot!(map, @r###" + lib: + - Thing (m) + - Thing (t) + - Thing (v) + "###); + + let map = import_map( + r" + //- /lib.rs crate:lib + pub mod Thing {} // t + #[macro_export] + macro_rules! Thing { // m + () => {}; + } + ", + ); + + assert_snapshot!(map, @r###" + lib: + - Thing (m) + - Thing (t) + "###); + } + + #[test] + fn search() { + let ra_fixture = r#" + //- /main.rs crate:main deps:dep + //- /dep.rs crate:dep deps:tdep + use tdep::fmt as fmt_dep; + pub mod fmt { + pub trait Display { + fn fmt(); + } + } + #[macro_export] + macro_rules! Fmt { + () => {}; + } + pub struct Fmt; + + pub fn format() {} + pub fn no() {} + + //- /tdep.rs crate:tdep + pub mod fmt { + pub struct NotImportableFromMain; + } + "#; + + let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); + assert_snapshot!(res, @r###" + dep::Fmt (v) + dep::fmt (t) + dep::Fmt (t) + dep::Fmt (m) + dep::fmt::Display (t) + dep::format (v) + "###); + + let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); + assert_snapshot!(res, @r###" + dep::Fmt (v) + dep::fmt (t) + dep::Fmt (t) + dep::Fmt (m) + "###); + } } diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 660bdfe33..f306d9641 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs @@ -67,6 +67,13 @@ impl Name { _ => None, } } + + pub fn as_text(&self) -> Option<&str> { + match &self.0 { + Repr::Text(s) => Some(s.as_str()), + _ => None, + } + } } pub trait AsName { -- cgit v1.2.3 From 6463d3ac63a479e33d923593e720696b38a1a54c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Jun 2020 18:47:14 +0200 Subject: symbol_index: allow querying a single crate --- crates/ra_ide_db/src/symbol_index.rs | 43 ++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index 78c714356..c974891ea 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -29,9 +29,10 @@ use std::{ }; use fst::{self, Streamer}; +use hir::db::DefDatabase; use ra_db::{ salsa::{self, ParallelDatabase}, - FileId, SourceDatabaseExt, SourceRootId, + CrateId, FileId, SourceDatabaseExt, SourceRootId, }; use ra_syntax::{ ast::{self, NameOwner}, @@ -110,6 +111,14 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc Arc::new(SymbolIndex::new(symbols)) } +/// Need to wrap Snapshot to provide `Clone` impl for `map_with` +struct Snap(salsa::Snapshot); +impl Clone for Snap { + fn clone(&self) -> Snap { + Snap(self.0.snapshot()) + } +} + // Feature: Workspace Symbol // // Uses fuzzy-search to find types, modules and functions by name across your @@ -134,14 +143,6 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); - /// Need to wrap Snapshot to provide `Clone` impl for `map_with` - struct Snap(salsa::Snapshot); - impl Clone for Snap { - fn clone(&self) -> Snap { - Snap(self.0.snapshot()) - } - } - let buf: Vec> = if query.libs { let snap = Snap(db.snapshot()); #[cfg(not(feature = "wasm"))] @@ -175,6 +176,30 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { query.search(&buf) } +pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec { + let def_map = db.crate_def_map(krate); + let mut files = Vec::new(); + let mut modules = vec![def_map.root]; + while let Some(module) = modules.pop() { + let data = &def_map[module]; + files.extend(data.origin.file_id()); + modules.extend(data.children.values()); + } + + let snap = Snap(db.snapshot()); + + #[cfg(not(feature = "wasm"))] + let buf = files + .par_iter() + .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) + .collect::>(); + + #[cfg(feature = "wasm")] + let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect::>(); + + query.search(&buf) +} + pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec { let name = name_ref.text(); let mut query = Query::new(name.to_string()); -- cgit v1.2.3 From b01fb22494eaf64c02c17fc38598a3a2dbd8e980 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Jun 2020 18:48:00 +0200 Subject: ra_hir: expose `import_map::search_dependencies` --- crates/ra_hir/src/code_model.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'crates') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 4a06f3bcd..c8329d971 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -9,6 +9,7 @@ use hir_def::{ builtin_type::BuiltinType, docs::Documentation, expr::{BindingAnnotation, Pat, PatId}, + import_map, per_ns::PerNs, resolver::{HasResolver, Resolver}, type_ref::{Mutability, TypeRef}, @@ -98,6 +99,19 @@ impl Crate { db.crate_graph()[self.id].display_name.as_ref().cloned() } + pub fn query_external_importables( + self, + db: &dyn DefDatabase, + query: &str, + ) -> impl Iterator> { + import_map::search_dependencies(db, self.into(), import_map::Query::new(query).anchor_end()) + .into_iter() + .map(|item| match item { + ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), + ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), + }) + } + pub fn all(db: &dyn HirDatabase) -> Vec { db.crate_graph().iter().map(|id| Crate { id }).collect() } -- cgit v1.2.3 From a70a0ca73ceac339de4e1df6d561894e485ba5ee Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Jun 2020 18:48:44 +0200 Subject: ImportsLocator: use ImportMap for non-local crates --- crates/ra_assists/src/handlers/auto_import.rs | 47 ++++++++++++++++++++++++++- crates/ra_ide_db/src/imports_locator.rs | 46 +++++++++++++------------- 2 files changed, 70 insertions(+), 23 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index edf96d50e..1f4142747 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs @@ -130,7 +130,7 @@ impl AutoImportAssets { fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet { let _p = profile("auto_import::search_for_imports"); let current_crate = self.module_with_name_to_import.krate(); - ImportsLocator::new(db) + ImportsLocator::new(db, current_crate) .find_imports(&self.get_search_query()) .into_iter() .filter_map(|candidate| match &self.import_candidate { @@ -841,4 +841,49 @@ fn main() { ", ) } + + #[test] + fn dep_import() { + check_assist( + auto_import, + r" + //- /lib.rs crate:dep + pub struct Struct; + + //- /main.rs crate:main deps:dep + fn main() { + Struct<|> + }", + r"use dep::Struct; + +fn main() { + Struct +} +", + ); + } + + #[test] + fn whole_segment() { + check_assist( + auto_import, + r" + //- /lib.rs crate:dep + pub mod fmt { + pub trait Display {} + } + + pub fn panic_fmt() {} + + //- /main.rs crate:main deps:dep + struct S; + + impl f<|>mt::Display for S {}", + r"use dep::fmt; + +struct S; +impl fmt::Display for S {} +", + ); + } } diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index bf0d8db60..fff112e66 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs @@ -1,7 +1,7 @@ //! This module contains an import search funcionality that is provided to the ra_assists module. //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. -use hir::{MacroDef, ModuleDef, Semantics}; +use hir::{Crate, MacroDef, ModuleDef, Semantics}; use ra_prof::profile; use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; @@ -11,44 +11,46 @@ use crate::{ RootDatabase, }; use either::Either; +use rustc_hash::FxHashSet; pub struct ImportsLocator<'a> { sema: Semantics<'a, RootDatabase>, + krate: Crate, } impl<'a> ImportsLocator<'a> { - pub fn new(db: &'a RootDatabase) -> Self { - Self { sema: Semantics::new(db) } + pub fn new(db: &'a RootDatabase, krate: Crate) -> Self { + Self { sema: Semantics::new(db), krate } } pub fn find_imports(&mut self, name_to_import: &str) -> Vec> { let _p = profile("search_for_imports"); let db = self.sema.db; - let project_results = { - let mut query = Query::new(name_to_import.to_string()); - query.exact(); - query.limit(40); - symbol_index::world_symbols(db, query) - }; - let lib_results = { + // Query dependencies first. + let mut candidates: FxHashSet<_> = + self.krate.query_external_importables(db, name_to_import).collect(); + + // Query the local crate using the symbol index. + let local_results = { let mut query = Query::new(name_to_import.to_string()); - query.libs(); query.exact(); query.limit(40); - symbol_index::world_symbols(db, query) + symbol_index::crate_symbols(db, self.krate.into(), query) }; - project_results - .into_iter() - .chain(lib_results.into_iter()) - .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) - .filter_map(|name_definition_to_import| match name_definition_to_import { - Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), - Definition::Macro(macro_def) => Some(Either::Right(macro_def)), - _ => None, - }) - .collect() + candidates.extend( + local_results + .into_iter() + .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) + .filter_map(|name_definition_to_import| match name_definition_to_import { + Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), + Definition::Macro(macro_def) => Some(Either::Right(macro_def)), + _ => None, + }), + ); + + candidates.into_iter().collect() } fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option { -- cgit v1.2.3 From 781b514e5886cbaff88483cdeddc504effef299c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Jun 2020 11:39:06 +0200 Subject: Add test for macro generated items --- crates/ra_assists/src/handlers/auto_import.rs | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 1f4142747..86a173ff5 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs @@ -865,6 +865,7 @@ fn main() { #[test] fn whole_segment() { + // Tests that only imports whose last segment matches the identifier get suggested. check_assist( auto_import, r" @@ -883,6 +884,36 @@ fn main() { struct S; impl fmt::Display for S {} +", + ); + } + + #[test] + fn macro_generated() { + // Tests that macro-generated items are suggested from external crates. + check_assist( + auto_import, + r" + //- /lib.rs crate:dep + + macro_rules! mac { + () => { + pub struct Cheese; + }; + } + + mac!(); + + //- /main.rs crate:main deps:dep + + fn main() { + Cheese<|>; + }", + r"use dep::Cheese; + +fn main() { + Cheese; +} ", ); } -- cgit v1.2.3 From bcf875f46ae5142c42ddac8094e1b6652182d4be Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Jun 2020 11:52:00 +0200 Subject: Clean up import_map.rs --- crates/ra_hir_def/src/import_map.rs | 45 +++++++++++++++++-------------------- crates/ra_hir_expand/src/name.rs | 7 ------ 2 files changed, 20 insertions(+), 32 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index e9b2fe26e..f2e4ca2db 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -1,10 +1,8 @@ //! A map of all publicly exported items in a crate. -use std::cmp::Ordering; -use std::{collections::hash_map::Entry, fmt, sync::Arc}; +use std::{cmp::Ordering, collections::hash_map::Entry, fmt, sync::Arc}; use fst::{self, Streamer}; -use itertools::Itertools; use ra_db::CrateId; use rustc_hash::FxHashMap; @@ -118,7 +116,7 @@ impl ImportMap { let start = last_batch_start; last_batch_start = idx + 1; - let key: String = fst_path(&importables[start].1).collect(); + let key = fst_path(&importables[start].1); builder.insert(key, start as u64).unwrap(); } @@ -137,7 +135,8 @@ impl ImportMap { impl PartialEq for ImportMap { fn eq(&self, other: &Self) -> bool { - self.importables == other.importables + // `fst` and `importables` are built from `map`, so we don't need to compare them. + self.map == other.map } } @@ -163,18 +162,16 @@ impl fmt::Debug for ImportMap { } } -fn fst_path(path: &ModPath) -> impl Iterator + '_ { - path.segments - .iter() - .map(|name| name.as_text().unwrap()) - .intersperse("::") - .flat_map(|s| s.chars().map(|c| c.to_ascii_lowercase())) +fn fst_path(path: &ModPath) -> String { + let mut s = path.to_string(); + s.make_ascii_lowercase(); + s } fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Ordering { - let lhs_chars = fst_path(lhs); - let rhs_chars = fst_path(rhs); - lhs_chars.cmp(rhs_chars) + let lhs_str = fst_path(lhs); + let rhs_str = fst_path(rhs); + lhs_str.cmp(&rhs_str) } #[derive(Debug)] @@ -184,8 +181,8 @@ pub struct Query { } impl Query { - pub fn new(query: impl AsRef) -> Self { - Self { query: query.as_ref().to_lowercase(), anchor_end: false } + pub fn new(query: &str) -> Self { + Self { query: query.to_lowercase(), anchor_end: false } } /// Only returns items whose paths end with the (case-insensitive) query string as their last @@ -197,14 +194,13 @@ impl Query { /// Searches dependencies of `krate` for an importable path matching `query`. /// -/// This returns all items that could be imported from within `krate`, excluding paths inside -/// `krate` itself. +/// This returns a list of items that could be imported from dependencies of `krate`. pub fn search_dependencies<'a>( db: &'a dyn DefDatabase, krate: CrateId, query: Query, ) -> Vec { - let _p = ra_prof::profile("import_map::global_search").detail(|| format!("{:?}", query)); + let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query)); let graph = db.crate_graph(); let import_maps: Vec<_> = @@ -239,7 +235,7 @@ pub fn search_dependencies<'a>( // `importables` whose paths match `path`. res.extend(importables.iter().copied().take_while(|item| { let item_path = &import_map.map[item]; - fst_path(item_path).eq(fst_path(path)) + fst_path(item_path) == fst_path(path) })); } } @@ -252,6 +248,7 @@ mod tests { use super::*; use crate::test_db::TestDB; use insta::assert_snapshot; + use itertools::Itertools; use ra_db::fixture::WithFixture; use ra_db::{SourceDatabase, Upcast}; @@ -259,7 +256,7 @@ mod tests { let db = TestDB::with_files(ra_fixture); let crate_graph = db.crate_graph(); - let import_maps: Vec<_> = crate_graph + let s = crate_graph .iter() .filter_map(|krate| { let cdata = &crate_graph[krate]; @@ -269,9 +266,8 @@ mod tests { Some(format!("{}:\n{:?}", name, map)) }) - .collect(); - - import_maps.join("\n") + .join("\n"); + s } fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { @@ -304,7 +300,6 @@ mod tests { ) }) }) - .collect::>() .join("\n") } diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index f306d9641..660bdfe33 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs @@ -67,13 +67,6 @@ impl Name { _ => None, } } - - pub fn as_text(&self) -> Option<&str> { - match &self.0 { - Repr::Text(s) => Some(s.as_str()), - _ => None, - } - } } pub trait AsName { -- cgit v1.2.3 From 56c7145993f94a12bf923f08cbd62d963e62bbd1 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Jun 2020 12:30:33 +0200 Subject: Limit import map queries --- crates/ra_hir/src/code_model.rs | 16 ++++++++------ crates/ra_hir_def/src/import_map.rs | 42 ++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index c8329d971..a55fe03a6 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -104,12 +104,16 @@ impl Crate { db: &dyn DefDatabase, query: &str, ) -> impl Iterator> { - import_map::search_dependencies(db, self.into(), import_map::Query::new(query).anchor_end()) - .into_iter() - .map(|item| match item { - ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), - ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), - }) + import_map::search_dependencies( + db, + self.into(), + import_map::Query::new(query).anchor_end().limit(40), + ) + .into_iter() + .map(|item| match item { + ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), + ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), + }) } pub fn all(db: &dyn HirDatabase) -> Vec { diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index f2e4ca2db..70368d8df 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -178,11 +178,12 @@ fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Or pub struct Query { query: String, anchor_end: bool, + limit: usize, } impl Query { pub fn new(query: &str) -> Self { - Self { query: query.to_lowercase(), anchor_end: false } + Self { query: query.to_lowercase(), anchor_end: false, limit: usize::max_value() } } /// Only returns items whose paths end with the (case-insensitive) query string as their last @@ -190,6 +191,11 @@ impl Query { pub fn anchor_end(self) -> Self { Self { anchor_end: true, ..self } } + + /// Limits the returned number of items to `limit`. + pub fn limit(self, limit: usize) -> Self { + Self { limit, ..self } + } } /// Searches dependencies of `krate` for an importable path matching `query`. @@ -237,6 +243,11 @@ pub fn search_dependencies<'a>( let item_path = &import_map.map[item]; fst_path(item_path) == fst_path(path) })); + + if res.len() >= query.limit { + res.truncate(query.limit); + return res; + } } } @@ -570,4 +581,33 @@ mod tests { dep::Fmt (m) "###); } + + #[test] + fn search_limit() { + let res = search_dependencies_of( + r#" + //- /main.rs crate:main deps:dep + //- /dep.rs crate:dep + pub mod fmt { + pub trait Display { + fn fmt(); + } + } + #[macro_export] + macro_rules! Fmt { + () => {}; + } + pub struct Fmt; + + pub fn format() {} + pub fn no() {} + "#, + "main", + Query::new("").limit(2), + ); + assert_snapshot!(res, @r###" + dep::fmt (t) + dep::Fmt (t) + "###); + } } -- cgit v1.2.3 From ed2817e599a9c0e812af26587badad6da7a4d949 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Jun 2020 12:37:00 +0200 Subject: Move limit check down --- crates/ra_ide_db/src/symbol_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index c974891ea..ac0a201df 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -337,10 +337,10 @@ impl Query { continue; } + res.push(symbol.clone()); if res.len() >= self.limit { return res; } - res.push(symbol.clone()); } } } -- cgit v1.2.3 From 7e83ed99a887f959bd4cf97357faf373a09f9269 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Jun 2020 16:04:55 +0200 Subject: Respect casing when searching for imports --- crates/ra_assists/src/handlers/auto_import.rs | 25 +++++++++++ crates/ra_hir/src/code_model.rs | 2 +- crates/ra_hir_def/src/import_map.rs | 60 ++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 86a173ff5..5092bf336 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs @@ -914,6 +914,31 @@ impl fmt::Display for S {} fn main() { Cheese; } +", + ); + } + + #[test] + fn casing() { + // Tests that differently cased names don't interfere and we only suggest the matching one. + check_assist( + auto_import, + r" + //- /lib.rs crate:dep + + pub struct FMT; + pub struct fmt; + + //- /main.rs crate:main deps:dep + + fn main() { + FMT<|>; + }", + r"use dep::FMT; + +fn main() { + FMT; +} ", ); } diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index a55fe03a6..1a9f6cc76 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -107,7 +107,7 @@ impl Crate { import_map::search_dependencies( db, self.into(), - import_map::Query::new(query).anchor_end().limit(40), + import_map::Query::new(query).anchor_end().case_sensitive().limit(40), ) .into_iter() .map(|item| match item { diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 70368d8df..a55d7d83b 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -177,13 +177,21 @@ fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Or #[derive(Debug)] pub struct Query { query: String, + lowercased: String, anchor_end: bool, + case_sensitive: bool, limit: usize, } impl Query { pub fn new(query: &str) -> Self { - Self { query: query.to_lowercase(), anchor_end: false, limit: usize::max_value() } + Self { + lowercased: query.to_lowercase(), + query: query.to_string(), + anchor_end: false, + case_sensitive: false, + limit: usize::max_value(), + } } /// Only returns items whose paths end with the (case-insensitive) query string as their last @@ -196,6 +204,11 @@ impl Query { pub fn limit(self, limit: usize) -> Self { Self { limit, ..self } } + + /// Respect casing of the query string when matching. + pub fn case_sensitive(self) -> Self { + Self { case_sensitive: true, ..self } + } } /// Searches dependencies of `krate` for an importable path matching `query`. @@ -212,7 +225,7 @@ pub fn search_dependencies<'a>( let import_maps: Vec<_> = graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); - let automaton = fst::automaton::Subsequence::new(&query.query); + let automaton = fst::automaton::Subsequence::new(&query.lowercased); let mut op = fst::map::OpBuilder::new(); for map in &import_maps { @@ -232,17 +245,27 @@ pub fn search_dependencies<'a>( if query.anchor_end { // Last segment must match query. let last = path.segments.last().unwrap().to_string(); - if last.to_lowercase() != query.query { + if last.to_lowercase() != query.lowercased { continue; } } // Add the items from this `ModPath` group. Those are all subsequent items in // `importables` whose paths match `path`. - res.extend(importables.iter().copied().take_while(|item| { + let iter = importables.iter().copied().take_while(|item| { let item_path = &import_map.map[item]; fst_path(item_path) == fst_path(path) - })); + }); + + if query.case_sensitive { + // FIXME: This does not do a subsequence match. + res.extend(iter.filter(|item| { + let item_path = &import_map.map[item]; + item_path.to_string().contains(&query.query) + })); + } else { + res.extend(iter); + } if res.len() >= query.limit { res.truncate(query.limit); @@ -582,6 +605,33 @@ mod tests { "###); } + #[test] + fn search_casing() { + let ra_fixture = r#" + //- /main.rs crate:main deps:dep + //- /dep.rs crate:dep + + pub struct fmt; + pub struct FMT; + "#; + + let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); + + assert_snapshot!(res, @r###" + dep::FMT (v) + dep::FMT (t) + dep::fmt (t) + dep::fmt (v) + "###); + + let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); + + assert_snapshot!(res, @r###" + dep::FMT (v) + dep::FMT (t) + "###); + } + #[test] fn search_limit() { let res = search_dependencies_of( -- cgit v1.2.3 From dd22657407bb0ab24d141275fd4f0d87269262c8 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 10 Jun 2020 16:15:49 +0200 Subject: ImportMap: use IndexMap internally It iterates in insertion order, which makes the ordering more predictable. --- crates/ra_hir_def/Cargo.toml | 1 + crates/ra_hir_def/src/import_map.rs | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index bd69abfc7..ef1f65ee0 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -16,6 +16,7 @@ anymap = "0.12.1" drop_bomb = "0.1.4" fst = { version = "0.4", default-features = false } itertools = "0.9.0" +indexmap = "1.4.0" stdx = { path = "../stdx" } diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index a55d7d83b..36b4fdd81 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -1,10 +1,11 @@ //! A map of all publicly exported items in a crate. -use std::{cmp::Ordering, collections::hash_map::Entry, fmt, sync::Arc}; +use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; use fst::{self, Streamer}; +use indexmap::{map::Entry, IndexMap}; use ra_db::CrateId; -use rustc_hash::FxHashMap; +use rustc_hash::FxHasher; use crate::{ db::DefDatabase, @@ -14,6 +15,8 @@ use crate::{ ModuleDefId, ModuleId, }; +type FxIndexMap = IndexMap>; + /// A map from publicly exported items to the path needed to import/name them from a downstream /// crate. /// @@ -23,7 +26,7 @@ use crate::{ /// Note that all paths are relative to the containing crate's root, so the crate name still needs /// to be prepended to the `ModPath` before the path is valid. pub struct ImportMap { - map: FxHashMap, + map: FxIndexMap, /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the /// values returned by running `fst`. @@ -39,7 +42,7 @@ impl ImportMap { pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { let _p = ra_prof::profile("import_map_query"); let def_map = db.crate_def_map(krate); - let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default()); + let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); // We look only into modules that are public(ly reexported), starting with the crate root. let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; @@ -588,9 +591,9 @@ mod tests { let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); assert_snapshot!(res, @r###" - dep::Fmt (v) dep::fmt (t) dep::Fmt (t) + dep::Fmt (v) dep::Fmt (m) dep::fmt::Display (t) dep::format (v) @@ -598,9 +601,9 @@ mod tests { let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); assert_snapshot!(res, @r###" - dep::Fmt (v) dep::fmt (t) dep::Fmt (t) + dep::Fmt (v) dep::Fmt (m) "###); } @@ -618,17 +621,17 @@ mod tests { let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); assert_snapshot!(res, @r###" - dep::FMT (v) - dep::FMT (t) dep::fmt (t) dep::fmt (v) + dep::FMT (t) + dep::FMT (v) "###); let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); assert_snapshot!(res, @r###" - dep::FMT (v) dep::FMT (t) + dep::FMT (v) "###); } -- cgit v1.2.3 From d8a5d39c2d05fb59b6c243935111714e18334599 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Jun 2020 11:30:06 +0200 Subject: Make relevant_crates return a Set --- crates/ra_db/src/input.rs | 8 +++----- crates/ra_db/src/lib.rs | 20 +++++++++++++------- crates/ra_hir_def/src/test_db.rs | 3 ++- crates/ra_hir_expand/Cargo.toml | 1 + crates/ra_hir_expand/src/builtin_derive.rs | 7 +++---- crates/ra_hir_expand/src/builtin_macro.rs | 5 ++--- crates/ra_hir_expand/src/lib.rs | 5 +++++ crates/ra_hir_expand/src/test_db.rs | 3 ++- crates/ra_hir_ty/src/test_db.rs | 3 ++- crates/ra_ide_db/src/lib.rs | 4 ++-- 10 files changed, 35 insertions(+), 24 deletions(-) (limited to 'crates') diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index a8d6466ea..bf26048f2 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -15,12 +15,10 @@ use std::{ use ra_cfg::CfgOptions; use ra_syntax::SmolStr; -use rustc_hash::FxHashMap; -use rustc_hash::FxHashSet; +use ra_tt::TokenExpander; +use rustc_hash::{FxHashMap, FxHashSet}; use crate::{RelativePath, RelativePathBuf}; -use fmt::Display; -use ra_tt::TokenExpander; /// `FileId` is an integer which uniquely identifies a file. File paths are /// messy and system-dependent, so most of the code should work directly with @@ -111,7 +109,7 @@ impl CrateName { } } -impl Display for CrateName { +impl fmt::Display for CrateName { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 2ab314884..80ddb6058 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -7,6 +7,7 @@ use std::{panic, sync::Arc}; use ra_prof::profile; use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; +use rustc_hash::FxHashSet; pub use crate::{ cancellation::Canceled, @@ -95,7 +96,7 @@ pub trait FileLoader { /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we /// get by with a `&str` for the time being. fn resolve_path(&self, anchor: FileId, path: &str) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; + fn relevant_crates(&self, file_id: FileId) -> Arc>; } /// Database which stores all significant input facts: source code and project @@ -133,16 +134,21 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; - fn source_root_crates(&self, id: SourceRootId) -> Arc>; + fn source_root_crates(&self, id: SourceRootId) -> Arc>; } fn source_root_crates( db: &(impl SourceDatabaseExt + SourceDatabase), id: SourceRootId, -) -> Arc> { - let root = db.source_root(id); +) -> Arc> { let graph = db.crate_graph(); - let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::>(); + let res = graph + .iter() + .filter(|&krate| { + let root_file = graph[krate].root_file_id; + db.file_source_root(root_file) == id + }) + .collect::>(); Arc::new(res) } @@ -156,7 +162,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { fn resolve_path(&self, anchor: FileId, path: &str) -> Option { // FIXME: this *somehow* should be platform agnostic... if std::path::Path::new(path).is_absolute() { - let krate = *self.relevant_crates(anchor).get(0)?; + let krate = *self.relevant_crates(anchor).iter().next()?; let (extern_source_id, relative_file) = self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; @@ -175,7 +181,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { } } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) } diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index bcfa66ac9..4581d8745 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -7,6 +7,7 @@ use std::{ use hir_expand::db::AstDatabase; use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; +use rustc_hash::FxHashSet; use crate::db::DefDatabase; @@ -59,7 +60,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, anchor: FileId, path: &str) -> Option { FileLoaderDelegate(self).resolve_path(anchor, path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index 2cd522766..e5c9f3e99 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] log = "0.4.8" either = "1.5.3" +rustc-hash = "1.0.0" ra_arena = { path = "../ra_arena" } ra_db = { path = "../ra_db" } diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 1dc9cac66..967d1f3a1 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -9,7 +9,7 @@ use ra_syntax::{ }; use crate::db::AstDatabase; -use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; +use crate::{guess_crate, name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; macro_rules! register_builtin { ( $($trait:ident => $expand:ident),* ) => { @@ -160,8 +160,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { let m: MacroCallId = id.into(); let file_id = m.as_file().original_file(db); let cg = db.crate_graph(); - let krates = db.relevant_crates(file_id); - let krate = match krates.get(0) { + let krate = match guess_crate(db, file_id) { Some(krate) => krate, None => { let tt = quote! { core }; @@ -172,7 +171,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { // XXX // All crates except core itself should have a dependency on core, // We detect `core` by seeing whether it doesn't have such a dependency. - let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { + let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { quote! { core } } else { quote! { crate } diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 7579546d2..93da3f149 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -5,7 +5,7 @@ use crate::{ name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, }; -use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; +use crate::{guess_crate, quote, EagerMacroId, LazyMacroId, MacroCallId}; use either::Either; use mbe::parse_to_token_tree; use ra_db::FileId; @@ -335,8 +335,7 @@ fn include_expand( fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option { let call_id: MacroCallId = arg_id.into(); let original_file = call_id.as_file().original_file(db); - - let krate = *db.relevant_crates(original_file).get(0)?; + let krate = guess_crate(db, original_file)?; db.crate_graph()[krate].env.get(key) } diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index f440c073b..dc4d7f000 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -424,3 +424,8 @@ impl InFile { self.with_value(self.value.syntax()) } } + +// FIXME: this is obviously wrong, there shouldn't be any guesing here +fn guess_crate(db: &dyn db::AstDatabase, file_id: FileId) -> Option { + db.relevant_crates(file_id).iter().next().copied() +} diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index fdf225f55..09fc18c36 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs @@ -6,6 +6,7 @@ use std::{ }; use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; +use rustc_hash::FxHashSet; #[salsa::database( ra_db::SourceDatabaseExtStorage, @@ -44,7 +45,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, anchor: FileId, path: &str) -> Option { FileLoaderDelegate(self).resolve_path(anchor, path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index e484968a0..ad04e3e0f 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs @@ -8,6 +8,7 @@ use std::{ use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; +use rustc_hash::FxHashSet; use stdx::format_to; use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; @@ -73,7 +74,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, anchor: FileId, path: &str) -> Option { FileLoaderDelegate(self).resolve_path(anchor, path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 727d743b5..480fd4576 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -19,7 +19,7 @@ use ra_db::{ Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, SourceRootId, Upcast, }; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; @@ -60,7 +60,7 @@ impl FileLoader for RootDatabase { fn resolve_path(&self, anchor: FileId, path: &str) -> Option { FileLoaderDelegate(self).resolve_path(anchor, path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } -- cgit v1.2.3 From 6766a6b0e189f47d7a405c872598bca9a2395360 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 11 Jun 2020 12:03:08 +0200 Subject: Add symbol index FIXME --- crates/ra_ide_db/src/symbol_index.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index ac0a201df..aab918973 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -177,6 +177,9 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { } pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec { + // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from + // that instead? + let def_map = db.crate_def_map(krate); let mut files = Vec::new(); let mut modules = vec![def_map.root]; -- cgit v1.2.3 From fac7b0e252ab305f5c8d69b04c46c587ee021aa9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Jun 2020 12:08:24 +0200 Subject: Don't guess macro expansion crate --- crates/ra_hir/src/semantics.rs | 3 ++- crates/ra_hir/src/source_analyzer.rs | 3 ++- crates/ra_hir_def/src/body.rs | 2 +- crates/ra_hir_def/src/lib.rs | 11 ++++++--- crates/ra_hir_def/src/nameres/collector.rs | 39 +++++++++++++++++------------- crates/ra_hir_expand/src/builtin_derive.rs | 28 +++++++++------------ crates/ra_hir_expand/src/builtin_macro.rs | 17 +++++++------ crates/ra_hir_expand/src/eager.rs | 32 ++++++++++++++++++------ crates/ra_hir_expand/src/lib.rs | 16 ++++++------ 9 files changed, 89 insertions(+), 62 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 7c1f79f27..a232a5856 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { let macro_call = self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); + let krate = sa.resolver.krate()?; let macro_call_id = macro_call - .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; + .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) } diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 4b509f07c..7c6bbea13 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -307,7 +307,8 @@ impl SourceAnalyzer { db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option { - let macro_call_id = macro_call.as_call_id(db.upcast(), |path| { + let krate = self.resolver.krate()?; + let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { self.resolver.resolve_path_as_macro(db.upcast(), &path) })?; Some(macro_call_id.as_file()) diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 273036cee..4f2350915 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -97,7 +97,7 @@ impl Expander { let macro_call = InFile::new(self.current_file_id, ¯o_call); - if let Some(call_id) = macro_call.as_call_id(db, |path| { + if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| { if let Some(local_scope) = local_scope { if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { return Some(def); diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index de490fcc5..edc59e5a8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -417,6 +417,7 @@ pub trait AsMacroCall { fn as_call_id( &self, db: &dyn db::DefDatabase, + krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, ) -> Option; } @@ -425,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> { fn as_call_id( &self, db: &dyn db::DefDatabase, + krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, ) -> Option { let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); let h = Hygiene::new(db.upcast(), self.file_id); let path = path::ModPath::from_src(self.value.path()?, &h)?; - AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver) + AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) } } @@ -452,6 +454,7 @@ impl AsMacroCall for AstIdWithPath { fn as_call_id( &self, db: &dyn db::DefDatabase, + krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, ) -> Option { let def: MacroDefId = resolver(self.path.clone())?; @@ -461,13 +464,13 @@ impl AsMacroCall for AstIdWithPath { let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); Some( - expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| { + expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { resolver(path::ModPath::from_src(path, &hygiene)?) })? .into(), ) } else { - Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into()) + Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into()) } } } @@ -476,12 +479,14 @@ impl AsMacroCall for AstIdWithPath { fn as_call_id( &self, db: &dyn db::DefDatabase, + krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, ) -> Option { let def = resolver(self.path.clone())?; Some( def.as_lazy_macro( db.upcast(), + krate, MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), ) .into(), diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 353a31ad4..976e5e585 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -571,16 +571,18 @@ impl DefCollector<'_> { return false; } - if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| { - let resolved_res = self.def_map.resolve_path_fp_with_macro( - self.db, - ResolveMode::Other, - directive.module_id, - &path, - BuiltinShadowMode::Module, - ); - resolved_res.resolved_def.take_macros() - }) { + if let Some(call_id) = + directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { + let resolved_res = self.def_map.resolve_path_fp_with_macro( + self.db, + ResolveMode::Other, + directive.module_id, + &path, + BuiltinShadowMode::Module, + ); + resolved_res.resolved_def.take_macros() + }) + { resolved.push((directive.module_id, call_id, directive.depth)); res = ReachedFixedPoint::No; return false; @@ -589,9 +591,10 @@ impl DefCollector<'_> { true }); attribute_macros.retain(|directive| { - if let Some(call_id) = directive - .ast_id - .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) + if let Some(call_id) = + directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { + self.resolve_attribute_macro(&directive, &path) + }) { resolved.push((directive.module_id, call_id, 0)); res = ReachedFixedPoint::No; @@ -957,11 +960,13 @@ impl ModCollector<'_, '_> { } // Case 2: try to resolve in legacy scope and expand macro_rules - if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| { - path.as_ident().and_then(|name| { - self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) + if let Some(macro_call_id) = + ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| { + path.as_ident().and_then(|name| { + self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) + }) }) - }) { + { self.def_collector.unexpanded_macros.push(MacroDirective { module_id: self.module_id, ast_id, diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 967d1f3a1..26b667b55 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -8,8 +8,7 @@ use ra_syntax::{ match_ast, }; -use crate::db::AstDatabase; -use crate::{guess_crate, name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; +use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind}; macro_rules! register_builtin { ( $($trait:ident => $expand:ident),* ) => { @@ -156,17 +155,8 @@ fn expand_simple_derive( fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { // FIXME: make hygiene works for builtin derive macro // such that $crate can be used here. - - let m: MacroCallId = id.into(); - let file_id = m.as_file().original_file(db); let cg = db.crate_graph(); - let krate = match guess_crate(db, file_id) { - Some(krate) => krate, - None => { - let tt = quote! { core }; - return tt.token_trees[0].clone(); - } - }; + let krate = db.lookup_intern_macro(id).krate; // XXX // All crates except core itself should have a dependency on core, @@ -263,10 +253,12 @@ fn partial_ord_expand( #[cfg(test)] mod tests { - use super::*; - use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; use name::{known, Name}; - use ra_db::{fixture::WithFixture, SourceDatabase}; + use ra_db::{fixture::WithFixture, CrateId, SourceDatabase}; + + use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; + + use super::*; fn expand_builtin_derive(s: &str, name: Name) -> String { let def = find_builtin_derive(&name).unwrap(); @@ -290,7 +282,11 @@ mod tests { let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); - let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; + let loc = MacroCallLoc { + def, + krate: CrateId(0), + kind: MacroCallKind::Attr(attr_id, name.to_string()), + }; let id: MacroCallId = db.intern_macro(loc).into(); let parsed = db.parse_or_expand(id.as_file()).unwrap(); diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 93da3f149..b50eb347c 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -1,15 +1,14 @@ //! Builtin macro -use crate::db::AstDatabase; use crate::{ - ast::{self, AstToken, HasStringValue}, - name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, + db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId, + MacroDefId, MacroDefKind, TextSize, }; -use crate::{guess_crate, quote, EagerMacroId, LazyMacroId, MacroCallId}; use either::Either; use mbe::parse_to_token_tree; use ra_db::FileId; use ra_parser::FragmentKind; +use ra_syntax::ast::{self, AstToken, HasStringValue}; macro_rules! register_builtin { ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { @@ -333,9 +332,7 @@ fn include_expand( } fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option { - let call_id: MacroCallId = arg_id.into(); - let original_file = call_id.as_file().original_file(db); - let krate = guess_crate(db, original_file)?; + let krate = db.lookup_intern_eager_expansion(arg_id).krate; db.crate_graph()[krate].env.get(key) } @@ -394,6 +391,7 @@ mod tests { let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); + let krate = CrateId(0); let file_id = match expander { Either::Left(expander) => { // the first one should be a macro_rules @@ -406,6 +404,7 @@ mod tests { let loc = MacroCallLoc { def, + krate, kind: MacroCallKind::FnLike(AstId::new( file_id.into(), ast_id_map.ast_id(¯o_calls[1]), @@ -418,7 +417,7 @@ mod tests { Either::Right(expander) => { // the first one should be a macro_rules let def = MacroDefId { - krate: Some(CrateId(0)), + krate: Some(krate), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), kind: MacroDefKind::BuiltInEager(expander), local_inner: false, @@ -432,6 +431,7 @@ mod tests { def, fragment: FragmentKind::Expr, subtree: Arc::new(parsed_args.clone()), + krate, file_id: file_id.into(), } }); @@ -441,6 +441,7 @@ mod tests { def, fragment, subtree: Arc::new(subtree), + krate, file_id: file_id.into(), }; diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs index 932f47c30..302d2b3e0 100644 --- a/crates/ra_hir_expand/src/eager.rs +++ b/crates/ra_hir_expand/src/eager.rs @@ -25,12 +25,14 @@ use crate::{ EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; +use ra_db::CrateId; use ra_parser::FragmentKind; use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; use std::sync::Arc; pub fn expand_eager_macro( db: &dyn AstDatabase, + krate: CrateId, macro_call: InFile, def: MacroDefId, resolver: &dyn Fn(ast::Path) -> Option, @@ -47,6 +49,7 @@ pub fn expand_eager_macro( def, fragment: FragmentKind::Expr, subtree: Arc::new(parsed_args.clone()), + krate, file_id: macro_call.file_id, } }); @@ -56,14 +59,20 @@ pub fn expand_eager_macro( let result = eager_macro_recur( db, InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), + krate, resolver, )?; let subtree = to_subtree(&result)?; if let MacroDefKind::BuiltInEager(eager) = def.kind { let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; - let eager = - EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; + let eager = EagerCallLoc { + def, + fragment, + subtree: Arc::new(subtree), + krate, + file_id: macro_call.file_id, + }; Some(db.intern_eager_expansion(eager)) } else { @@ -81,11 +90,12 @@ fn lazy_expand( db: &dyn AstDatabase, def: &MacroDefId, macro_call: InFile, + krate: CrateId, ) -> Option> { let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); let id: MacroCallId = - def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); + def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) } @@ -93,6 +103,7 @@ fn lazy_expand( fn eager_macro_recur( db: &dyn AstDatabase, curr: InFile, + krate: CrateId, macro_resolver: &dyn Fn(ast::Path) -> Option, ) -> Option { let original = curr.value.clone(); @@ -105,18 +116,23 @@ fn eager_macro_recur( let def: MacroDefId = macro_resolver(child.path()?)?; let insert = match def.kind { MacroDefKind::BuiltInEager(_) => { - let id: MacroCallId = - expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? - .into(); + let id: MacroCallId = expand_eager_macro( + db, + krate, + curr.with_value(child.clone()), + def, + macro_resolver, + )? + .into(); db.parse_or_expand(id.as_file())? } MacroDefKind::Declarative | MacroDefKind::BuiltIn(_) | MacroDefKind::BuiltInDerive(_) | MacroDefKind::CustomDerive(_) => { - let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; + let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?; // replace macro inside - eager_macro_recur(db, expanded, macro_resolver)? + eager_macro_recur(db, expanded, krate, macro_resolver)? } }; diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index dc4d7f000..5eac2605b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -209,8 +209,13 @@ pub struct MacroDefId { } impl MacroDefId { - pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { - db.intern_macro(MacroCallLoc { def: self, kind }) + pub fn as_lazy_macro( + self, + db: &dyn db::AstDatabase, + krate: CrateId, + kind: MacroCallKind, + ) -> LazyMacroId { + db.intern_macro(MacroCallLoc { def: self, krate, kind }) } } @@ -227,6 +232,7 @@ pub enum MacroDefKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MacroCallLoc { pub(crate) def: MacroDefId, + pub(crate) krate: CrateId, pub(crate) kind: MacroCallKind, } @@ -274,6 +280,7 @@ pub struct EagerCallLoc { pub(crate) def: MacroDefId, pub(crate) fragment: FragmentKind, pub(crate) subtree: Arc, + pub(crate) krate: CrateId, pub(crate) file_id: HirFileId, } @@ -424,8 +431,3 @@ impl InFile { self.with_value(self.value.syntax()) } } - -// FIXME: this is obviously wrong, there shouldn't be any guesing here -fn guess_crate(db: &dyn db::AstDatabase, file_id: FileId) -> Option { - db.relevant_crates(file_id).iter().next().copied() -} -- cgit v1.2.3 From 663ce0e99d8aa11707dd2ca22956552859b6ea12 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Jun 2020 13:26:48 +0200 Subject: Remove dead code --- crates/ra_ide_db/src/change.rs | 9 +-------- crates/ra_ide_db/src/lib.rs | 18 ++---------------- crates/rust-analyzer/src/cli/load_cargo.rs | 4 ---- crates/rust-analyzer/src/global_state.rs | 1 - 4 files changed, 3 insertions(+), 29 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 5dbe1c1b7..2fc796a85 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -16,7 +16,7 @@ use rustc_hash::FxHashMap; use crate::{ symbol_index::{SymbolIndex, SymbolsDatabase}, - DebugData, RootDatabase, + RootDatabase, }; #[derive(Default)] @@ -26,7 +26,6 @@ pub struct AnalysisChange { files_changed: Vec<(FileId, Arc)>, libraries_added: Vec, crate_graph: Option, - debug_data: DebugData, } impl fmt::Debug for AnalysisChange { @@ -87,10 +86,6 @@ impl AnalysisChange { pub fn set_crate_graph(&mut self, graph: CrateGraph) { self.crate_graph = Some(graph); } - - pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) { - self.debug_data.root_paths.insert(source_root_id, path); - } } #[derive(Debug)] @@ -218,8 +213,6 @@ impl RootDatabase { if let Some(crate_graph) = change.crate_graph { self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) } - - Arc::make_mut(&mut self.debug_data).merge(change.debug_data) } fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 480fd4576..a808de4f1 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -17,9 +17,9 @@ use hir::db::{AstDatabase, DefDatabase}; use ra_db::{ salsa::{self, Database, Durability}, Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, - SourceRootId, Upcast, + Upcast, }; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashSet; use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; @@ -36,7 +36,6 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; #[derive(Debug)] pub struct RootDatabase { runtime: salsa::Runtime, - pub(crate) debug_data: Arc, pub last_gc: crate::wasm_shims::Instant, pub last_gc_check: crate::wasm_shims::Instant, } @@ -98,7 +97,6 @@ impl RootDatabase { runtime: salsa::Runtime::default(), last_gc: crate::wasm_shims::Instant::now(), last_gc_check: crate::wasm_shims::Instant::now(), - debug_data: Default::default(), }; db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); db.set_local_roots_with_durability(Default::default(), Durability::HIGH); @@ -121,7 +119,6 @@ impl salsa::ParallelDatabase for RootDatabase { runtime: self.runtime.snapshot(self), last_gc: self.last_gc, last_gc_check: self.last_gc_check, - debug_data: Arc::clone(&self.debug_data), }) } } @@ -135,14 +132,3 @@ fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc { let text = db.file_text(file_id); Arc::new(LineIndex::new(&*text)) } - -#[derive(Debug, Default, Clone)] -pub(crate) struct DebugData { - pub(crate) root_paths: FxHashMap, -} - -impl DebugData { - pub(crate) fn merge(&mut self, other: DebugData) { - self.root_paths.extend(other.root_paths.into_iter()); - } -} diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 45af96317..97367d7c6 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -111,10 +111,6 @@ pub(crate) fn load( vfs.root2path(root) ); analysis_change.add_root(source_root_id, is_local); - analysis_change.set_debug_root_path( - source_root_id, - source_roots[&source_root_id].path().display().to_string(), - ); let vfs_root_path = vfs.root2path(root); if extern_dirs.contains(&vfs_root_path) { diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 96d91b12d..21116e165 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -126,7 +126,6 @@ impl GlobalState { let vfs_root_path = vfs.root2path(r); let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); change.add_root(SourceRootId(r.0), is_local); - change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); // FIXME: add path2root in vfs to simpily this logic if extern_dirs.contains(&vfs_root_path) { -- cgit v1.2.3 From 90331ea0350eaea281d35bd0aa13df7f20a8600d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 11 Jun 2020 16:22:31 +0200 Subject: Make known paths use `core` instead of `std` --- crates/ra_hir_def/src/data.rs | 2 +- crates/ra_hir_def/src/path.rs | 20 ++++++++++---------- crates/ra_hir_ty/src/expr.rs | 10 ++++++---- crates/ra_hir_ty/src/infer.rs | 16 ++++++++-------- crates/ra_hir_ty/src/tests/simple.rs | 4 ++-- crates/ra_hir_ty/src/tests/traits.rs | 30 ++++++++++++++++-------------- crates/ra_ide/src/diagnostics.rs | 18 +++++++++--------- 7 files changed, 52 insertions(+), 48 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 807195d25..53599e74a 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -99,7 +99,7 @@ impl FunctionData { } fn desugar_future_path(orig: TypeRef) -> Path { - let path = path![std::future::Future]; + let path = path![core::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); let mut last = GenericArgs::empty(); last.bindings.push(AssociatedTypeBinding { diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index bfa921de2..ba16442bd 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -323,16 +323,16 @@ pub use hir_expand::name as __name; #[macro_export] macro_rules! __known_path { - (std::iter::IntoIterator) => {}; - (std::result::Result) => {}; - (std::ops::Range) => {}; - (std::ops::RangeFrom) => {}; - (std::ops::RangeFull) => {}; - (std::ops::RangeTo) => {}; - (std::ops::RangeToInclusive) => {}; - (std::ops::RangeInclusive) => {}; - (std::future::Future) => {}; - (std::ops::Try) => {}; + (core::iter::IntoIterator) => {}; + (core::result::Result) => {}; + (core::ops::Range) => {}; + (core::ops::RangeFrom) => {}; + (core::ops::RangeFull) => {}; + (core::ops::RangeTo) => {}; + (core::ops::RangeToInclusive) => {}; + (core::ops::RangeInclusive) => {}; + (core::future::Future) => {}; + (core::ops::Try) => {}; ($path:path) => { compile_error!("Please register your known path in the path module") }; diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index f04968e14..7db928dde 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs @@ -226,17 +226,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> { None => return, }; - let std_result_path = path![std::result::Result]; + let core_result_path = path![core::result::Result]; let resolver = self.func.resolver(db.upcast()); - let std_result_enum = match resolver.resolve_known_enum(db.upcast(), &std_result_path) { + let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { Some(it) => it, _ => return, }; - let std_result_ctor = TypeCtor::Adt(AdtId::EnumId(std_result_enum)); + let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); let params = match &mismatch.expected { - Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, + Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { + parameters + } _ => return, }; diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f965eb2b5..3719f76a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -555,13 +555,13 @@ impl<'a> InferenceContext<'a> { } fn resolve_into_iter_item(&self) -> Option { - let path = path![std::iter::IntoIterator]; + let path = path![core::iter::IntoIterator]; let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Item]) } fn resolve_ops_try_ok(&self) -> Option { - let path = path![std::ops::Try]; + let path = path![core::ops::Try]; let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) } @@ -587,37 +587,37 @@ impl<'a> InferenceContext<'a> { } fn resolve_range_full(&self) -> Option { - let path = path![std::ops::RangeFull]; + let path = path![core::ops::RangeFull]; let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; Some(struct_.into()) } fn resolve_range(&self) -> Option { - let path = path![std::ops::Range]; + let path = path![core::ops::Range]; let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; Some(struct_.into()) } fn resolve_range_inclusive(&self) -> Option { - let path = path![std::ops::RangeInclusive]; + let path = path![core::ops::RangeInclusive]; let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; Some(struct_.into()) } fn resolve_range_from(&self) -> Option { - let path = path![std::ops::RangeFrom]; + let path = path![core::ops::RangeFrom]; let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; Some(struct_.into()) } fn resolve_range_to(&self) -> Option { - let path = path![std::ops::RangeTo]; + let path = path![core::ops::RangeTo]; let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; Some(struct_.into()) } fn resolve_range_to_inclusive(&self) -> Option { - let path = path![std::ops::RangeToInclusive]; + let path = path![core::ops::RangeToInclusive]; let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; Some(struct_.into()) } diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 8a5031756..37659cd02 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -95,7 +95,7 @@ fn foo() { fn infer_ranges() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core fn test() { let a = ..; let b = 1..; @@ -108,7 +108,7 @@ fn test() { t<|>; } -//- /std.rs crate:std +//- /core.rs crate:core #[prelude_import] use prelude::*; mod prelude {} diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 133fb5f39..e81193a3c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -10,7 +10,7 @@ use super::{infer, infer_with_mismatches, type_at, type_at_pos}; fn infer_await() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core struct IntFuture; @@ -24,7 +24,7 @@ fn test() { v<|>; } -//- /std.rs crate:std +//- /core.rs crate:core #[prelude_import] use future::*; mod future { #[lang = "future_trait"] @@ -42,7 +42,7 @@ mod future { fn infer_async() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core async fn foo() -> u64 { 128 @@ -54,7 +54,7 @@ fn test() { v<|>; } -//- /std.rs crate:std +//- /core.rs crate:core #[prelude_import] use future::*; mod future { #[lang = "future_trait"] @@ -72,7 +72,7 @@ mod future { fn infer_desugar_async() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core async fn foo() -> u64 { 128 @@ -83,7 +83,7 @@ fn test() { r<|>; } -//- /std.rs crate:std +//- /core.rs crate:core #[prelude_import] use future::*; mod future { trait Future { @@ -100,7 +100,7 @@ mod future { fn infer_try() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core fn test() { let r: Result = Result::Ok(1); @@ -108,7 +108,7 @@ fn test() { v<|>; } -//- /std.rs crate:std +//- /core.rs crate:core #[prelude_import] use ops::*; mod ops { @@ -140,9 +140,9 @@ mod result { fn infer_for_loop() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core,alloc -use std::collections::Vec; +use alloc::collections::Vec; fn test() { let v = Vec::new(); @@ -152,7 +152,7 @@ fn test() { } } -//- /std.rs crate:std +//- /core.rs crate:core #[prelude_import] use iter::*; mod iter { @@ -161,6 +161,8 @@ mod iter { } } +//- /alloc.rs crate:alloc deps:core + mod collections { struct Vec {} impl Vec { @@ -168,7 +170,7 @@ mod collections { fn push(&mut self, t: T) { } } - impl crate::iter::IntoIterator for Vec { + impl IntoIterator for Vec { type Item=T; } } @@ -2846,12 +2848,12 @@ fn test() { fn integer_range_iterate() { let t = type_at( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core fn test() { for x in 0..100 { x<|>; } } -//- /std.rs crate:std +//- /core.rs crate:core pub mod ops { pub struct Range { pub start: Idx, diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index bf14a467f..0f1cb0bcc 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -321,7 +321,7 @@ mod tests { fn test_wrap_return_type() { let before = r#" //- /main.rs - use std::{string::String, result::Result::{self, Ok, Err}}; + use core::{string::String, result::Result::{self, Ok, Err}}; fn div(x: i32, y: i32) -> Result { if y == 0 { @@ -330,7 +330,7 @@ mod tests { x / y<|> } - //- /std/lib.rs + //- /core/lib.rs pub mod string { pub struct String { } } @@ -339,7 +339,7 @@ mod tests { } "#; let after = r#" - use std::{string::String, result::Result::{self, Ok, Err}}; + use core::{string::String, result::Result::{self, Ok, Err}}; fn div(x: i32, y: i32) -> Result { if y == 0 { @@ -355,7 +355,7 @@ mod tests { fn test_wrap_return_type_handles_generic_functions() { let before = r#" //- /main.rs - use std::result::Result::{self, Ok, Err}; + use core::result::Result::{self, Ok, Err}; fn div(x: T) -> Result { if x == 0 { @@ -364,13 +364,13 @@ mod tests { <|>x } - //- /std/lib.rs + //- /core/lib.rs pub mod result { pub enum Result { Ok(T), Err(E) } } "#; let after = r#" - use std::result::Result::{self, Ok, Err}; + use core::result::Result::{self, Ok, Err}; fn div(x: T) -> Result { if x == 0 { @@ -386,7 +386,7 @@ mod tests { fn test_wrap_return_type_handles_type_aliases() { let before = r#" //- /main.rs - use std::{string::String, result::Result::{self, Ok, Err}}; + use core::{string::String, result::Result::{self, Ok, Err}}; type MyResult = Result; @@ -397,7 +397,7 @@ mod tests { x <|>/ y } - //- /std/lib.rs + //- /core/lib.rs pub mod string { pub struct String { } } @@ -406,7 +406,7 @@ mod tests { } "#; let after = r#" - use std::{string::String, result::Result::{self, Ok, Err}}; + use core::{string::String, result::Result::{self, Ok, Err}}; type MyResult = Result; fn div(x: i32, y: i32) -> MyResult { -- cgit v1.2.3 From 279a1ae5646aa474f6e6b6d2a0b9c248e7e0460c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Jun 2020 17:13:24 +0200 Subject: Indent chain `.` even if there's more stuff afterwards --- crates/ra_ide/src/typing.rs | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 533306e2e..83776d2b6 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs @@ -21,7 +21,9 @@ use ra_ide_db::{source_change::SourceFileEdit, RootDatabase}; use ra_syntax::{ algo::find_node_at_offset, ast::{self, AstToken}, - AstNode, SourceFile, TextRange, TextSize, + AstNode, SourceFile, + SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, + TextRange, TextSize, }; use ra_text_edit::TextEdit; @@ -98,9 +100,12 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { }; let current_indent_len = TextSize::of(current_indent); + let parent = whitespace.syntax().parent(); // Make sure dot is a part of call chain - let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?; - let prev_indent = leading_indent(field_expr.syntax())?; + if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) { + return None; + } + let prev_indent = leading_indent(&parent)?; let target_indent = format!(" {}", prev_indent); let target_indent_len = TextSize::of(&target_indent); if current_indent_len == target_indent_len { @@ -143,11 +148,11 @@ mod tests { }) } - fn type_char(char_typed: char, before: &str, after: &str) { - let actual = do_type_char(char_typed, before) + fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) { + let actual = do_type_char(char_typed, ra_fixture_before) .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); - assert_eq_text!(after, &actual); + assert_eq_text!(ra_fixture_after, &actual); } fn type_char_noop(char_typed: char, before: &str) { @@ -248,6 +253,27 @@ fn foo() { ) } + #[test] + fn indents_new_chain_call_with_let() { + type_char( + '.', + r#" +fn main() { + let _ = foo + <|> + bar() +} +"#, + r#" +fn main() { + let _ = foo + . + bar() +} +"#, + ); + } + #[test] fn indents_continued_chain_call() { type_char( -- cgit v1.2.3 From 215e229dd1a495cda6541371c75145ba03f62de5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 11 Jun 2020 17:28:32 +0200 Subject: Update wrap return tests Update "no diagnostic" tests, use `()` instead of `String` --- crates/ra_ide/src/diagnostics.rs | 46 +++++++++++++++------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 0f1cb0bcc..f44feaf69 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -321,29 +321,26 @@ mod tests { fn test_wrap_return_type() { let before = r#" //- /main.rs - use core::{string::String, result::Result::{self, Ok, Err}}; + use core::result::Result::{self, Ok, Err}; - fn div(x: i32, y: i32) -> Result { + fn div(x: i32, y: i32) -> Result { if y == 0 { - return Err("div by zero".into()); + return Err(()); } x / y<|> } //- /core/lib.rs - pub mod string { - pub struct String { } - } pub mod result { pub enum Result { Ok(T), Err(E) } } "#; let after = r#" - use core::{string::String, result::Result::{self, Ok, Err}}; + use core::result::Result::{self, Ok, Err}; - fn div(x: i32, y: i32) -> Result { + fn div(x: i32, y: i32) -> Result { if y == 0 { - return Err("div by zero".into()); + return Err(()); } Ok(x / y) } @@ -386,32 +383,29 @@ mod tests { fn test_wrap_return_type_handles_type_aliases() { let before = r#" //- /main.rs - use core::{string::String, result::Result::{self, Ok, Err}}; + use core::result::Result::{self, Ok, Err}; - type MyResult = Result; + type MyResult = Result; fn div(x: i32, y: i32) -> MyResult { if y == 0 { - return Err("div by zero".into()); + return Err(()); } x <|>/ y } //- /core/lib.rs - pub mod string { - pub struct String { } - } pub mod result { pub enum Result { Ok(T), Err(E) } } "#; let after = r#" - use core::{string::String, result::Result::{self, Ok, Err}}; + use core::result::Result::{self, Ok, Err}; - type MyResult = Result; + type MyResult = Result; fn div(x: i32, y: i32) -> MyResult { if y == 0 { - return Err("div by zero".into()); + return Err(()); } Ok(x / y) } @@ -423,16 +417,13 @@ mod tests { fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { let content = r#" //- /main.rs - use std::{string::String, result::Result::{self, Ok, Err}}; + use core::result::Result::{self, Ok, Err}; - fn foo() -> Result { + fn foo() -> Result<(), i32> { 0<|> } - //- /std/lib.rs - pub mod string { - pub struct String { } - } + //- /core/lib.rs pub mod result { pub enum Result { Ok(T), Err(E) } } @@ -444,7 +435,7 @@ mod tests { fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { let content = r#" //- /main.rs - use std::{string::String, result::Result::{self, Ok, Err}}; + use core::result::Result::{self, Ok, Err}; enum SomeOtherEnum { Ok(i32), @@ -455,10 +446,7 @@ mod tests { 0<|> } - //- /std/lib.rs - pub mod string { - pub struct String { } - } + //- /core/lib.rs pub mod result { pub enum Result { Ok(T), Err(E) } } -- cgit v1.2.3 From 879693e63c19b474153473e11f96ab9c321739db Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Jun 2020 18:14:57 +0100 Subject: Move complex inline test to own file --- crates/ra_parser/src/grammar/type_params.rs | 16 - .../parser/err/0044_unexpected_for_type.rast | 324 ++++++++++++----- .../parser/err/0044_unexpected_for_type.rs | 12 +- .../parser/inline/ok/0003_where_pred_for.rast | 252 +------------ .../parser/inline/ok/0003_where_pred_for.rs | 16 - .../test_data/parser/ok/0067_where_for_pred.rast | 392 +++++++++++++++++++++ .../test_data/parser/ok/0067_where_for_pred.rs | 30 ++ 7 files changed, 670 insertions(+), 372 deletions(-) create mode 100644 crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast create mode 100644 crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index b3508c732..325d566ad 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs @@ -195,22 +195,6 @@ fn where_predicate(p: &mut Parser) { // where // for<'a> F: Fn(&'a str) // { } - // fn for_ref() - // where - // for<'a> &'a F: Debug - // { } - // fn for_parens() - // where - // for<'a> (&'a F): Fn(&'a str) - // { } - // fn for_slice() - // where - // for<'a> [&'a F]: Eq - // { } - // fn for_qpath(_t: &T) - // where - // for<'a> <&'a T as Baz>::Foo: Iterator - // { } if p.at(T![for]) { types::for_binder(p); } diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast index 3400beff0..cb90f28bc 100644 --- a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast +++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast @@ -1,88 +1,240 @@ -SOURCE_FILE@0..79 - TYPE_ALIAS_DEF@0..25 +SOURCE_FILE@0..239 + TYPE_ALIAS_DEF@0..30 TYPE_KW@0..4 "type" WHITESPACE@4..5 " " - NAME@5..6 - IDENT@5..6 "A" - WHITESPACE@6..7 " " - EQ@7..8 "=" - WHITESPACE@8..9 " " - FOR_TYPE@9..24 - FOR_KW@9..12 "for" - TYPE_PARAM_LIST@12..16 - L_ANGLE@12..13 "<" - LIFETIME_PARAM@13..15 - LIFETIME@13..15 "\'a" - R_ANGLE@15..16 ">" - WHITESPACE@16..17 " " - REFERENCE_TYPE@17..24 - AMP@17..18 "&" - LIFETIME@18..20 "\'a" - WHITESPACE@20..21 " " - PATH_TYPE@21..24 - PATH@21..24 - PATH_SEGMENT@21..24 - NAME_REF@21..24 - IDENT@21..24 "u32" - SEMICOLON@24..25 ";" - WHITESPACE@25..26 "\n" - TYPE_ALIAS_DEF@26..54 - TYPE_KW@26..30 "type" - WHITESPACE@30..31 " " - NAME@31..32 - IDENT@31..32 "B" - WHITESPACE@32..33 " " - EQ@33..34 "=" - WHITESPACE@34..35 " " - FOR_TYPE@35..53 - FOR_KW@35..38 "for" - TYPE_PARAM_LIST@38..42 - L_ANGLE@38..39 "<" - LIFETIME_PARAM@39..41 - LIFETIME@39..41 "\'a" - R_ANGLE@41..42 ">" - WHITESPACE@42..43 " " - TUPLE_TYPE@43..53 - L_PAREN@43..44 "(" - REFERENCE_TYPE@44..51 - AMP@44..45 "&" - LIFETIME@45..47 "\'a" - WHITESPACE@47..48 " " - PATH_TYPE@48..51 - PATH@48..51 - PATH_SEGMENT@48..51 - NAME_REF@48..51 - IDENT@48..51 "u32" - COMMA@51..52 "," - R_PAREN@52..53 ")" - SEMICOLON@53..54 ";" - WHITESPACE@54..55 "\n" - TYPE_ALIAS_DEF@55..78 - TYPE_KW@55..59 "type" - WHITESPACE@59..60 " " - NAME@60..61 - IDENT@60..61 "B" - WHITESPACE@61..62 " " - EQ@62..63 "=" - WHITESPACE@63..64 " " - FOR_TYPE@64..77 - FOR_KW@64..67 "for" - TYPE_PARAM_LIST@67..71 - L_ANGLE@67..68 "<" - LIFETIME_PARAM@68..70 - LIFETIME@68..70 "\'a" - R_ANGLE@70..71 ">" - WHITESPACE@71..72 " " - SLICE_TYPE@72..77 - L_BRACK@72..73 "[" - PATH_TYPE@73..76 - PATH@73..76 - PATH_SEGMENT@73..76 - NAME_REF@73..76 - IDENT@73..76 "u32" - R_BRACK@76..77 "]" - SEMICOLON@77..78 ";" - WHITESPACE@78..79 "\n" -error 16..16: expected a function pointer or path -error 42..42: expected a function pointer or path -error 71..71: expected a function pointer or path + NAME@5..11 + IDENT@5..11 "ForRef" + WHITESPACE@11..12 " " + EQ@12..13 "=" + WHITESPACE@13..14 " " + FOR_TYPE@14..29 + FOR_KW@14..17 "for" + TYPE_PARAM_LIST@17..21 + L_ANGLE@17..18 "<" + LIFETIME_PARAM@18..20 + LIFETIME@18..20 "\'a" + R_ANGLE@20..21 ">" + WHITESPACE@21..22 " " + REFERENCE_TYPE@22..29 + AMP@22..23 "&" + LIFETIME@23..25 "\'a" + WHITESPACE@25..26 " " + PATH_TYPE@26..29 + PATH@26..29 + PATH_SEGMENT@26..29 + NAME_REF@26..29 + IDENT@26..29 "u32" + SEMICOLON@29..30 ";" + WHITESPACE@30..31 "\n" + TYPE_ALIAS_DEF@31..64 + TYPE_KW@31..35 "type" + WHITESPACE@35..36 " " + NAME@36..42 + IDENT@36..42 "ForTup" + WHITESPACE@42..43 " " + EQ@43..44 "=" + WHITESPACE@44..45 " " + FOR_TYPE@45..63 + FOR_KW@45..48 "for" + TYPE_PARAM_LIST@48..52 + L_ANGLE@48..49 "<" + LIFETIME_PARAM@49..51 + LIFETIME@49..51 "\'a" + R_ANGLE@51..52 ">" + WHITESPACE@52..53 " " + TUPLE_TYPE@53..63 + L_PAREN@53..54 "(" + REFERENCE_TYPE@54..61 + AMP@54..55 "&" + LIFETIME@55..57 "\'a" + WHITESPACE@57..58 " " + PATH_TYPE@58..61 + PATH@58..61 + PATH_SEGMENT@58..61 + NAME_REF@58..61 + IDENT@58..61 "u32" + COMMA@61..62 "," + R_PAREN@62..63 ")" + SEMICOLON@63..64 ";" + WHITESPACE@64..65 "\n" + TYPE_ALIAS_DEF@65..95 + TYPE_KW@65..69 "type" + WHITESPACE@69..70 " " + NAME@70..78 + IDENT@70..78 "ForSlice" + WHITESPACE@78..79 " " + EQ@79..80 "=" + WHITESPACE@80..81 " " + FOR_TYPE@81..94 + FOR_KW@81..84 "for" + TYPE_PARAM_LIST@84..88 + L_ANGLE@84..85 "<" + LIFETIME_PARAM@85..87 + LIFETIME@85..87 "\'a" + R_ANGLE@87..88 ">" + WHITESPACE@88..89 " " + SLICE_TYPE@89..94 + L_BRACK@89..90 "[" + PATH_TYPE@90..93 + PATH@90..93 + PATH_SEGMENT@90..93 + NAME_REF@90..93 + IDENT@90..93 "u32" + R_BRACK@93..94 "]" + SEMICOLON@94..95 ";" + WHITESPACE@95..96 "\n" + TYPE_ALIAS_DEF@96..149 + TYPE_KW@96..100 "type" + WHITESPACE@100..101 " " + NAME@101..109 + IDENT@101..109 "ForForFn" + WHITESPACE@109..110 " " + EQ@110..111 "=" + WHITESPACE@111..112 " " + FOR_TYPE@112..148 + FOR_KW@112..115 "for" + TYPE_PARAM_LIST@115..119 + L_ANGLE@115..116 "<" + LIFETIME_PARAM@116..118 + LIFETIME@116..118 "\'a" + R_ANGLE@118..119 ">" + WHITESPACE@119..120 " " + FOR_TYPE@120..148 + FOR_KW@120..123 "for" + TYPE_PARAM_LIST@123..127 + L_ANGLE@123..124 "<" + LIFETIME_PARAM@124..126 + LIFETIME@124..126 "\'b" + R_ANGLE@126..127 ">" + WHITESPACE@127..128 " " + FN_POINTER_TYPE@128..148 + FN_KW@128..130 "fn" + PARAM_LIST@130..148 + L_PAREN@130..131 "(" + PARAM@131..138 + REFERENCE_TYPE@131..138 + AMP@131..132 "&" + LIFETIME@132..134 "\'a" + WHITESPACE@134..135 " " + PATH_TYPE@135..138 + PATH@135..138 + PATH_SEGMENT@135..138 + NAME_REF@135..138 + IDENT@135..138 "i32" + COMMA@138..139 "," + WHITESPACE@139..140 " " + PARAM@140..147 + REFERENCE_TYPE@140..147 + AMP@140..141 "&" + LIFETIME@141..143 "\'b" + WHITESPACE@143..144 " " + PATH_TYPE@144..147 + PATH@144..147 + PATH_SEGMENT@144..147 + NAME_REF@144..147 + IDENT@144..147 "i32" + R_PAREN@147..148 ")" + SEMICOLON@148..149 ";" + WHITESPACE@149..150 "\n" + FN_DEF@150..238 + FN_KW@150..152 "fn" + WHITESPACE@152..153 " " + NAME@153..164 + IDENT@153..164 "for_for_for" + TYPE_PARAM_LIST@164..167 + L_ANGLE@164..165 "<" + TYPE_PARAM@165..166 + NAME@165..166 + IDENT@165..166 "T" + R_ANGLE@166..167 ">" + PARAM_LIST@167..169 + L_PAREN@167..168 "(" + R_PAREN@168..169 ")" + WHITESPACE@169..170 "\n" + WHERE_CLAUSE@170..234 + WHERE_KW@170..175 "where" + WHITESPACE@175..180 "\n " + WHERE_PRED@180..233 + FOR_KW@180..183 "for" + TYPE_PARAM_LIST@183..187 + L_ANGLE@183..184 "<" + LIFETIME_PARAM@184..186 + LIFETIME@184..186 "\'a" + R_ANGLE@186..187 ">" + WHITESPACE@187..188 " " + FOR_TYPE@188..227 + FOR_KW@188..191 "for" + TYPE_PARAM_LIST@191..195 + L_ANGLE@191..192 "<" + LIFETIME_PARAM@192..194 + LIFETIME@192..194 "\'b" + R_ANGLE@194..195 ">" + WHITESPACE@195..196 " " + FOR_TYPE@196..227 + FOR_KW@196..199 "for" + TYPE_PARAM_LIST@199..203 + L_ANGLE@199..200 "<" + LIFETIME_PARAM@200..202 + LIFETIME@200..202 "\'c" + R_ANGLE@202..203 ">" + WHITESPACE@203..204 " " + FN_POINTER_TYPE@204..227 + FN_KW@204..206 "fn" + PARAM_LIST@206..227 + L_PAREN@206..207 "(" + PARAM@207..212 + REFERENCE_TYPE@207..212 + AMP@207..208 "&" + LIFETIME@208..210 "\'a" + WHITESPACE@210..211 " " + PATH_TYPE@211..212 + PATH@211..212 + PATH_SEGMENT@211..212 + NAME_REF@211..212 + IDENT@211..212 "T" + COMMA@212..213 "," + WHITESPACE@213..214 " " + PARAM@214..219 + REFERENCE_TYPE@214..219 + AMP@214..215 "&" + LIFETIME@215..217 "\'b" + WHITESPACE@217..218 " " + PATH_TYPE@218..219 + PATH@218..219 + PATH_SEGMENT@218..219 + NAME_REF@218..219 + IDENT@218..219 "T" + COMMA@219..220 "," + WHITESPACE@220..221 " " + PARAM@221..226 + REFERENCE_TYPE@221..226 + AMP@221..222 "&" + LIFETIME@222..224 "\'c" + WHITESPACE@224..225 " " + PATH_TYPE@225..226 + PATH@225..226 + PATH_SEGMENT@225..226 + NAME_REF@225..226 + IDENT@225..226 "T" + R_PAREN@226..227 ")" + COLON@227..228 ":" + WHITESPACE@228..229 " " + TYPE_BOUND_LIST@229..233 + TYPE_BOUND@229..233 + PATH_TYPE@229..233 + PATH@229..233 + PATH_SEGMENT@229..233 + NAME_REF@229..233 + IDENT@229..233 "Copy" + COMMA@233..234 "," + WHITESPACE@234..235 "\n" + BLOCK_EXPR@235..238 + L_CURLY@235..236 "{" + WHITESPACE@236..237 "\n" + R_CURLY@237..238 "}" + WHITESPACE@238..239 "\n" +error 21..21: expected a function pointer or path +error 52..52: expected a function pointer or path +error 88..88: expected a function pointer or path +error 119..119: expected a function pointer or path +error 195..195: expected a function pointer or path diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs index f34ac7fc5..0e9f8ccb4 100644 --- a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs +++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs @@ -1,3 +1,9 @@ -type A = for<'a> &'a u32; -type B = for<'a> (&'a u32,); -type B = for<'a> [u32]; +type ForRef = for<'a> &'a u32; +type ForTup = for<'a> (&'a u32,); +type ForSlice = for<'a> [u32]; +type ForForFn = for<'a> for<'b> fn(&'a i32, &'b i32); +fn for_for_for() +where + for<'a> for<'b> for<'c> fn(&'a T, &'b T, &'c T): Copy, +{ +} diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast index 4f88bfe43..cd0892451 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast @@ -1,4 +1,4 @@ -SOURCE_FILE@0..292 +SOURCE_FILE@0..54 FN_DEF@0..53 FN_KW@0..2 "fn" WHITESPACE@2..3 " " @@ -58,253 +58,3 @@ SOURCE_FILE@0..292 WHITESPACE@51..52 " " R_CURLY@52..53 "}" WHITESPACE@53..54 "\n" - FN_DEF@54..103 - FN_KW@54..56 "fn" - WHITESPACE@56..57 " " - NAME@57..64 - IDENT@57..64 "for_ref" - TYPE_PARAM_LIST@64..67 - L_ANGLE@64..65 "<" - TYPE_PARAM@65..66 - NAME@65..66 - IDENT@65..66 "F" - R_ANGLE@66..67 ">" - PARAM_LIST@67..69 - L_PAREN@67..68 "(" - R_PAREN@68..69 ")" - WHITESPACE@69..70 "\n" - WHERE_CLAUSE@70..99 - WHERE_KW@70..75 "where" - WHITESPACE@75..79 "\n " - WHERE_PRED@79..99 - FOR_KW@79..82 "for" - TYPE_PARAM_LIST@82..86 - L_ANGLE@82..83 "<" - LIFETIME_PARAM@83..85 - LIFETIME@83..85 "\'a" - R_ANGLE@85..86 ">" - WHITESPACE@86..87 " " - REFERENCE_TYPE@87..92 - AMP@87..88 "&" - LIFETIME@88..90 "\'a" - WHITESPACE@90..91 " " - PATH_TYPE@91..92 - PATH@91..92 - PATH_SEGMENT@91..92 - NAME_REF@91..92 - IDENT@91..92 "F" - COLON@92..93 ":" - WHITESPACE@93..94 " " - TYPE_BOUND_LIST@94..99 - TYPE_BOUND@94..99 - PATH_TYPE@94..99 - PATH@94..99 - PATH_SEGMENT@94..99 - NAME_REF@94..99 - IDENT@94..99 "Debug" - WHITESPACE@99..100 "\n" - BLOCK_EXPR@100..103 - L_CURLY@100..101 "{" - WHITESPACE@101..102 " " - R_CURLY@102..103 "}" - WHITESPACE@103..104 "\n" - FN_DEF@104..164 - FN_KW@104..106 "fn" - WHITESPACE@106..107 " " - NAME@107..117 - IDENT@107..117 "for_parens" - TYPE_PARAM_LIST@117..120 - L_ANGLE@117..118 "<" - TYPE_PARAM@118..119 - NAME@118..119 - IDENT@118..119 "F" - R_ANGLE@119..120 ">" - PARAM_LIST@120..122 - L_PAREN@120..121 "(" - R_PAREN@121..122 ")" - WHITESPACE@122..123 "\n" - WHERE_CLAUSE@123..160 - WHERE_KW@123..128 "where" - WHITESPACE@128..132 "\n " - WHERE_PRED@132..160 - FOR_KW@132..135 "for" - TYPE_PARAM_LIST@135..139 - L_ANGLE@135..136 "<" - LIFETIME_PARAM@136..138 - LIFETIME@136..138 "\'a" - R_ANGLE@138..139 ">" - WHITESPACE@139..140 " " - PAREN_TYPE@140..147 - L_PAREN@140..141 "(" - REFERENCE_TYPE@141..146 - AMP@141..142 "&" - LIFETIME@142..144 "\'a" - WHITESPACE@144..145 " " - PATH_TYPE@145..146 - PATH@145..146 - PATH_SEGMENT@145..146 - NAME_REF@145..146 - IDENT@145..146 "F" - R_PAREN@146..147 ")" - COLON@147..148 ":" - WHITESPACE@148..149 " " - TYPE_BOUND_LIST@149..160 - TYPE_BOUND@149..160 - PATH_TYPE@149..160 - PATH@149..160 - PATH_SEGMENT@149..160 - NAME_REF@149..151 - IDENT@149..151 "Fn" - PARAM_LIST@151..160 - L_PAREN@151..152 "(" - PARAM@152..159 - REFERENCE_TYPE@152..159 - AMP@152..153 "&" - LIFETIME@153..155 "\'a" - WHITESPACE@155..156 " " - PATH_TYPE@156..159 - PATH@156..159 - PATH_SEGMENT@156..159 - NAME_REF@156..159 - IDENT@156..159 "str" - R_PAREN@159..160 ")" - WHITESPACE@160..161 "\n" - BLOCK_EXPR@161..164 - L_CURLY@161..162 "{" - WHITESPACE@162..163 " " - R_CURLY@163..164 "}" - WHITESPACE@164..165 "\n" - FN_DEF@165..215 - FN_KW@165..167 "fn" - WHITESPACE@167..168 " " - NAME@168..177 - IDENT@168..177 "for_slice" - TYPE_PARAM_LIST@177..180 - L_ANGLE@177..178 "<" - TYPE_PARAM@178..179 - NAME@178..179 - IDENT@178..179 "F" - R_ANGLE@179..180 ">" - PARAM_LIST@180..182 - L_PAREN@180..181 "(" - R_PAREN@181..182 ")" - WHITESPACE@182..183 "\n" - WHERE_CLAUSE@183..211 - WHERE_KW@183..188 "where" - WHITESPACE@188..192 "\n " - WHERE_PRED@192..211 - FOR_KW@192..195 "for" - TYPE_PARAM_LIST@195..199 - L_ANGLE@195..196 "<" - LIFETIME_PARAM@196..198 - LIFETIME@196..198 "\'a" - R_ANGLE@198..199 ">" - WHITESPACE@199..200 " " - SLICE_TYPE@200..207 - L_BRACK@200..201 "[" - REFERENCE_TYPE@201..206 - AMP@201..202 "&" - LIFETIME@202..204 "\'a" - WHITESPACE@204..205 " " - PATH_TYPE@205..206 - PATH@205..206 - PATH_SEGMENT@205..206 - NAME_REF@205..206 - IDENT@205..206 "F" - R_BRACK@206..207 "]" - COLON@207..208 ":" - WHITESPACE@208..209 " " - TYPE_BOUND_LIST@209..211 - TYPE_BOUND@209..211 - PATH_TYPE@209..211 - PATH@209..211 - PATH_SEGMENT@209..211 - NAME_REF@209..211 - IDENT@209..211 "Eq" - WHITESPACE@211..212 "\n" - BLOCK_EXPR@212..215 - L_CURLY@212..213 "{" - WHITESPACE@213..214 " " - R_CURLY@214..215 "}" - WHITESPACE@215..216 "\n" - FN_DEF@216..291 - FN_KW@216..218 "fn" - WHITESPACE@218..219 " " - NAME@219..228 - IDENT@219..228 "for_qpath" - TYPE_PARAM_LIST@228..231 - L_ANGLE@228..229 "<" - TYPE_PARAM@229..230 - NAME@229..230 - IDENT@229..230 "T" - R_ANGLE@230..231 ">" - PARAM_LIST@231..239 - L_PAREN@231..232 "(" - PARAM@232..238 - BIND_PAT@232..234 - NAME@232..234 - IDENT@232..234 "_t" - COLON@234..235 ":" - WHITESPACE@235..236 " " - REFERENCE_TYPE@236..238 - AMP@236..237 "&" - PATH_TYPE@237..238 - PATH@237..238 - PATH_SEGMENT@237..238 - NAME_REF@237..238 - IDENT@237..238 "T" - R_PAREN@238..239 ")" - WHITESPACE@239..240 "\n" - WHERE_CLAUSE@240..287 - WHERE_KW@240..245 "where" - WHITESPACE@245..250 "\n " - WHERE_PRED@250..287 - FOR_KW@250..253 "for" - TYPE_PARAM_LIST@253..257 - L_ANGLE@253..254 "<" - LIFETIME_PARAM@254..256 - LIFETIME@254..256 "\'a" - R_ANGLE@256..257 ">" - WHITESPACE@257..258 " " - PATH_TYPE@258..277 - PATH@258..277 - PATH@258..272 - PATH_SEGMENT@258..272 - L_ANGLE@258..259 "<" - REFERENCE_TYPE@259..264 - AMP@259..260 "&" - LIFETIME@260..262 "\'a" - WHITESPACE@262..263 " " - PATH_TYPE@263..264 - PATH@263..264 - PATH_SEGMENT@263..264 - NAME_REF@263..264 - IDENT@263..264 "T" - WHITESPACE@264..265 " " - AS_KW@265..267 "as" - WHITESPACE@267..268 " " - PATH_TYPE@268..271 - PATH@268..271 - PATH_SEGMENT@268..271 - NAME_REF@268..271 - IDENT@268..271 "Baz" - R_ANGLE@271..272 ">" - COLON2@272..274 "::" - PATH_SEGMENT@274..277 - NAME_REF@274..277 - IDENT@274..277 "Foo" - COLON@277..278 ":" - WHITESPACE@278..279 " " - TYPE_BOUND_LIST@279..287 - TYPE_BOUND@279..287 - PATH_TYPE@279..287 - PATH@279..287 - PATH_SEGMENT@279..287 - NAME_REF@279..287 - IDENT@279..287 "Iterator" - WHITESPACE@287..288 "\n" - BLOCK_EXPR@288..291 - L_CURLY@288..289 "{" - WHITESPACE@289..290 " " - R_CURLY@290..291 "}" - WHITESPACE@291..292 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs index 2d47596be..423bc105b 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs @@ -2,19 +2,3 @@ fn for_trait() where for<'a> F: Fn(&'a str) { } -fn for_ref() -where - for<'a> &'a F: Debug -{ } -fn for_parens() -where - for<'a> (&'a F): Fn(&'a str) -{ } -fn for_slice() -where - for<'a> [&'a F]: Eq -{ } -fn for_qpath(_t: &T) -where - for<'a> <&'a T as Baz>::Foo: Iterator -{ } diff --git a/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast new file mode 100644 index 000000000..503585103 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast @@ -0,0 +1,392 @@ +SOURCE_FILE@0..374 + FN_DEF@0..55 + FN_KW@0..2 "fn" + WHITESPACE@2..3 " " + NAME@3..12 + IDENT@3..12 "for_trait" + TYPE_PARAM_LIST@12..15 + L_ANGLE@12..13 "<" + TYPE_PARAM@13..14 + NAME@13..14 + IDENT@13..14 "F" + R_ANGLE@14..15 ">" + PARAM_LIST@15..17 + L_PAREN@15..16 "(" + R_PAREN@16..17 ")" + WHITESPACE@17..18 "\n" + WHERE_CLAUSE@18..51 + WHERE_KW@18..23 "where" + WHITESPACE@23..28 "\n " + WHERE_PRED@28..50 + FOR_KW@28..31 "for" + TYPE_PARAM_LIST@31..35 + L_ANGLE@31..32 "<" + LIFETIME_PARAM@32..34 + LIFETIME@32..34 "\'a" + R_ANGLE@34..35 ">" + WHITESPACE@35..36 " " + PATH_TYPE@36..37 + PATH@36..37 + PATH_SEGMENT@36..37 + NAME_REF@36..37 + IDENT@36..37 "F" + COLON@37..38 ":" + WHITESPACE@38..39 " " + TYPE_BOUND_LIST@39..50 + TYPE_BOUND@39..50 + PATH_TYPE@39..50 + PATH@39..50 + PATH_SEGMENT@39..50 + NAME_REF@39..41 + IDENT@39..41 "Fn" + PARAM_LIST@41..50 + L_PAREN@41..42 "(" + PARAM@42..49 + REFERENCE_TYPE@42..49 + AMP@42..43 "&" + LIFETIME@43..45 "\'a" + WHITESPACE@45..46 " " + PATH_TYPE@46..49 + PATH@46..49 + PATH_SEGMENT@46..49 + NAME_REF@46..49 + IDENT@46..49 "str" + R_PAREN@49..50 ")" + COMMA@50..51 "," + WHITESPACE@51..52 "\n" + BLOCK_EXPR@52..55 + L_CURLY@52..53 "{" + WHITESPACE@53..54 "\n" + R_CURLY@54..55 "}" + WHITESPACE@55..56 "\n" + FN_DEF@56..107 + FN_KW@56..58 "fn" + WHITESPACE@58..59 " " + NAME@59..66 + IDENT@59..66 "for_ref" + TYPE_PARAM_LIST@66..69 + L_ANGLE@66..67 "<" + TYPE_PARAM@67..68 + NAME@67..68 + IDENT@67..68 "F" + R_ANGLE@68..69 ">" + PARAM_LIST@69..71 + L_PAREN@69..70 "(" + R_PAREN@70..71 ")" + WHITESPACE@71..72 "\n" + WHERE_CLAUSE@72..103 + WHERE_KW@72..77 "where" + WHITESPACE@77..82 "\n " + WHERE_PRED@82..102 + FOR_KW@82..85 "for" + TYPE_PARAM_LIST@85..89 + L_ANGLE@85..86 "<" + LIFETIME_PARAM@86..88 + LIFETIME@86..88 "\'a" + R_ANGLE@88..89 ">" + WHITESPACE@89..90 " " + REFERENCE_TYPE@90..95 + AMP@90..91 "&" + LIFETIME@91..93 "\'a" + WHITESPACE@93..94 " " + PATH_TYPE@94..95 + PATH@94..95 + PATH_SEGMENT@94..95 + NAME_REF@94..95 + IDENT@94..95 "F" + COLON@95..96 ":" + WHITESPACE@96..97 " " + TYPE_BOUND_LIST@97..102 + TYPE_BOUND@97..102 + PATH_TYPE@97..102 + PATH@97..102 + PATH_SEGMENT@97..102 + NAME_REF@97..102 + IDENT@97..102 "Debug" + COMMA@102..103 "," + WHITESPACE@103..104 "\n" + BLOCK_EXPR@104..107 + L_CURLY@104..105 "{" + WHITESPACE@105..106 "\n" + R_CURLY@106..107 "}" + WHITESPACE@107..108 "\n" + FN_DEF@108..170 + FN_KW@108..110 "fn" + WHITESPACE@110..111 " " + NAME@111..121 + IDENT@111..121 "for_parens" + TYPE_PARAM_LIST@121..124 + L_ANGLE@121..122 "<" + TYPE_PARAM@122..123 + NAME@122..123 + IDENT@122..123 "F" + R_ANGLE@123..124 ">" + PARAM_LIST@124..126 + L_PAREN@124..125 "(" + R_PAREN@125..126 ")" + WHITESPACE@126..127 "\n" + WHERE_CLAUSE@127..166 + WHERE_KW@127..132 "where" + WHITESPACE@132..137 "\n " + WHERE_PRED@137..165 + FOR_KW@137..140 "for" + TYPE_PARAM_LIST@140..144 + L_ANGLE@140..141 "<" + LIFETIME_PARAM@141..143 + LIFETIME@141..143 "\'a" + R_ANGLE@143..144 ">" + WHITESPACE@144..145 " " + PAREN_TYPE@145..152 + L_PAREN@145..146 "(" + REFERENCE_TYPE@146..151 + AMP@146..147 "&" + LIFETIME@147..149 "\'a" + WHITESPACE@149..150 " " + PATH_TYPE@150..151 + PATH@150..151 + PATH_SEGMENT@150..151 + NAME_REF@150..151 + IDENT@150..151 "F" + R_PAREN@151..152 ")" + COLON@152..153 ":" + WHITESPACE@153..154 " " + TYPE_BOUND_LIST@154..165 + TYPE_BOUND@154..165 + PATH_TYPE@154..165 + PATH@154..165 + PATH_SEGMENT@154..165 + NAME_REF@154..156 + IDENT@154..156 "Fn" + PARAM_LIST@156..165 + L_PAREN@156..157 "(" + PARAM@157..164 + REFERENCE_TYPE@157..164 + AMP@157..158 "&" + LIFETIME@158..160 "\'a" + WHITESPACE@160..161 " " + PATH_TYPE@161..164 + PATH@161..164 + PATH_SEGMENT@161..164 + NAME_REF@161..164 + IDENT@161..164 "str" + R_PAREN@164..165 ")" + COMMA@165..166 "," + WHITESPACE@166..167 "\n" + BLOCK_EXPR@167..170 + L_CURLY@167..168 "{" + WHITESPACE@168..169 "\n" + R_CURLY@169..170 "}" + WHITESPACE@170..171 "\n" + FN_DEF@171..223 + FN_KW@171..173 "fn" + WHITESPACE@173..174 " " + NAME@174..183 + IDENT@174..183 "for_slice" + TYPE_PARAM_LIST@183..186 + L_ANGLE@183..184 "<" + TYPE_PARAM@184..185 + NAME@184..185 + IDENT@184..185 "F" + R_ANGLE@185..186 ">" + PARAM_LIST@186..188 + L_PAREN@186..187 "(" + R_PAREN@187..188 ")" + WHITESPACE@188..189 "\n" + WHERE_CLAUSE@189..219 + WHERE_KW@189..194 "where" + WHITESPACE@194..199 "\n " + WHERE_PRED@199..218 + FOR_KW@199..202 "for" + TYPE_PARAM_LIST@202..206 + L_ANGLE@202..203 "<" + LIFETIME_PARAM@203..205 + LIFETIME@203..205 "\'a" + R_ANGLE@205..206 ">" + WHITESPACE@206..207 " " + SLICE_TYPE@207..214 + L_BRACK@207..208 "[" + REFERENCE_TYPE@208..213 + AMP@208..209 "&" + LIFETIME@209..211 "\'a" + WHITESPACE@211..212 " " + PATH_TYPE@212..213 + PATH@212..213 + PATH_SEGMENT@212..213 + NAME_REF@212..213 + IDENT@212..213 "F" + R_BRACK@213..214 "]" + COLON@214..215 ":" + WHITESPACE@215..216 " " + TYPE_BOUND_LIST@216..218 + TYPE_BOUND@216..218 + PATH_TYPE@216..218 + PATH@216..218 + PATH_SEGMENT@216..218 + NAME_REF@216..218 + IDENT@216..218 "Eq" + COMMA@218..219 "," + WHITESPACE@219..220 "\n" + BLOCK_EXPR@220..223 + L_CURLY@220..221 "{" + WHITESPACE@221..222 "\n" + R_CURLY@222..223 "}" + WHITESPACE@223..224 "\n" + FN_DEF@224..300 + FN_KW@224..226 "fn" + WHITESPACE@226..227 " " + NAME@227..236 + IDENT@227..236 "for_qpath" + TYPE_PARAM_LIST@236..239 + L_ANGLE@236..237 "<" + TYPE_PARAM@237..238 + NAME@237..238 + IDENT@237..238 "T" + R_ANGLE@238..239 ">" + PARAM_LIST@239..247 + L_PAREN@239..240 "(" + PARAM@240..246 + BIND_PAT@240..242 + NAME@240..242 + IDENT@240..242 "_t" + COLON@242..243 ":" + WHITESPACE@243..244 " " + REFERENCE_TYPE@244..246 + AMP@244..245 "&" + PATH_TYPE@245..246 + PATH@245..246 + PATH_SEGMENT@245..246 + NAME_REF@245..246 + IDENT@245..246 "T" + R_PAREN@246..247 ")" + WHITESPACE@247..248 "\n" + WHERE_CLAUSE@248..296 + WHERE_KW@248..253 "where" + WHITESPACE@253..258 "\n " + WHERE_PRED@258..295 + FOR_KW@258..261 "for" + TYPE_PARAM_LIST@261..265 + L_ANGLE@261..262 "<" + LIFETIME_PARAM@262..264 + LIFETIME@262..264 "\'a" + R_ANGLE@264..265 ">" + WHITESPACE@265..266 " " + PATH_TYPE@266..285 + PATH@266..285 + PATH@266..280 + PATH_SEGMENT@266..280 + L_ANGLE@266..267 "<" + REFERENCE_TYPE@267..272 + AMP@267..268 "&" + LIFETIME@268..270 "\'a" + WHITESPACE@270..271 " " + PATH_TYPE@271..272 + PATH@271..272 + PATH_SEGMENT@271..272 + NAME_REF@271..272 + IDENT@271..272 "T" + WHITESPACE@272..273 " " + AS_KW@273..275 "as" + WHITESPACE@275..276 " " + PATH_TYPE@276..279 + PATH@276..279 + PATH_SEGMENT@276..279 + NAME_REF@276..279 + IDENT@276..279 "Baz" + R_ANGLE@279..280 ">" + COLON2@280..282 "::" + PATH_SEGMENT@282..285 + NAME_REF@282..285 + IDENT@282..285 "Foo" + COLON@285..286 ":" + WHITESPACE@286..287 " " + TYPE_BOUND_LIST@287..295 + TYPE_BOUND@287..295 + PATH_TYPE@287..295 + PATH@287..295 + PATH_SEGMENT@287..295 + NAME_REF@287..295 + IDENT@287..295 "Iterator" + COMMA@295..296 "," + WHITESPACE@296..297 "\n" + BLOCK_EXPR@297..300 + L_CURLY@297..298 "{" + WHITESPACE@298..299 "\n" + R_CURLY@299..300 "}" + WHITESPACE@300..301 "\n" + FN_DEF@301..373 + FN_KW@301..303 "fn" + WHITESPACE@303..304 " " + NAME@304..314 + IDENT@304..314 "for_for_fn" + TYPE_PARAM_LIST@314..317 + L_ANGLE@314..315 "<" + TYPE_PARAM@315..316 + NAME@315..316 + IDENT@315..316 "T" + R_ANGLE@316..317 ">" + PARAM_LIST@317..319 + L_PAREN@317..318 "(" + R_PAREN@318..319 ")" + WHITESPACE@319..320 "\n" + WHERE_CLAUSE@320..369 + WHERE_KW@320..325 "where" + WHITESPACE@325..330 "\n " + WHERE_PRED@330..368 + FOR_KW@330..333 "for" + TYPE_PARAM_LIST@333..337 + L_ANGLE@333..334 "<" + LIFETIME_PARAM@334..336 + LIFETIME@334..336 "\'a" + R_ANGLE@336..337 ">" + WHITESPACE@337..338 " " + FOR_TYPE@338..362 + FOR_KW@338..341 "for" + TYPE_PARAM_LIST@341..345 + L_ANGLE@341..342 "<" + LIFETIME_PARAM@342..344 + LIFETIME@342..344 "\'b" + R_ANGLE@344..345 ">" + WHITESPACE@345..346 " " + FN_POINTER_TYPE@346..362 + FN_KW@346..348 "fn" + PARAM_LIST@348..362 + L_PAREN@348..349 "(" + PARAM@349..354 + REFERENCE_TYPE@349..354 + AMP@349..350 "&" + LIFETIME@350..352 "\'a" + WHITESPACE@352..353 " " + PATH_TYPE@353..354 + PATH@353..354 + PATH_SEGMENT@353..354 + NAME_REF@353..354 + IDENT@353..354 "T" + COMMA@354..355 "," + WHITESPACE@355..356 " " + PARAM@356..361 + REFERENCE_TYPE@356..361 + AMP@356..357 "&" + LIFETIME@357..359 "\'b" + WHITESPACE@359..360 " " + PATH_TYPE@360..361 + PATH@360..361 + PATH_SEGMENT@360..361 + NAME_REF@360..361 + IDENT@360..361 "T" + R_PAREN@361..362 ")" + COLON@362..363 ":" + WHITESPACE@363..364 " " + TYPE_BOUND_LIST@364..368 + TYPE_BOUND@364..368 + PATH_TYPE@364..368 + PATH@364..368 + PATH_SEGMENT@364..368 + NAME_REF@364..368 + IDENT@364..368 "Copy" + COMMA@368..369 "," + WHITESPACE@369..370 "\n" + BLOCK_EXPR@370..373 + L_CURLY@370..371 "{" + WHITESPACE@371..372 "\n" + R_CURLY@372..373 "}" + WHITESPACE@373..374 "\n" diff --git a/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs new file mode 100644 index 000000000..9058c4619 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs @@ -0,0 +1,30 @@ +fn for_trait() +where + for<'a> F: Fn(&'a str), +{ +} +fn for_ref() +where + for<'a> &'a F: Debug, +{ +} +fn for_parens() +where + for<'a> (&'a F): Fn(&'a str), +{ +} +fn for_slice() +where + for<'a> [&'a F]: Eq, +{ +} +fn for_qpath(_t: &T) +where + for<'a> <&'a T as Baz>::Foo: Iterator, +{ +} +fn for_for_fn() +where + for<'a> for<'b> fn(&'a T, &'b T): Copy, +{ +} -- cgit v1.2.3 From 8622e4cc1b79f5d23b8a2c6610d749f5b987ea7e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Jun 2020 18:15:03 +0100 Subject: Add example of old trait object syntax --- crates/ra_parser/src/grammar/types.rs | 1 + .../test_data/parser/inline/ok/0081_for_type.rast | 38 +++++++++++++++++++++- .../test_data/parser/inline/ok/0081_for_type.rs | 1 + 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index 63dd3774f..9e8e3bd97 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs @@ -217,6 +217,7 @@ pub(super) fn for_binder(p: &mut Parser) { // test for_type // type A = for<'a> fn() -> (); // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); +// type Obj = for<'a> PartialEq<&'a i32>; pub(super) fn for_type(p: &mut Parser) { assert!(p.at(T![for])); let m = p.start(); diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast index 26a80017a..b26ac2d36 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast @@ -1,4 +1,4 @@ -SOURCE_FILE@0..82 +SOURCE_FILE@0..121 TYPE_ALIAS_DEF@0..28 TYPE_KW@0..4 "type" WHITESPACE@4..5 " " @@ -74,3 +74,39 @@ SOURCE_FILE@0..82 R_PAREN@79..80 ")" SEMICOLON@80..81 ";" WHITESPACE@81..82 "\n" + TYPE_ALIAS_DEF@82..120 + TYPE_KW@82..86 "type" + WHITESPACE@86..87 " " + NAME@87..90 + IDENT@87..90 "Obj" + WHITESPACE@90..91 " " + EQ@91..92 "=" + WHITESPACE@92..93 " " + FOR_TYPE@93..119 + FOR_KW@93..96 "for" + TYPE_PARAM_LIST@96..100 + L_ANGLE@96..97 "<" + LIFETIME_PARAM@97..99 + LIFETIME@97..99 "\'a" + R_ANGLE@99..100 ">" + WHITESPACE@100..101 " " + PATH_TYPE@101..119 + PATH@101..119 + PATH_SEGMENT@101..119 + NAME_REF@101..110 + IDENT@101..110 "PartialEq" + TYPE_ARG_LIST@110..119 + L_ANGLE@110..111 "<" + TYPE_ARG@111..118 + REFERENCE_TYPE@111..118 + AMP@111..112 "&" + LIFETIME@112..114 "\'a" + WHITESPACE@114..115 " " + PATH_TYPE@115..118 + PATH@115..118 + PATH_SEGMENT@115..118 + NAME_REF@115..118 + IDENT@115..118 "i32" + R_ANGLE@118..119 ">" + SEMICOLON@119..120 ";" + WHITESPACE@120..121 "\n" diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs index 457e8744f..8ac7b9e10 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs @@ -1,2 +1,3 @@ type A = for<'a> fn() -> (); type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); +type Obj = for<'a> PartialEq<&'a i32>; -- cgit v1.2.3 From c514060600ac6787da4bcfa0bbd8b74bb4cf7d18 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 12 Jun 2020 01:26:58 +0300 Subject: Apply codegen with idiomatic lifetimes --- crates/ra_syntax/src/ast/generated/nodes.rs | 274 +++++++++++++-------------- crates/ra_syntax/src/ast/generated/tokens.rs | 8 +- 2 files changed, 141 insertions(+), 141 deletions(-) (limited to 'crates') diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 40081ebb1..58141da11 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs @@ -4851,687 +4851,687 @@ impl AstNode for FieldDefList { } } impl std::fmt::Display for NominalDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for GenericParam { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for GenericArg { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeRef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ModuleItem { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for AssocItem { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ExternItem { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Expr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Pat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordInnerPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for AttrInput { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Stmt { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for FieldDefList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for SourceFile { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for FnDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RetType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for StructDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for UnionDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordFieldDefList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordFieldDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TupleFieldDefList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TupleFieldDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for EnumDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for EnumVariantList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for EnumVariant { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TraitDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Module { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ItemList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ConstDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for StaticDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeAliasDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ImplDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ParenType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TupleType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for NeverType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PathType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PointerType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ArrayType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for SliceType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ReferenceType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PlaceholderType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for FnPointerType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ForType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ImplTraitType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for DynTraitType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TupleExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ArrayExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ParenExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PathExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for LambdaExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for IfExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for LoopExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for EffectExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ForExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for WhileExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ContinueExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for BreakExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Label { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for BlockExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ReturnExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for CallExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MethodCallExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for IndexExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for FieldExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for AwaitExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TryExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for CastExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RefExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PrefixExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for BoxExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RangeExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for BinExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Literal { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MatchExpr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MatchArmList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MatchArm { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MatchGuard { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordLit { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordFieldList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordField { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for OrPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ParenPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RefPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for BoxPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for BindPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PlaceholderPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for DotDotPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PathPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for SlicePat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RangePat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for LiteralPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MacroPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordFieldPatList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for RecordFieldPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TupleStructPat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TuplePat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Visibility { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Name { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for NameRef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MacroCall { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Attr { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TokenTree { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeParamList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeParam { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ConstParam { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for LifetimeParam { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeBound { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeBoundList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for WherePred { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for WhereClause { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Abi { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ExprStmt { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for LetStmt { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Condition { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ParamList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for SelfParam { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Param { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for UseItem { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for UseTree { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Alias { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for UseTreeList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ExternCrateItem { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ArgList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for Path { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for PathSegment { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeArgList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for TypeArg { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for AssocTypeArg { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for LifetimeArg { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ConstArg { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MacroItems { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MacroStmts { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ExternItemList { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for ExternBlock { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MetaItem { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } impl std::fmt::Display for MacroDef { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } diff --git a/crates/ra_syntax/src/ast/generated/tokens.rs b/crates/ra_syntax/src/ast/generated/tokens.rs index f91befaac..abadd0b61 100644 --- a/crates/ra_syntax/src/ast/generated/tokens.rs +++ b/crates/ra_syntax/src/ast/generated/tokens.rs @@ -11,7 +11,7 @@ pub struct Whitespace { pub(crate) syntax: SyntaxToken, } impl std::fmt::Display for Whitespace { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.syntax, f) } } @@ -32,7 +32,7 @@ pub struct Comment { pub(crate) syntax: SyntaxToken, } impl std::fmt::Display for Comment { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.syntax, f) } } @@ -53,7 +53,7 @@ pub struct String { pub(crate) syntax: SyntaxToken, } impl std::fmt::Display for String { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.syntax, f) } } @@ -74,7 +74,7 @@ pub struct RawString { pub(crate) syntax: SyntaxToken, } impl std::fmt::Display for RawString { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.syntax, f) } } -- cgit v1.2.3 From 4fefc7d06c8da093e783852c5f0d3aea31e2c939 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 12 Jun 2020 02:06:28 +0300 Subject: Simplify --- crates/ra_syntax/src/ast/tokens.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 56378385a..2e72d4927 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs @@ -84,7 +84,7 @@ impl Whitespace { } pub struct QuoteOffsets { - pub quotes: [TextRange; 2], + pub quotes: (TextRange, TextRange), pub contents: TextRange, } @@ -103,7 +103,7 @@ impl QuoteOffsets { let end = TextSize::of(literal); let res = QuoteOffsets { - quotes: [TextRange::new(start, left_quote), TextRange::new(right_quote, end)], + quotes: (TextRange::new(start, left_quote), TextRange::new(right_quote, end)), contents: TextRange::new(left_quote, right_quote), }; Some(res) @@ -116,17 +116,17 @@ pub trait HasQuotes: AstToken { let offsets = QuoteOffsets::new(text)?; let o = self.syntax().text_range().start(); let offsets = QuoteOffsets { - quotes: [offsets.quotes[0] + o, offsets.quotes[1] + o], + quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o), contents: offsets.contents + o, }; Some(offsets) } fn open_quote_text_range(&self) -> Option { - self.quote_offsets().map(|it| it.quotes[0]) + self.quote_offsets().map(|it| it.quotes.0) } fn close_quote_text_range(&self) -> Option { - self.quote_offsets().map(|it| it.quotes[1]) + self.quote_offsets().map(|it| it.quotes.1) } fn text_range_between_quotes(&self) -> Option { -- cgit v1.2.3 From 59f195a3231d9cbc3baac2c6ca8e6400311deeb7 Mon Sep 17 00:00:00 2001 From: OptimalStrategy Date: Fri, 12 Jun 2020 01:11:54 -0400 Subject: Fix invalid shorthand initialization diagnostic for tuple structs --- crates/ra_ide/src/diagnostics.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index f44feaf69..9cd36ad35 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -187,7 +187,12 @@ fn check_struct_shorthand_initialization( if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { let field_name = name_ref.syntax().text().to_string(); let field_expr = expr.syntax().text().to_string(); - if field_name == field_expr { + let field_name_is_tup_index = name_ref + .syntax() + .first_token() + .map(|token| token.kind().is_literal()) + .unwrap_or(false); + if field_name == field_expr && !field_name_is_tup_index { let mut edit_builder = TextEditBuilder::default(); edit_builder.delete(record_field.syntax().text_range()); edit_builder.insert(record_field.syntax().text_range().start(), field_name); @@ -719,6 +724,18 @@ mod tests { "#, check_struct_shorthand_initialization, ); + check_not_applicable( + r#" + struct A(usize); + + fn main() { + A { + 0: 0 + } + } + "#, + check_struct_shorthand_initialization, + ); check_apply( r#" -- cgit v1.2.3 From 0231e4ac77dacf6ca30f6b68c6081415f2da54ba Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 12 Jun 2020 13:01:20 +0200 Subject: find_path: return shorter paths for external items If a containing module is already in scope, there's no need to use the full path to the item. --- crates/ra_hir_def/src/find_path.rs | 59 ++++++++++++++++++++++++++++++++----- crates/ra_hir_def/src/import_map.rs | 39 ++++++++++++++++-------- 2 files changed, 77 insertions(+), 21 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index a7f59e028..06701a830 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -159,10 +159,16 @@ fn find_path_inner( let crate_graph = db.crate_graph(); let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { let import_map = db.import_map(dep.crate_id); - import_map.path_of(item).map(|modpath| { - let mut modpath = modpath.clone(); - modpath.segments.insert(0, dep.as_name()); - modpath + import_map.import_info_for(item).and_then(|info| { + // Determine best path for containing module and append last segment from `info`. + let mut path = find_path_inner( + db, + ItemInNs::Types(ModuleDefId::ModuleId(info.container)), + from, + best_path_len - 1, + )?; + path.segments.push(info.path.segments.last().unwrap().clone()); + Some(path) }) }); @@ -299,8 +305,8 @@ mod tests { /// `code` needs to contain a cursor marker; checks that `find_path` for the /// item the `path` refers to returns that same path when called from the /// module the cursor is in. - fn check_found_path(code: &str, path: &str) { - let (db, pos) = TestDB::with_position(code); + fn check_found_path(ra_fixture: &str, path: &str) { + let (db, pos) = TestDB::with_position(ra_fixture); let module = db.module_for_file(pos.file_id); let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); let ast_path = parsed_path_file @@ -420,7 +426,6 @@ mod tests { #[test] fn different_crate_renamed() { - // Even if a local path exists, if the item is defined externally, prefer an external path. let code = r#" //- /main.rs crate:main deps:std extern crate std as std_renamed; @@ -428,7 +433,45 @@ mod tests { //- /std.rs crate:std pub struct S; "#; - check_found_path(code, "std::S"); + check_found_path(code, "std_renamed::S"); + } + + #[test] + fn partially_imported() { + // Tests that short paths are used even for external items, when parts of the path are + // already in scope. + check_found_path( + r#" + //- /main.rs crate:main deps:ra_syntax + + use ra_syntax::ast; + <|> + + //- /lib.rs crate:ra_syntax + pub mod ast { + pub enum ModuleItem { + A, B, C, + } + } + "#, + "ast::ModuleItem", + ); + + check_found_path( + r#" + //- /main.rs crate:main deps:ra_syntax + + <|> + + //- /lib.rs crate:ra_syntax + pub mod ast { + pub enum ModuleItem { + A, B, C, + } + } + "#, + "ra_syntax::ast::ModuleItem", + ); } #[test] diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 36b4fdd81..68e20d06b 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -17,6 +17,15 @@ use crate::{ type FxIndexMap = IndexMap>; +/// Item import details stored in the `ImportMap`. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ImportInfo { + /// A path that can be used to import the item, relative to the crate's root. + pub path: ModPath, + /// The module containing this item. + pub container: ModuleId, +} + /// A map from publicly exported items to the path needed to import/name them from a downstream /// crate. /// @@ -26,7 +35,7 @@ type FxIndexMap = IndexMap>; /// Note that all paths are relative to the containing crate's root, so the crate name still needs /// to be prepended to the `ModPath` before the path is valid. pub struct ImportMap { - map: FxIndexMap, + map: FxIndexMap, /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the /// values returned by running `fst`. @@ -78,12 +87,12 @@ impl ImportMap { let path = mk_path(); match import_map.entry(item) { Entry::Vacant(entry) => { - entry.insert(path); + entry.insert(ImportInfo { path, container: module }); } Entry::Occupied(mut entry) => { // If the new path is shorter, prefer that one. - if path.len() < entry.get().len() { - *entry.get_mut() = path; + if path.len() < entry.get().path.len() { + *entry.get_mut() = ImportInfo { path, container: module }; } else { continue; } @@ -119,7 +128,7 @@ impl ImportMap { let start = last_batch_start; last_batch_start = idx + 1; - let key = fst_path(&importables[start].1); + let key = fst_path(&importables[start].1.path); builder.insert(key, start as u64).unwrap(); } @@ -132,6 +141,10 @@ impl ImportMap { /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { + Some(&self.map.get(&item)?.path) + } + + pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { self.map.get(&item) } } @@ -150,13 +163,13 @@ impl fmt::Debug for ImportMap { let mut importable_paths: Vec<_> = self .map .iter() - .map(|(item, modpath)| { + .map(|(item, info)| { let ns = match item { ItemInNs::Types(_) => "t", ItemInNs::Values(_) => "v", ItemInNs::Macros(_) => "m", }; - format!("- {} ({})", modpath, ns) + format!("- {} ({})", info.path, ns) }) .collect(); @@ -171,9 +184,9 @@ fn fst_path(path: &ModPath) -> String { s } -fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Ordering { - let lhs_str = fst_path(lhs); - let rhs_str = fst_path(rhs); +fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { + let lhs_str = fst_path(&lhs.path); + let rhs_str = fst_path(&rhs.path); lhs_str.cmp(&rhs_str) } @@ -243,7 +256,7 @@ pub fn search_dependencies<'a>( let importables = &import_map.importables[indexed_value.value as usize..]; // Path shared by the importable items in this group. - let path = &import_map.map[&importables[0]]; + let path = &import_map.map[&importables[0]].path; if query.anchor_end { // Last segment must match query. @@ -256,14 +269,14 @@ pub fn search_dependencies<'a>( // Add the items from this `ModPath` group. Those are all subsequent items in // `importables` whose paths match `path`. let iter = importables.iter().copied().take_while(|item| { - let item_path = &import_map.map[item]; + let item_path = &import_map.map[item].path; fst_path(item_path) == fst_path(path) }); if query.case_sensitive { // FIXME: This does not do a subsequence match. res.extend(iter.filter(|item| { - let item_path = &import_map.map[item]; + let item_path = &import_map.map[item].path; item_path.to_string().contains(&query.query) })); } else { -- cgit v1.2.3 From 591b5ec2c15a83fd10da7049b5f3ea1a783d52ed Mon Sep 17 00:00:00 2001 From: OptimalStrategy <17456182+OptimalStrategy@users.noreply.github.com> Date: Fri, 12 Jun 2020 10:16:19 -0400 Subject: simplify determining whether the field is a tuple field --- crates/ra_ide/src/diagnostics.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 9cd36ad35..e1bfd72f9 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -187,11 +187,7 @@ fn check_struct_shorthand_initialization( if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { let field_name = name_ref.syntax().text().to_string(); let field_expr = expr.syntax().text().to_string(); - let field_name_is_tup_index = name_ref - .syntax() - .first_token() - .map(|token| token.kind().is_literal()) - .unwrap_or(false); + let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); if field_name == field_expr && !field_name_is_tup_index { let mut edit_builder = TextEditBuilder::default(); edit_builder.delete(record_field.syntax().text_range()); -- cgit v1.2.3