aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-08-12 15:26:43 +0100
committerIgor Aleksanov <[email protected]>2020-08-12 15:26:43 +0100
commitb50bb800a5b5e01b6cb4de10330fd5b61d6cd0db (patch)
treeadb19b05996e8a2829f5a6eb0ed7017404aaf7da /crates
parent13f736d4a13bdf5af2cdd6a4832a41470431a70b (diff)
parent6be5ab02008b442c85c201968b97f24f13c4692e (diff)
Merge branch 'master' into add-disable-diagnostics
Diffstat (limited to 'crates')
-rw-r--r--crates/expect/src/lib.rs2
-rw-r--r--crates/flycheck/src/lib.rs10
-rw-r--r--crates/ra_assists/src/ast_transform.rs2
-rw-r--r--crates/ra_assists/src/handlers/add_custom_impl.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_turbo_fish.rs2
-rw-r--r--crates/ra_assists/src/handlers/apply_demorgan.rs2
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/ra_assists/src/handlers/generate_impl.rs5
-rw-r--r--crates/ra_assists/src/handlers/generate_new.rs9
-rw-r--r--crates/ra_assists/src/lib.rs25
-rw-r--r--crates/ra_assists/src/tests.rs2
-rw-r--r--crates/ra_assists/src/utils.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs22
-rw-r--r--crates/ra_hir/src/diagnostics.rs4
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/semantics.rs138
-rw-r--r--crates/ra_hir/src/source_analyzer.rs7
-rw-r--r--crates/ra_hir_def/src/adt.rs42
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs25
-rw-r--r--crates/ra_hir_expand/src/hygiene.rs2
-rw-r--r--crates/ra_hir_expand/src/lib.rs3
-rw-r--r--crates/ra_hir_ty/Cargo.toml6
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs128
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs14
-rw-r--r--crates/ra_hir_ty/src/diagnostics/match_check.rs8
-rw-r--r--crates/ra_hir_ty/src/diagnostics/unsafe_check.rs38
-rw-r--r--crates/ra_hir_ty/src/infer.rs11
-rw-r--r--crates/ra_hir_ty/src/lower.rs5
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs38
-rw-r--r--crates/ra_ide/src/completion/complete_snippet.rs8
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs10
-rw-r--r--crates/ra_ide/src/completion/presentation.rs31
-rw-r--r--crates/ra_ide/src/diagnostics.rs189
-rw-r--r--crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs171
-rw-r--r--crates/ra_ide/src/display/short_label.rs12
-rw-r--r--crates/ra_ide/src/goto_definition.rs36
-rw-r--r--crates/ra_ide/src/hover.rs88
-rw-r--r--crates/ra_ide/src/lib.rs10
-rw-r--r--crates/ra_ide/src/references.rs4
-rw-r--r--crates/ra_ide/src/ssr.rs4
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs148
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs5
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs68
-rw-r--r--crates/ra_ide/test_data/highlight_extern_crate.html40
-rw-r--r--crates/ra_ide/test_data/highlight_unsafe.html51
-rw-r--r--crates/ra_ide/test_data/highlighting.html4
-rw-r--r--crates/ra_ide_db/src/defs.rs90
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs2
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs2
-rw-r--r--crates/ra_parser/src/grammar.rs2
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs3
-rw-r--r--crates/ra_parser/src/grammar/items.rs112
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs4
-rw-r--r--crates/ra_parser/src/parser.rs16
-rw-r--r--crates/ra_proc_macro/src/process.rs2
-rw-r--r--crates/ra_prof/src/memory_usage.rs2
-rw-r--r--crates/ra_ssr/src/resolving.rs31
-rw-r--r--crates/ra_ssr/src/tests.rs64
-rw-r--r--crates/ra_syntax/src/ast/traits.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/err/0043_default_const.rast40
-rw-r--r--crates/ra_syntax/test_data/parser/err/0043_default_const.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rast (renamed from crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rs (renamed from crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rs (renamed from crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast58
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast13
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast21
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast17
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast13
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast15
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast35
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast55
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast22
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast11
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast40
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast44
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rs (renamed from crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs)2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast24
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast56
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0066_default_const.rast44
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0066_default_const.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast218
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs16
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast218
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs16
-rw-r--r--crates/ra_text_edit/src/lib.rs13
-rw-r--r--crates/ra_tt/src/lib.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs2
-rw-r--r--crates/rust-analyzer/src/handlers.rs13
-rw-r--r--crates/rust-analyzer/src/main_loop.rs27
-rw-r--r--crates/rust-analyzer/src/to_proto.rs11
-rw-r--r--crates/stdx/src/lib.rs65
126 files changed, 1851 insertions, 1229 deletions
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs
index 21a458d47..bd83895f7 100644
--- a/crates/expect/src/lib.rs
+++ b/crates/expect/src/lib.rs
@@ -74,7 +74,7 @@ impl fmt::Display for Position {
74impl Expect { 74impl Expect {
75 pub fn assert_eq(&self, actual: &str) { 75 pub fn assert_eq(&self, actual: &str) {
76 let trimmed = self.trimmed(); 76 let trimmed = self.trimmed();
77 if &trimmed == actual { 77 if trimmed == actual {
78 return; 78 return;
79 } 79 }
80 Runtime::fail_expect(self, &trimmed, actual); 80 Runtime::fail_expect(self, &trimmed, actual);
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 7c38f5ef9..31e14246d 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -1,4 +1,4 @@
1//! cargo_check provides the functionality needed to run `cargo check` or 1//! Flycheck provides the functionality needed to run `cargo check` or
2//! another compatible command (f.x. clippy) in a background thread and provide 2//! another compatible command (f.x. clippy) in a background thread and provide
3//! LSP diagnostics based on the output of the command. 3//! LSP diagnostics based on the output of the command.
4 4
@@ -147,6 +147,12 @@ impl FlycheckActor {
147 // avoid busy-waiting. 147 // avoid busy-waiting.
148 let cargo_handle = self.cargo_handle.take().unwrap(); 148 let cargo_handle = self.cargo_handle.take().unwrap();
149 let res = cargo_handle.join(); 149 let res = cargo_handle.join();
150 if res.is_err() {
151 log::error!(
152 "Flycheck failed to run the following command: {:?}",
153 self.check_command()
154 )
155 }
150 self.send(Message::Progress(Progress::DidFinish(res))); 156 self.send(Message::Progress(Progress::DidFinish(res)));
151 } 157 }
152 Event::CheckEvent(Some(message)) => match message { 158 Event::CheckEvent(Some(message)) => match message {
@@ -253,7 +259,7 @@ impl CargoHandle {
253 return Err(io::Error::new( 259 return Err(io::Error::new(
254 io::ErrorKind::Other, 260 io::ErrorKind::Other,
255 format!( 261 format!(
256 "Cargo watcher failed,the command produced no valid metadata (exit code: {:?})", 262 "Cargo watcher failed, the command produced no valid metadata (exit code: {:?})",
257 exit_status 263 exit_status
258 ), 264 ),
259 )); 265 ));
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index 15ec75c95..07c978378 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -51,7 +51,7 @@ impl<'a> SubstituteTypeParams<'a> {
51 // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky 51 // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
52 .skip(1) 52 .skip(1)
53 // The actual list of trait type parameters may be longer than the one 53 // The actual list of trait type parameters may be longer than the one
54 // used in the `impl` block due to trailing default type parametrs. 54 // used in the `impl` block due to trailing default type parameters.
55 // For that case we extend the `substs` with an empty iterator so we 55 // For that case we extend the `substs` with an empty iterator so we
56 // can still hit those trailing values and check if they actually have 56 // can still hit those trailing values and check if they actually have
57 // a default type. If they do, go for that type from `hir` to `ast` so 57 // a default type. If they do, go for that type from `hir` to `ast` so
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs
index b67438b6b..ebdf00e67 100644
--- a/crates/ra_assists/src/handlers/add_custom_impl.rs
+++ b/crates/ra_assists/src/handlers/add_custom_impl.rs
@@ -1,10 +1,10 @@
1use itertools::Itertools;
1use ra_syntax::{ 2use ra_syntax::{
2 ast::{self, AstNode}, 3 ast::{self, AstNode},
3 Direction, SmolStr, 4 Direction, SmolStr,
4 SyntaxKind::{IDENT, WHITESPACE}, 5 SyntaxKind::{IDENT, WHITESPACE},
5 TextRange, TextSize, 6 TextRange, TextSize,
6}; 7};
7use stdx::SepBy;
8 8
9use crate::{ 9use crate::{
10 assist_context::{AssistContext, Assists}, 10 assist_context::{AssistContext, Assists},
@@ -61,9 +61,9 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
61 .filter(|t| t != trait_token.text()) 61 .filter(|t| t != trait_token.text())
62 .collect::<Vec<SmolStr>>(); 62 .collect::<Vec<SmolStr>>();
63 let has_more_derives = !new_attr_input.is_empty(); 63 let has_more_derives = !new_attr_input.is_empty();
64 let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
65 64
66 if has_more_derives { 65 if has_more_derives {
66 let new_attr_input = format!("({})", new_attr_input.iter().format(", "));
67 builder.replace(input.syntax().text_range(), new_attr_input); 67 builder.replace(input.syntax().text_range(), new_attr_input);
68 } else { 68 } else {
69 let attr_range = attr.syntax().text_range(); 69 let attr_range = attr.syntax().text_range();
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs
index 0c565e89a..537322a72 100644
--- a/crates/ra_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs
@@ -41,7 +41,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
41 let name_ref = ast::NameRef::cast(ident.parent())?; 41 let name_ref = ast::NameRef::cast(ident.parent())?;
42 let def = match classify_name_ref(&ctx.sema, &name_ref)? { 42 let def = match classify_name_ref(&ctx.sema, &name_ref)? {
43 NameRefClass::Definition(def) => def, 43 NameRefClass::Definition(def) => def,
44 NameRefClass::FieldShorthand { .. } => return None, 44 NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
45 }; 45 };
46 let fun = match def { 46 let fun = match def {
47 Definition::ModuleDef(hir::ModuleDef::Function(it)) => it, 47 Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs
index de701f8b8..3ac4aed7d 100644
--- a/crates/ra_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ra_assists/src/handlers/apply_demorgan.rs
@@ -4,7 +4,7 @@ use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKin
4 4
5// Assist: apply_demorgan 5// Assist: apply_demorgan
6// 6//
7// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). 7// Apply https://en.wikipedia.org/wiki/De_Morgan%27s_laws[De Morgan's law].
8// This transforms expressions of the form `!l || !r` into `!(l && r)`. 8// This transforms expressions of the form `!l || !r` into `!(l && r)`.
9// This also works with `&&`. This assist can only be applied with the cursor 9// This also works with `&&`. This assist can only be applied with the cursor
10// on either `||` or `&&`, with both operands being a negation of some kind. 10// on either `||` or `&&`, with both operands being a negation of some kind.
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 1aefa79cc..a19dbf33f 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -121,7 +121,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
121 Some(cap) => match current_visibility { 121 Some(cap) => match current_visibility {
122 Some(current_visibility) => builder.replace_snippet( 122 Some(current_visibility) => builder.replace_snippet(
123 cap, 123 cap,
124 dbg!(current_visibility.syntax()).text_range(), 124 current_visibility.syntax().text_range(),
125 format!("$0{}", missing_visibility), 125 format!("$0{}", missing_visibility),
126 ), 126 ),
127 None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), 127 None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
diff --git a/crates/ra_assists/src/handlers/generate_impl.rs b/crates/ra_assists/src/handlers/generate_impl.rs
index d9b87c9c0..7162dc184 100644
--- a/crates/ra_assists/src/handlers/generate_impl.rs
+++ b/crates/ra_assists/src/handlers/generate_impl.rs
@@ -1,5 +1,6 @@
1use itertools::Itertools;
1use ra_syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner}; 2use ra_syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner};
2use stdx::{format_to, SepBy}; 3use stdx::format_to;
3 4
4use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
5 6
@@ -50,7 +51,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
50 .filter_map(|it| it.name()) 51 .filter_map(|it| it.name())
51 .map(|it| it.text().clone()); 52 .map(|it| it.text().clone());
52 53
53 let generic_params = lifetime_params.chain(type_params).sep_by(", "); 54 let generic_params = lifetime_params.chain(type_params).format(", ");
54 format_to!(buf, "<{}>", generic_params) 55 format_to!(buf, "<{}>", generic_params)
55 } 56 }
56 match ctx.config.snippet_cap { 57 match ctx.config.snippet_cap {
diff --git a/crates/ra_assists/src/handlers/generate_new.rs b/crates/ra_assists/src/handlers/generate_new.rs
index b84aa24b6..32dfed274 100644
--- a/crates/ra_assists/src/handlers/generate_new.rs
+++ b/crates/ra_assists/src/handlers/generate_new.rs
@@ -1,9 +1,10 @@
1use hir::Adt; 1use hir::Adt;
2use itertools::Itertools;
2use ra_syntax::{ 3use ra_syntax::{
3 ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, 4 ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner},
4 T, 5 T,
5}; 6};
6use stdx::{format_to, SepBy}; 7use stdx::format_to;
7 8
8use crate::{AssistContext, AssistId, AssistKind, Assists}; 9use crate::{AssistContext, AssistId, AssistKind, Assists};
9 10
@@ -52,8 +53,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
52 let params = field_list 53 let params = field_list
53 .fields() 54 .fields()
54 .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))) 55 .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax())))
55 .sep_by(", "); 56 .format(", ");
56 let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); 57 let fields = field_list.fields().filter_map(|f| f.name()).format(", ");
57 58
58 format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); 59 format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
59 60
@@ -102,7 +103,7 @@ fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String {
102 .map(|it| it.text().clone()); 103 .map(|it| it.text().clone());
103 let type_params = 104 let type_params =
104 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); 105 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
105 format_to!(buf, "<{}>", lifetime_params.chain(type_params).sep_by(", ")) 106 format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", "))
106 } 107 }
107 108
108 format_to!(buf, " {{\n{}\n}}\n", code); 109 format_to!(buf, " {{\n{}\n}}\n", code);
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 507646cc8..890996a68 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -66,13 +66,13 @@ pub struct GroupLabel(pub String);
66 66
67#[derive(Debug, Clone)] 67#[derive(Debug, Clone)]
68pub struct Assist { 68pub struct Assist {
69 pub id: AssistId, 69 id: AssistId,
70 /// Short description of the assist, as shown in the UI. 70 /// Short description of the assist, as shown in the UI.
71 pub label: String, 71 label: String,
72 pub group: Option<GroupLabel>, 72 group: Option<GroupLabel>,
73 /// Target ranges are used to sort assists: the smaller the target range, 73 /// Target ranges are used to sort assists: the smaller the target range,
74 /// the more specific assist is, and so it should be sorted first. 74 /// the more specific assist is, and so it should be sorted first.
75 pub target: TextRange, 75 target: TextRange,
76} 76}
77 77
78#[derive(Debug, Clone)] 78#[derive(Debug, Clone)]
@@ -120,10 +120,25 @@ impl Assist {
120 group: Option<GroupLabel>, 120 group: Option<GroupLabel>,
121 target: TextRange, 121 target: TextRange,
122 ) -> Assist { 122 ) -> Assist {
123 // FIXME: make fields private, so that this invariant can't be broken
124 assert!(label.starts_with(|c: char| c.is_uppercase())); 123 assert!(label.starts_with(|c: char| c.is_uppercase()));
125 Assist { id, label, group, target } 124 Assist { id, label, group, target }
126 } 125 }
126
127 pub fn id(&self) -> AssistId {
128 self.id
129 }
130
131 pub fn label(&self) -> String {
132 self.label.clone()
133 }
134
135 pub fn group(&self) -> Option<GroupLabel> {
136 self.group.clone()
137 }
138
139 pub fn target(&self) -> TextRange {
140 self.target
141 }
127} 142}
128 143
129mod handlers { 144mod handlers {
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs
index 18fcb9049..e73836422 100644
--- a/crates/ra_assists/src/tests.rs
+++ b/crates/ra_assists/src/tests.rs
@@ -20,7 +20,7 @@ pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_
20 20
21// FIXME: instead of having a separate function here, maybe use 21// FIXME: instead of having a separate function here, maybe use
22// `extract_ranges` and mark the target as `<target> </target>` in the 22// `extract_ranges` and mark the target as `<target> </target>` in the
23// fixuture? 23// fixture?
24pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) { 24pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) {
25 check(assist, ra_fixture, ExpectedResult::Target(target)); 25 check(assist, ra_fixture, ExpectedResult::Target(target));
26} 26}
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 54d5678d1..0de6fdf3f 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -257,7 +257,7 @@ pub use prelude::*;
257 .find(|dep| &dep.name.to_string() == std_crate)? 257 .find(|dep| &dep.name.to_string() == std_crate)?
258 .krate; 258 .krate;
259 259
260 let mut module = std_crate.root_module(db)?; 260 let mut module = std_crate.root_module(db);
261 for segment in path { 261 for segment in path {
262 module = module.children(db).find_map(|child| { 262 module = module.children(db).find_map(|child| {
263 let name = child.name(db)?; 263 let name = child.name(db)?;
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 27cdabea0..0007d7fa8 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -4,6 +4,7 @@ use std::{iter, sync::Arc};
4use arrayvec::ArrayVec; 4use arrayvec::ArrayVec;
5use either::Either; 5use either::Either;
6use hir_def::{ 6use hir_def::{
7 adt::ReprKind,
7 adt::StructKind, 8 adt::StructKind,
8 adt::VariantData, 9 adt::VariantData,
9 builtin_type::BuiltinType, 10 builtin_type::BuiltinType,
@@ -83,9 +84,9 @@ impl Crate {
83 .collect() 84 .collect()
84 } 85 }
85 86
86 pub fn root_module(self, db: &dyn HirDatabase) -> Option<Module> { 87 pub fn root_module(self, db: &dyn HirDatabase) -> Module {
87 let module_id = db.crate_def_map(self.id).root; 88 let module_id = db.crate_def_map(self.id).root;
88 Some(Module::new(self, module_id)) 89 Module::new(self, module_id)
89 } 90 }
90 91
91 pub fn root_file(self, db: &dyn HirDatabase) -> FileId { 92 pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
@@ -431,6 +432,10 @@ impl Struct {
431 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) 432 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id)
432 } 433 }
433 434
435 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
436 db.struct_data(self.id).repr.clone()
437 }
438
434 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { 439 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
435 db.struct_data(self.id).variant_data.clone() 440 db.struct_data(self.id).variant_data.clone()
436 } 441 }
@@ -1253,6 +1258,19 @@ impl Type {
1253 ) 1258 )
1254 } 1259 }
1255 1260
1261 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1262 let adt_id = match self.ty.value {
1263 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_id), .. }) => adt_id,
1264 _ => return false,
1265 };
1266
1267 let adt = adt_id.into();
1268 match adt {
1269 Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
1270 _ => false,
1271 }
1272 }
1273
1256 pub fn is_raw_ptr(&self) -> bool { 1274 pub fn is_raw_ptr(&self) -> bool {
1257 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) 1275 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }))
1258 } 1276 }
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 266b513dc..363164b9b 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,8 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2pub use hir_def::diagnostics::UnresolvedModule; 2pub use hir_def::diagnostics::UnresolvedModule;
3pub use hir_expand::diagnostics::{ 3pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder};
4 AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder,
5};
6pub use hir_ty::diagnostics::{ 4pub use hir_ty::diagnostics::{
7 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, 5 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
8}; 6};
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 31f3241c9..34b02c536 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -49,7 +49,7 @@ pub use hir_def::{
49 docs::Documentation, 49 docs::Documentation,
50 nameres::ModuleSource, 50 nameres::ModuleSource,
51 path::{ModPath, Path, PathKind}, 51 path::{ModPath, Path, PathKind},
52 type_ref::Mutability, 52 type_ref::{Mutability, TypeRef},
53}; 53};
54pub use hir_expand::{ 54pub use hir_expand::{
55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, 55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc,
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 307b336f2..36b688ccb 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -8,7 +8,7 @@ use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, FunctionId, TraitId, VariantId, 9 AsMacroCall, FunctionId, TraitId, VariantId,
10}; 10};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; 11use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
13use itertools::Itertools; 13use itertools::Itertools;
14use ra_db::{FileId, FileRange}; 14use ra_db::{FileId, FileRange};
@@ -24,8 +24,9 @@ use crate::{
24 diagnostics::Diagnostic, 24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, 27 AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
28 ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, 28 Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef,
29 VariantDef,
29}; 30};
30use resolver::TypeNs; 31use resolver::TypeNs;
31 32
@@ -109,13 +110,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
109 self.imp.parse(file_id) 110 self.imp.parse(file_id)
110 } 111 }
111 112
112 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
113 let file_id = d.source().file_id;
114 let root = self.db.parse_or_expand(file_id).unwrap();
115 self.imp.cache(root, file_id);
116 d.ast(self.db.upcast())
117 }
118
119 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 113 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
120 self.imp.expand(macro_call) 114 self.imp.expand(macro_call)
121 } 115 }
@@ -145,8 +139,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
145 self.imp.original_range(node) 139 self.imp.original_range(node)
146 } 140 }
147 141
148 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { 142 pub fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
149 self.imp.diagnostics_range(diagnostics) 143 self.imp.diagnostics_display_range(diagnostics)
150 } 144 }
151 145
152 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { 146 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
@@ -228,6 +222,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
228 self.imp.resolve_path(path) 222 self.imp.resolve_path(path)
229 } 223 }
230 224
225 pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
226 self.imp.resolve_extern_crate(extern_crate)
227 }
228
231 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { 229 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
232 self.imp.resolve_variant(record_lit).map(VariantDef::from) 230 self.imp.resolve_variant(record_lit).map(VariantDef::from)
233 } 231 }
@@ -275,6 +273,18 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
275 pub fn assert_contains_node(&self, node: &SyntaxNode) { 273 pub fn assert_contains_node(&self, node: &SyntaxNode) {
276 self.imp.assert_contains_node(node) 274 self.imp.assert_contains_node(node)
277 } 275 }
276
277 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
278 self.imp.is_unsafe_method_call(method_call_expr)
279 }
280
281 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
282 self.imp.is_unsafe_ref_expr(ref_expr)
283 }
284
285 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
286 self.imp.is_unsafe_ident_pat(ident_pat)
287 }
278} 288}
279 289
280impl<'db> SemanticsImpl<'db> { 290impl<'db> SemanticsImpl<'db> {
@@ -372,10 +382,11 @@ impl<'db> SemanticsImpl<'db> {
372 original_range(self.db, node.as_ref()) 382 original_range(self.db, node.as_ref())
373 } 383 }
374 384
375 fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { 385 fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
376 let src = diagnostics.source(); 386 let src = diagnostics.display_source();
377 let root = self.db.parse_or_expand(src.file_id).unwrap(); 387 let root = self.db.parse_or_expand(src.file_id).unwrap();
378 let node = src.value.to_node(&root); 388 let node = src.value.to_node(&root);
389 self.cache(root, src.file_id);
379 original_range(self.db, src.with_value(&node)) 390 original_range(self.db, src.with_value(&node))
380 } 391 }
381 392
@@ -443,6 +454,17 @@ impl<'db> SemanticsImpl<'db> {
443 self.analyze(path.syntax()).resolve_path(self.db, path) 454 self.analyze(path.syntax()).resolve_path(self.db, path)
444 } 455 }
445 456
457 fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
458 let krate = self.scope(extern_crate.syntax()).krate()?;
459 krate.dependencies(self.db).into_iter().find_map(|dep| {
460 if dep.name == extern_crate.name_ref()?.as_name() {
461 Some(dep.krate)
462 } else {
463 None
464 }
465 })
466 }
467
446 fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { 468 fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
447 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) 469 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
448 } 470 }
@@ -559,6 +581,90 @@ impl<'db> SemanticsImpl<'db> {
559 }); 581 });
560 InFile::new(file_id, node) 582 InFile::new(file_id, node)
561 } 583 }
584
585 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
586 method_call_expr
587 .expr()
588 .and_then(|expr| {
589 let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
590 field_expr
591 } else {
592 return None;
593 };
594 let ty = self.type_of_expr(&field_expr.expr()?)?;
595 if !ty.is_packed(self.db) {
596 return None;
597 }
598
599 let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
600 let is_unsafe = func.has_self_param(self.db)
601 && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
602 Some(is_unsafe)
603 })
604 .unwrap_or(false)
605 }
606
607 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
608 ref_expr
609 .expr()
610 .and_then(|expr| {
611 let field_expr = match expr {
612 ast::Expr::FieldExpr(field_expr) => field_expr,
613 _ => return None,
614 };
615 let expr = field_expr.expr()?;
616 self.type_of_expr(&expr)
617 })
618 // Binding a reference to a packed type is possibly unsafe.
619 .map(|ty| ty.is_packed(self.db))
620 .unwrap_or(false)
621
622 // FIXME This needs layout computation to be correct. It will highlight
623 // more than it should with the current implementation.
624 }
625
626 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
627 if !ident_pat.ref_token().is_some() {
628 return false;
629 }
630
631 ident_pat
632 .syntax()
633 .parent()
634 .and_then(|parent| {
635 // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
636 // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
637 // so this tries to lookup the `IdentPat` anywhere along that structure to the
638 // `RecordPat` so we can get the containing type.
639 let record_pat = ast::RecordPatField::cast(parent.clone())
640 .and_then(|record_pat| record_pat.syntax().parent())
641 .or_else(|| Some(parent.clone()))
642 .and_then(|parent| {
643 ast::RecordPatFieldList::cast(parent)?
644 .syntax()
645 .parent()
646 .and_then(ast::RecordPat::cast)
647 });
648
649 // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
650 // this is initialized from a `FieldExpr`.
651 if let Some(record_pat) = record_pat {
652 self.type_of_pat(&ast::Pat::RecordPat(record_pat))
653 } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
654 let field_expr = match let_stmt.initializer()? {
655 ast::Expr::FieldExpr(field_expr) => field_expr,
656 _ => return None,
657 };
658
659 self.type_of_expr(&field_expr.expr()?)
660 } else {
661 None
662 }
663 })
664 // Binding a reference to a packed type is possibly unsafe.
665 .map(|ty| ty.is_packed(self.db))
666 .unwrap_or(false)
667 }
562} 668}
563 669
564pub trait ToDef: AstNode + Clone { 670pub trait ToDef: AstNode + Clone {
@@ -612,6 +718,10 @@ impl<'a> SemanticsScope<'a> {
612 Some(Module { id: self.resolver.module()? }) 718 Some(Module { id: self.resolver.module()? })
613 } 719 }
614 720
721 pub fn krate(&self) -> Option<Crate> {
722 Some(Crate { id: self.resolver.krate()? })
723 }
724
615 /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type 725 /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
616 // FIXME: rename to visible_traits to not repeat scope? 726 // FIXME: rename to visible_traits to not repeat scope?
617 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { 727 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index d0cb62ef0..d3d62debf 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -265,8 +265,7 @@ impl SourceAnalyzer {
265 } 265 }
266 266
267 // This must be a normal source file rather than macro file. 267 // This must be a normal source file rather than macro file.
268 let hir_path = 268 let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
269 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
270 269
271 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we 270 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
272 // trying to resolve foo::bar. 271 // trying to resolve foo::bar.
@@ -451,7 +450,7 @@ fn adjust(
451pub(crate) fn resolve_hir_path( 450pub(crate) fn resolve_hir_path(
452 db: &dyn HirDatabase, 451 db: &dyn HirDatabase,
453 resolver: &Resolver, 452 resolver: &Resolver,
454 path: &crate::Path, 453 path: &Path,
455) -> Option<PathResolution> { 454) -> Option<PathResolution> {
456 let types = 455 let types =
457 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { 456 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
@@ -512,7 +511,7 @@ pub(crate) fn resolve_hir_path(
512pub(crate) fn resolve_hir_path_qualifier( 511pub(crate) fn resolve_hir_path_qualifier(
513 db: &dyn HirDatabase, 512 db: &dyn HirDatabase,
514 resolver: &Resolver, 513 resolver: &Resolver,
515 path: &crate::Path, 514 path: &Path,
516) -> Option<PathResolution> { 515) -> Option<PathResolution> {
517 let items = resolver 516 let items = resolver
518 .resolve_module_path_in_items(db.upcast(), path.mod_path()) 517 .resolve_module_path_in_items(db.upcast(), path.mod_path())
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 6cb56a1cd..35c3a9140 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -9,11 +9,12 @@ use hir_expand::{
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; 11use ra_syntax::ast::{self, NameOwner, VisibilityOwner};
12use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
12 13
13use crate::{ 14use crate::{
14 body::{CfgExpander, LowerCtx}, 15 body::{CfgExpander, LowerCtx},
15 db::DefDatabase, 16 db::DefDatabase,
16 item_tree::{Field, Fields, ItemTree}, 17 item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem},
17 src::HasChildSource, 18 src::HasChildSource,
18 src::HasSource, 19 src::HasSource,
19 trace::Trace, 20 trace::Trace,
@@ -29,6 +30,7 @@ use ra_cfg::CfgOptions;
29pub struct StructData { 30pub struct StructData {
30 pub name: Name, 31 pub name: Name,
31 pub variant_data: Arc<VariantData>, 32 pub variant_data: Arc<VariantData>,
33 pub repr: Option<ReprKind>,
32} 34}
33 35
34#[derive(Debug, Clone, PartialEq, Eq)] 36#[derive(Debug, Clone, PartialEq, Eq)]
@@ -58,26 +60,58 @@ pub struct FieldData {
58 pub visibility: RawVisibility, 60 pub visibility: RawVisibility,
59} 61}
60 62
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum ReprKind {
65 Packed,
66 Other,
67}
68
69fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option<ReprKind> {
70 item_tree.attrs(of).by_key("repr").tt_values().find_map(parse_repr_tt)
71}
72
73fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
74 match tt.delimiter {
75 Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
76 _ => return None,
77 }
78
79 let mut it = tt.token_trees.iter();
80 match it.next()? {
81 TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed),
82 _ => Some(ReprKind::Other),
83 }
84}
85
61impl StructData { 86impl StructData {
62 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { 87 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
63 let loc = id.lookup(db); 88 let loc = id.lookup(db);
64 let item_tree = db.item_tree(loc.id.file_id); 89 let item_tree = db.item_tree(loc.id.file_id);
90 let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into());
65 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 91 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
66 92
67 let strukt = &item_tree[loc.id.value]; 93 let strukt = &item_tree[loc.id.value];
68 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); 94 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);
69 95 Arc::new(StructData {
70 Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) 96 name: strukt.name.clone(),
97 variant_data: Arc::new(variant_data),
98 repr,
99 })
71 } 100 }
72 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { 101 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
73 let loc = id.lookup(db); 102 let loc = id.lookup(db);
74 let item_tree = db.item_tree(loc.id.file_id); 103 let item_tree = db.item_tree(loc.id.file_id);
104 let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into());
75 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 105 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
76 106
77 let union = &item_tree[loc.id.value]; 107 let union = &item_tree[loc.id.value];
78 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); 108 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);
79 109
80 Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) 110 Arc::new(StructData {
111 name: union.name.clone(),
112 variant_data: Arc::new(variant_data),
113 repr,
114 })
81 } 115 }
82} 116}
83 117
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
index 481b13a87..5b7f05bf4 100644
--- a/crates/ra_hir_def/src/diagnostics.rs
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -21,7 +21,7 @@ impl Diagnostic for UnresolvedModule {
21 fn message(&self) -> String { 21 fn message(&self) -> String {
22 "unresolved module".to_string() 22 "unresolved module".to_string()
23 } 23 }
24 fn source(&self) -> InFile<SyntaxNodePtr> { 24 fn display_source(&self) -> InFile<SyntaxNodePtr> {
25 InFile::new(self.file, self.decl.clone().into()) 25 InFile::new(self.file, self.decl.clone().into())
26 } 26 }
27 fn as_any(&self) -> &(dyn Any + Send + 'static) { 27 fn as_any(&self) -> &(dyn Any + Send + 'static) {
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 507132a13..a618934c9 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -16,36 +16,21 @@
16 16
17use std::{any::Any, fmt}; 17use std::{any::Any, fmt};
18 18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr}; 19use ra_syntax::SyntaxNodePtr;
20 20
21use crate::{db::AstDatabase, InFile}; 21use crate::InFile;
22 22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { 23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn name(&self) -> &'static str; 24 fn name(&self) -> &'static str;
25 fn message(&self) -> String; 25 fn message(&self) -> String;
26 fn source(&self) -> InFile<SyntaxNodePtr>; 26 /// Used in highlighting and related purposes
27 fn display_source(&self) -> InFile<SyntaxNodePtr>;
27 fn as_any(&self) -> &(dyn Any + Send + 'static); 28 fn as_any(&self) -> &(dyn Any + Send + 'static);
28 fn is_experimental(&self) -> bool { 29 fn is_experimental(&self) -> bool {
29 false 30 false
30 } 31 }
31} 32}
32 33
33pub trait AstDiagnostic {
34 type AST;
35 fn ast(&self, db: &dyn AstDatabase) -> Self::AST;
36}
37
38impl dyn Diagnostic {
39 pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode {
40 let node = db.parse_or_expand(self.source().file_id).unwrap();
41 self.source().value.to_node(&node)
42 }
43
44 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
45 self.as_any().downcast_ref()
46 }
47}
48
49pub struct DiagnosticSink<'a> { 34pub struct DiagnosticSink<'a> {
50 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, 35 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
51 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>, 36 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
@@ -90,7 +75,7 @@ impl<'a> DiagnosticSinkBuilder<'a> {
90 } 75 }
91 76
92 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self { 77 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
93 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { 78 let cb = move |diag: &dyn Diagnostic| match diag.as_any().downcast_ref::<D>() {
94 Some(d) => { 79 Some(d) => {
95 cb(d); 80 cb(d);
96 Ok(()) 81 Ok(())
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs
index 6b482a60c..aefe47bd3 100644
--- a/crates/ra_hir_expand/src/hygiene.rs
+++ b/crates/ra_hir_expand/src/hygiene.rs
@@ -17,7 +17,7 @@ pub struct Hygiene {
17 // This is what `$crate` expands to 17 // This is what `$crate` expands to
18 def_crate: Option<CrateId>, 18 def_crate: Option<CrateId>,
19 19
20 // Indiciate this is a local inner macro 20 // Indicate this is a local inner macro
21 local_inner: bool, 21 local_inner: bool,
22} 22}
23 23
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 2e8d63691..8bb735fc6 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -44,7 +44,8 @@ mod test_db;
44/// containing the call plus the offset of the macro call in the file. Note that 44/// containing the call plus the offset of the macro call in the file. Note that
45/// this is a recursive definition! However, the size_of of `HirFileId` is 45/// this is a recursive definition! However, the size_of of `HirFileId` is
46/// finite (because everything bottoms out at the real `FileId`) and small 46/// finite (because everything bottoms out at the real `FileId`) and small
47/// (`MacroCallId` uses the location interner). 47/// (`MacroCallId` uses the location interning. You can check details here:
48/// https://en.wikipedia.org/wiki/String_interning).
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49pub struct HirFileId(HirFileIdRepr); 50pub struct HirFileId(HirFileIdRepr);
50 51
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 623ce261a..83397d579 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -28,9 +28,9 @@ test_utils = { path = "../test_utils" }
28 28
29scoped-tls = "1" 29scoped-tls = "1"
30 30
31chalk-solve = { version = "0.19.0" } 31chalk-solve = { version = "0.21.0" }
32chalk-ir = { version = "0.19.0" } 32chalk-ir = { version = "0.21.0" }
33chalk-recursive = { version = "0.19.0" } 33chalk-recursive = { version = "0.21.0" }
34 34
35[dev-dependencies] 35[dev-dependencies]
36expect = { path = "../expect" } 36expect = { path = "../expect" }
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 56acd3bbf..45e31033e 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -6,10 +6,10 @@ mod unsafe_check;
6use std::any::Any; 6use std::any::Any;
7 7
8use hir_def::DefWithBodyId; 8use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 9use hir_expand::diagnostics::{Diagnostic, DiagnosticSink};
10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; 10use hir_expand::{name::Name, HirFileId, InFile};
11use ra_prof::profile; 11use ra_prof::profile;
12use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 12use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
13use stdx::format_to; 13use stdx::format_to;
14 14
15use crate::db::HirDatabase; 15use crate::db::HirDatabase;
@@ -41,7 +41,7 @@ impl Diagnostic for NoSuchField {
41 "no such field".to_string() 41 "no such field".to_string()
42 } 42 }
43 43
44 fn source(&self) -> InFile<SyntaxNodePtr> { 44 fn display_source(&self) -> InFile<SyntaxNodePtr> {
45 InFile::new(self.file, self.field.clone().into()) 45 InFile::new(self.file, self.field.clone().into())
46 } 46 }
47 47
@@ -50,20 +50,11 @@ impl Diagnostic for NoSuchField {
50 } 50 }
51} 51}
52 52
53impl AstDiagnostic for NoSuchField {
54 type AST = ast::RecordExprField;
55
56 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
57 let root = db.parse_or_expand(self.source().file_id).unwrap();
58 let node = self.source().value.to_node(&root);
59 ast::RecordExprField::cast(node).unwrap()
60 }
61}
62
63#[derive(Debug)] 53#[derive(Debug)]
64pub struct MissingFields { 54pub struct MissingFields {
65 pub file: HirFileId, 55 pub file: HirFileId,
66 pub field_list: AstPtr<ast::RecordExprFieldList>, 56 pub field_list_parent: AstPtr<ast::RecordExpr>,
57 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
67 pub missed_fields: Vec<Name>, 58 pub missed_fields: Vec<Name>,
68} 59}
69 60
@@ -78,28 +69,28 @@ impl Diagnostic for MissingFields {
78 } 69 }
79 buf 70 buf
80 } 71 }
81 fn source(&self) -> InFile<SyntaxNodePtr> { 72
82 InFile { file_id: self.file, value: self.field_list.clone().into() } 73 fn display_source(&self) -> InFile<SyntaxNodePtr> {
74 InFile {
75 file_id: self.file,
76 value: self
77 .field_list_parent_path
78 .clone()
79 .map(SyntaxNodePtr::from)
80 .unwrap_or_else(|| self.field_list_parent.clone().into()),
81 }
83 } 82 }
83
84 fn as_any(&self) -> &(dyn Any + Send + 'static) { 84 fn as_any(&self) -> &(dyn Any + Send + 'static) {
85 self 85 self
86 } 86 }
87} 87}
88 88
89impl AstDiagnostic for MissingFields {
90 type AST = ast::RecordExprFieldList;
91
92 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
93 let root = db.parse_or_expand(self.source().file_id).unwrap();
94 let node = self.source().value.to_node(&root);
95 ast::RecordExprFieldList::cast(node).unwrap()
96 }
97}
98
99#[derive(Debug)] 89#[derive(Debug)]
100pub struct MissingPatFields { 90pub struct MissingPatFields {
101 pub file: HirFileId, 91 pub file: HirFileId,
102 pub field_list: AstPtr<ast::RecordPatFieldList>, 92 pub field_list_parent: AstPtr<ast::RecordPat>,
93 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
103 pub missed_fields: Vec<Name>, 94 pub missed_fields: Vec<Name>,
104} 95}
105 96
@@ -114,8 +105,15 @@ impl Diagnostic for MissingPatFields {
114 } 105 }
115 buf 106 buf
116 } 107 }
117 fn source(&self) -> InFile<SyntaxNodePtr> { 108 fn display_source(&self) -> InFile<SyntaxNodePtr> {
118 InFile { file_id: self.file, value: self.field_list.clone().into() } 109 InFile {
110 file_id: self.file,
111 value: self
112 .field_list_parent_path
113 .clone()
114 .map(SyntaxNodePtr::from)
115 .unwrap_or_else(|| self.field_list_parent.clone().into()),
116 }
119 } 117 }
120 fn as_any(&self) -> &(dyn Any + Send + 'static) { 118 fn as_any(&self) -> &(dyn Any + Send + 'static) {
121 self 119 self
@@ -136,7 +134,7 @@ impl Diagnostic for MissingMatchArms {
136 fn message(&self) -> String { 134 fn message(&self) -> String {
137 String::from("Missing match arm") 135 String::from("Missing match arm")
138 } 136 }
139 fn source(&self) -> InFile<SyntaxNodePtr> { 137 fn display_source(&self) -> InFile<SyntaxNodePtr> {
140 InFile { file_id: self.file, value: self.match_expr.clone().into() } 138 InFile { file_id: self.file, value: self.match_expr.clone().into() }
141 } 139 }
142 fn as_any(&self) -> &(dyn Any + Send + 'static) { 140 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -157,7 +155,7 @@ impl Diagnostic for MissingOkInTailExpr {
157 fn message(&self) -> String { 155 fn message(&self) -> String {
158 "wrap return expression in Ok".to_string() 156 "wrap return expression in Ok".to_string()
159 } 157 }
160 fn source(&self) -> InFile<SyntaxNodePtr> { 158 fn display_source(&self) -> InFile<SyntaxNodePtr> {
161 InFile { file_id: self.file, value: self.expr.clone().into() } 159 InFile { file_id: self.file, value: self.expr.clone().into() }
162 } 160 }
163 fn as_any(&self) -> &(dyn Any + Send + 'static) { 161 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -165,16 +163,6 @@ impl Diagnostic for MissingOkInTailExpr {
165 } 163 }
166} 164}
167 165
168impl AstDiagnostic for MissingOkInTailExpr {
169 type AST = ast::Expr;
170
171 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
172 let root = db.parse_or_expand(self.file).unwrap();
173 let node = self.source().value.to_node(&root);
174 ast::Expr::cast(node).unwrap()
175 }
176}
177
178#[derive(Debug)] 166#[derive(Debug)]
179pub struct BreakOutsideOfLoop { 167pub struct BreakOutsideOfLoop {
180 pub file: HirFileId, 168 pub file: HirFileId,
@@ -188,7 +176,7 @@ impl Diagnostic for BreakOutsideOfLoop {
188 fn message(&self) -> String { 176 fn message(&self) -> String {
189 "break outside of loop".to_string() 177 "break outside of loop".to_string()
190 } 178 }
191 fn source(&self) -> InFile<SyntaxNodePtr> { 179 fn display_source(&self) -> InFile<SyntaxNodePtr> {
192 InFile { file_id: self.file, value: self.expr.clone().into() } 180 InFile { file_id: self.file, value: self.expr.clone().into() }
193 } 181 }
194 fn as_any(&self) -> &(dyn Any + Send + 'static) { 182 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -196,16 +184,6 @@ impl Diagnostic for BreakOutsideOfLoop {
196 } 184 }
197} 185}
198 186
199impl AstDiagnostic for BreakOutsideOfLoop {
200 type AST = ast::Expr;
201
202 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
203 let root = db.parse_or_expand(self.file).unwrap();
204 let node = self.source().value.to_node(&root);
205 ast::Expr::cast(node).unwrap()
206 }
207}
208
209#[derive(Debug)] 187#[derive(Debug)]
210pub struct MissingUnsafe { 188pub struct MissingUnsafe {
211 pub file: HirFileId, 189 pub file: HirFileId,
@@ -219,7 +197,7 @@ impl Diagnostic for MissingUnsafe {
219 fn message(&self) -> String { 197 fn message(&self) -> String {
220 format!("This operation is unsafe and requires an unsafe function or block") 198 format!("This operation is unsafe and requires an unsafe function or block")
221 } 199 }
222 fn source(&self) -> InFile<SyntaxNodePtr> { 200 fn display_source(&self) -> InFile<SyntaxNodePtr> {
223 InFile { file_id: self.file, value: self.expr.clone().into() } 201 InFile { file_id: self.file, value: self.expr.clone().into() }
224 } 202 }
225 fn as_any(&self) -> &(dyn Any + Send + 'static) { 203 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -227,16 +205,6 @@ impl Diagnostic for MissingUnsafe {
227 } 205 }
228} 206}
229 207
230impl AstDiagnostic for MissingUnsafe {
231 type AST = ast::Expr;
232
233 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
234 let root = db.parse_or_expand(self.source().file_id).unwrap();
235 let node = self.source().value.to_node(&root);
236 ast::Expr::cast(node).unwrap()
237 }
238}
239
240#[derive(Debug)] 208#[derive(Debug)]
241pub struct MismatchedArgCount { 209pub struct MismatchedArgCount {
242 pub file: HirFileId, 210 pub file: HirFileId,
@@ -253,7 +221,7 @@ impl Diagnostic for MismatchedArgCount {
253 let s = if self.expected == 1 { "" } else { "s" }; 221 let s = if self.expected == 1 { "" } else { "s" };
254 format!("Expected {} argument{}, found {}", self.expected, s, self.found) 222 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
255 } 223 }
256 fn source(&self) -> InFile<SyntaxNodePtr> { 224 fn display_source(&self) -> InFile<SyntaxNodePtr> {
257 InFile { file_id: self.file, value: self.call_expr.clone().into() } 225 InFile { file_id: self.file, value: self.call_expr.clone().into() }
258 } 226 }
259 fn as_any(&self) -> &(dyn Any + Send + 'static) { 227 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -264,19 +232,13 @@ impl Diagnostic for MismatchedArgCount {
264 } 232 }
265} 233}
266 234
267impl AstDiagnostic for MismatchedArgCount {
268 type AST = ast::CallExpr;
269 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
270 let root = db.parse_or_expand(self.source().file_id).unwrap();
271 let node = self.source().value.to_node(&root);
272 ast::CallExpr::cast(node).unwrap()
273 }
274}
275
276#[cfg(test)] 235#[cfg(test)]
277mod tests { 236mod tests {
278 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; 237 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
279 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; 238 use hir_expand::{
239 db::AstDatabase,
240 diagnostics::{Diagnostic, DiagnosticSinkBuilder},
241 };
280 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 242 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
281 use ra_syntax::{TextRange, TextSize}; 243 use ra_syntax::{TextRange, TextSize};
282 use rustc_hash::FxHashMap; 244 use rustc_hash::FxHashMap;
@@ -321,9 +283,11 @@ mod tests {
321 283
322 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); 284 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
323 db.diagnostics(|d| { 285 db.diagnostics(|d| {
324 // FXIME: macros... 286 let src = d.display_source();
325 let file_id = d.source().file_id.original_file(&db); 287 let root = db.parse_or_expand(src.file_id).unwrap();
326 let range = d.syntax_node(&db).text_range(); 288 // FIXME: macros...
289 let file_id = src.file_id.original_file(&db);
290 let range = src.value.to_node(&root).text_range();
327 let message = d.message().to_owned(); 291 let message = d.message().to_owned();
328 actual.entry(file_id).or_default().push((range, message)); 292 actual.entry(file_id).or_default().push((range, message));
329 }); 293 });
@@ -351,8 +315,8 @@ struct S { foo: i32, bar: () }
351impl S { 315impl S {
352 fn new() -> S { 316 fn new() -> S {
353 S { 317 S {
354 //^... Missing structure fields: 318 //^ Missing structure fields:
355 //| - bar 319 //| - bar
356 foo: 92, 320 foo: 92,
357 baz: 62, 321 baz: 62,
358 //^^^^^^^ no such field 322 //^^^^^^^ no such field
@@ -473,8 +437,8 @@ impl Foo {
473struct S { foo: i32, bar: () } 437struct S { foo: i32, bar: () }
474fn baz(s: S) { 438fn baz(s: S) {
475 let S { foo: _ } = s; 439 let S { foo: _ } = s;
476 //^^^^^^^^^^ Missing structure fields: 440 //^ Missing structure fields:
477 // | - bar 441 //| - bar
478} 442}
479"#, 443"#,
480 ); 444 );
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 95bbf2d95..51adcecaf 100644
--- a/crates/ra_hir_ty/src/diagnostics/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -100,8 +100,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
100 100
101 if let Ok(source_ptr) = source_map.expr_syntax(id) { 101 if let Ok(source_ptr) = source_map.expr_syntax(id) {
102 let root = source_ptr.file_syntax(db.upcast()); 102 let root = source_ptr.file_syntax(db.upcast());
103 if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) { 103 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) {
104 if let Some(field_list) = record_lit.record_expr_field_list() { 104 if let Some(_) = record_expr.record_expr_field_list() {
105 let variant_data = variant_data(db.upcast(), variant_def); 105 let variant_data = variant_data(db.upcast(), variant_def);
106 let missed_fields = missed_fields 106 let missed_fields = missed_fields
107 .into_iter() 107 .into_iter()
@@ -109,7 +109,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
109 .collect(); 109 .collect();
110 self.sink.push(MissingFields { 110 self.sink.push(MissingFields {
111 file: source_ptr.file_id, 111 file: source_ptr.file_id,
112 field_list: AstPtr::new(&field_list), 112 field_list_parent: AstPtr::new(&record_expr),
113 field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)),
113 missed_fields, 114 missed_fields,
114 }) 115 })
115 } 116 }
@@ -131,7 +132,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
131 if let Some(expr) = source_ptr.value.as_ref().left() { 132 if let Some(expr) = source_ptr.value.as_ref().left() {
132 let root = source_ptr.file_syntax(db.upcast()); 133 let root = source_ptr.file_syntax(db.upcast());
133 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { 134 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
134 if let Some(field_list) = record_pat.record_pat_field_list() { 135 if let Some(_) = record_pat.record_pat_field_list() {
135 let variant_data = variant_data(db.upcast(), variant_def); 136 let variant_data = variant_data(db.upcast(), variant_def);
136 let missed_fields = missed_fields 137 let missed_fields = missed_fields
137 .into_iter() 138 .into_iter()
@@ -139,7 +140,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
139 .collect(); 140 .collect();
140 self.sink.push(MissingPatFields { 141 self.sink.push(MissingPatFields {
141 file: source_ptr.file_id, 142 file: source_ptr.file_id,
142 field_list: AstPtr::new(&field_list), 143 field_list_parent: AstPtr::new(&record_pat),
144 field_list_parent_path: record_pat
145 .path()
146 .map(|path| AstPtr::new(&path)),
143 missed_fields, 147 missed_fields,
144 }) 148 })
145 } 149 }
diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
index 507edcb7d..deca244db 100644
--- a/crates/ra_hir_ty/src/diagnostics/match_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -1161,15 +1161,15 @@ fn main() {
1161 //^ Missing match arm 1161 //^ Missing match arm
1162 match a { 1162 match a {
1163 Either::A { } => (), 1163 Either::A { } => (),
1164 //^^^ Missing structure fields: 1164 //^^^^^^^^^ Missing structure fields:
1165 // | - foo 1165 // | - foo
1166 Either::B => (), 1166 Either::B => (),
1167 } 1167 }
1168 match a { 1168 match a {
1169 //^ Missing match arm 1169 //^ Missing match arm
1170 Either::A { } => (), 1170 Either::A { } => (),
1171 } //^^^ Missing structure fields: 1171 } //^^^^^^^^^ Missing structure fields:
1172 // | - foo 1172 // | - foo
1173 1173
1174 match a { 1174 match a {
1175 Either::A { foo: true } => (), 1175 Either::A { foo: true } => (),
diff --git a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index 5cc76bdce..61ffbf5d1 100644
--- a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -6,6 +6,7 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 body::Body, 7 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 8 expr::{Expr, ExprId, UnaryOp},
9 resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
9 DefWithBodyId, 10 DefWithBodyId,
10}; 11};
11use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
@@ -70,7 +71,7 @@ pub fn unsafe_expressions(
70) -> Vec<UnsafeExpr> { 71) -> Vec<UnsafeExpr> {
71 let mut unsafe_exprs = vec![]; 72 let mut unsafe_exprs = vec![];
72 let body = db.body(def); 73 let body = db.body(def);
73 walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false); 74 walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false);
74 75
75 unsafe_exprs 76 unsafe_exprs
76} 77}
@@ -79,6 +80,7 @@ fn walk_unsafe(
79 unsafe_exprs: &mut Vec<UnsafeExpr>, 80 unsafe_exprs: &mut Vec<UnsafeExpr>,
80 db: &dyn HirDatabase, 81 db: &dyn HirDatabase,
81 infer: &InferenceResult, 82 infer: &InferenceResult,
83 def: DefWithBodyId,
82 body: &Body, 84 body: &Body,
83 current: ExprId, 85 current: ExprId,
84 inside_unsafe_block: bool, 86 inside_unsafe_block: bool,
@@ -97,6 +99,15 @@ fn walk_unsafe(
97 } 99 }
98 } 100 }
99 } 101 }
102 Expr::Path(path) => {
103 let resolver = resolver_for_expr(db.upcast(), def, current);
104 let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
105 if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
106 if db.static_data(id).mutable {
107 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
108 }
109 }
110 }
100 Expr::MethodCall { .. } => { 111 Expr::MethodCall { .. } => {
101 if infer 112 if infer
102 .method_resolution(current) 113 .method_resolution(current)
@@ -112,13 +123,13 @@ fn walk_unsafe(
112 } 123 }
113 } 124 }
114 Expr::Unsafe { body: child } => { 125 Expr::Unsafe { body: child } => {
115 return walk_unsafe(unsafe_exprs, db, infer, body, *child, true); 126 return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true);
116 } 127 }
117 _ => {} 128 _ => {}
118 } 129 }
119 130
120 expr.walk_child_exprs(|child| { 131 expr.walk_child_exprs(|child| {
121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); 132 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
122 }); 133 });
123} 134}
124 135
@@ -170,4 +181,25 @@ fn main() {
170"#, 181"#,
171 ); 182 );
172 } 183 }
184
185 #[test]
186 fn missing_unsafe_diagnostic_with_static_mut() {
187 check_diagnostics(
188 r#"
189struct Ty {
190 a: u8,
191}
192
193static mut static_mut: Ty = Ty { a: 0 };
194
195fn main() {
196 let x = static_mut.a;
197 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
198 unsafe {
199 let x = static_mut.a;
200 }
201}
202"#,
203 );
204 }
173} 205}
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 28f32a0a4..3d12039a6 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -440,6 +440,12 @@ impl<'a> InferenceContext<'a> {
440 let ty = self.insert_type_vars(ty.subst(&substs)); 440 let ty = self.insert_type_vars(ty.subst(&substs));
441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) 441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
442 } 442 }
443 TypeNs::AdtId(AdtId::UnionId(u)) => {
444 let substs = Ty::substs_from_path(&ctx, path, u.into(), true);
445 let ty = self.db.ty(u.into());
446 let ty = self.insert_type_vars(ty.subst(&substs));
447 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
448 }
443 TypeNs::EnumVariantId(var) => { 449 TypeNs::EnumVariantId(var) => {
444 let substs = Ty::substs_from_path(&ctx, path, var.into(), true); 450 let substs = Ty::substs_from_path(&ctx, path, var.into(), true);
445 let ty = self.db.ty(var.parent.into()); 451 let ty = self.db.ty(var.parent.into());
@@ -490,10 +496,7 @@ impl<'a> InferenceContext<'a> {
490 // FIXME potentially resolve assoc type 496 // FIXME potentially resolve assoc type
491 (Ty::Unknown, None) 497 (Ty::Unknown, None)
492 } 498 }
493 TypeNs::AdtId(AdtId::EnumId(_)) 499 TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
494 | TypeNs::AdtId(AdtId::UnionId(_))
495 | TypeNs::BuiltinType(_)
496 | TypeNs::TraitId(_) => {
497 // FIXME diagnostic 500 // FIXME diagnostic
498 (Ty::Unknown, None) 501 (Ty::Unknown, None)
499 } 502 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 1eacc6f95..7638f167b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -518,6 +518,7 @@ impl Ty {
518 let (segment, generic_def) = match resolved { 518 let (segment, generic_def) = match resolved {
519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
520 ValueTyDefId::StructId(it) => (last, Some(it.into())), 520 ValueTyDefId::StructId(it) => (last, Some(it.into())),
521 ValueTyDefId::UnionId(it) => (last, Some(it.into())),
521 ValueTyDefId::ConstId(it) => (last, Some(it.into())), 522 ValueTyDefId::ConstId(it) => (last, Some(it.into())),
522 ValueTyDefId::StaticId(_) => (last, None), 523 ValueTyDefId::StaticId(_) => (last, None),
523 ValueTyDefId::EnumVariantId(var) => { 524 ValueTyDefId::EnumVariantId(var) => {
@@ -1148,11 +1149,12 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI
1148pub enum ValueTyDefId { 1149pub enum ValueTyDefId {
1149 FunctionId(FunctionId), 1150 FunctionId(FunctionId),
1150 StructId(StructId), 1151 StructId(StructId),
1152 UnionId(UnionId),
1151 EnumVariantId(EnumVariantId), 1153 EnumVariantId(EnumVariantId),
1152 ConstId(ConstId), 1154 ConstId(ConstId),
1153 StaticId(StaticId), 1155 StaticId(StaticId),
1154} 1156}
1155impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); 1157impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
1156 1158
1157/// Build the declared type of an item. This depends on the namespace; e.g. for 1159/// Build the declared type of an item. This depends on the namespace; e.g. for
1158/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 1160/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1179,6 +1181,7 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
1179 match def { 1181 match def {
1180 ValueTyDefId::FunctionId(it) => type_for_fn(db, it), 1182 ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
1181 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), 1183 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
1184 ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
1182 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), 1185 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
1183 ValueTyDefId::ConstId(it) => type_for_const(db, it), 1186 ValueTyDefId::ConstId(it) => type_for_const(db, it),
1184 ValueTyDefId::StaticId(it) => type_for_static(db, it), 1187 ValueTyDefId::StaticId(it) => type_for_static(db, it),
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 3fd7d5cd4..5a7cf9455 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -334,16 +334,44 @@ fn infer_union() {
334 bar: f32, 334 bar: f32,
335 } 335 }
336 336
337 fn test() {
338 let u = MyUnion { foo: 0 };
339 unsafe { baz(u); }
340 let u = MyUnion { bar: 0.0 };
341 unsafe { baz(u); }
342 }
343
337 unsafe fn baz(u: MyUnion) { 344 unsafe fn baz(u: MyUnion) {
338 let inner = u.foo; 345 let inner = u.foo;
346 let inner = u.bar;
339 } 347 }
340 "#, 348 "#,
341 expect![[r#" 349 expect![[r#"
342 61..62 'u': MyUnion 350 57..172 '{ ...); } }': ()
343 73..99 '{ ...foo; }': () 351 67..68 'u': MyUnion
344 83..88 'inner': u32 352 71..89 'MyUnio...o: 0 }': MyUnion
345 91..92 'u': MyUnion 353 86..87 '0': u32
346 91..96 'u.foo': u32 354 95..113 'unsafe...(u); }': ()
355 102..113 '{ baz(u); }': ()
356 104..107 'baz': fn baz(MyUnion)
357 104..110 'baz(u)': ()
358 108..109 'u': MyUnion
359 122..123 'u': MyUnion
360 126..146 'MyUnio... 0.0 }': MyUnion
361 141..144 '0.0': f32
362 152..170 'unsafe...(u); }': ()
363 159..170 '{ baz(u); }': ()
364 161..164 'baz': fn baz(MyUnion)
365 161..167 'baz(u)': ()
366 165..166 'u': MyUnion
367 188..189 'u': MyUnion
368 200..249 '{ ...bar; }': ()
369 210..215 'inner': u32
370 218..219 'u': MyUnion
371 218..223 'u.foo': u32
372 233..238 'inner': f32
373 241..242 'u': MyUnion
374 241..246 'u.bar': f32
347 "#]], 375 "#]],
348 ); 376 );
349} 377}
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs
index 28d8f7876..4368e4eec 100644
--- a/crates/ra_ide/src/completion/complete_snippet.rs
+++ b/crates/ra_ide/src/completion/complete_snippet.rs
@@ -36,7 +36,7 @@ pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte
36 snippet( 36 snippet(
37 ctx, 37 ctx,
38 cap, 38 cap,
39 "Test module", 39 "tmod (Test module)",
40 "\ 40 "\
41#[cfg(test)] 41#[cfg(test)]
42mod tests { 42mod tests {
@@ -54,7 +54,7 @@ mod tests {
54 snippet( 54 snippet(
55 ctx, 55 ctx,
56 cap, 56 cap,
57 "Test function", 57 "tfn (Test function)",
58 "\ 58 "\
59#[test] 59#[test]
60fn ${1:feature}() { 60fn ${1:feature}() {
@@ -106,10 +106,10 @@ mod tests {
106} 106}
107"#, 107"#,
108 expect![[r#" 108 expect![[r#"
109 sn Test function
110 sn Test module
111 sn macro_rules 109 sn macro_rules
112 sn pub(crate) 110 sn pub(crate)
111 sn tfn (Test function)
112 sn tmod (Test module)
113 "#]], 113 "#]],
114 ) 114 )
115 } 115 }
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 6b03b30bb..4aa761148 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -27,7 +27,7 @@ pub(crate) struct CompletionContext<'a> {
27 pub(super) scope: SemanticsScope<'a>, 27 pub(super) scope: SemanticsScope<'a>,
28 pub(super) db: &'a RootDatabase, 28 pub(super) db: &'a RootDatabase,
29 pub(super) config: &'a CompletionConfig, 29 pub(super) config: &'a CompletionConfig,
30 pub(super) offset: TextSize, 30 pub(super) position: FilePosition,
31 /// The token before the cursor, in the original file. 31 /// The token before the cursor, in the original file.
32 pub(super) original_token: SyntaxToken, 32 pub(super) original_token: SyntaxToken,
33 /// The token before the cursor, in the macro-expanded file. 33 /// The token before the cursor, in the macro-expanded file.
@@ -117,7 +117,7 @@ impl<'a> CompletionContext<'a> {
117 config, 117 config,
118 original_token, 118 original_token,
119 token, 119 token,
120 offset: position.offset, 120 position,
121 krate, 121 krate,
122 expected_type: None, 122 expected_type: None,
123 name_ref_syntax: None, 123 name_ref_syntax: None,
@@ -209,7 +209,7 @@ impl<'a> CompletionContext<'a> {
209 mark::hit!(completes_if_prefix_is_keyword); 209 mark::hit!(completes_if_prefix_is_keyword);
210 self.original_token.text_range() 210 self.original_token.text_range()
211 } else { 211 } else {
212 TextRange::empty(self.offset) 212 TextRange::empty(self.position.offset)
213 } 213 }
214 } 214 }
215 215
@@ -379,8 +379,8 @@ impl<'a> CompletionContext<'a> {
379 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 379 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
380 self.has_type_args = segment.generic_arg_list().is_some(); 380 self.has_type_args = segment.generic_arg_list().is_some();
381 381
382 #[allow(deprecated)] 382 let hygiene = hir::Hygiene::new(self.db, self.position.file_id.into());
383 if let Some(path) = hir::Path::from_ast(path.clone()) { 383 if let Some(path) = hir::Path::from_src(path.clone(), &hygiene) {
384 if let Some(path_prefix) = path.qualifier() { 384 if let Some(path_prefix) = path.qualifier() {
385 self.path_prefix = Some(path_prefix); 385 self.path_prefix = Some(path_prefix);
386 return; 386 return;
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 9a94ff476..59f1b1424 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -2,8 +2,8 @@
2//! It also handles scoring (sorting) completions. 2//! It also handles scoring (sorting) completions.
3 3
4use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; 4use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
5use itertools::Itertools;
5use ra_syntax::ast::NameOwner; 6use ra_syntax::ast::NameOwner;
6use stdx::SepBy;
7use test_utils::mark; 7use test_utils::mark;
8 8
9use crate::{ 9use crate::{
@@ -289,16 +289,16 @@ impl Completions {
289 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); 289 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
290 let variant_kind = variant.kind(ctx.db); 290 let variant_kind = variant.kind(ctx.db);
291 let detail = match variant_kind { 291 let detail = match variant_kind {
292 StructKind::Tuple | StructKind::Unit => detail_types 292 StructKind::Tuple | StructKind::Unit => format!(
293 .map(|(_, t)| t.display(ctx.db).to_string()) 293 "({})",
294 .sep_by(", ") 294 detail_types.map(|(_, t)| t.display(ctx.db).to_string()).format(", ")
295 .surround_with("(", ")") 295 ),
296 .to_string(), 296 StructKind::Record => format!(
297 StructKind::Record => detail_types 297 "{{ {} }}",
298 .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string())) 298 detail_types
299 .sep_by(", ") 299 .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))
300 .surround_with("{ ", " }") 300 .format(", ")
301 .to_string(), 301 ),
302 }; 302 };
303 let mut res = CompletionItem::new( 303 let mut res = CompletionItem::new(
304 CompletionKind::Reference, 304 CompletionKind::Reference,
@@ -412,11 +412,10 @@ impl Builder {
412 self = self.trigger_call_info(); 412 self = self.trigger_call_info();
413 let snippet = match (ctx.config.add_call_argument_snippets, params) { 413 let snippet = match (ctx.config.add_call_argument_snippets, params) {
414 (true, Params::Named(params)) => { 414 (true, Params::Named(params)) => {
415 let function_params_snippet = params 415 let function_params_snippet =
416 .iter() 416 params.iter().enumerate().format_with(", ", |(index, param_name), f| {
417 .enumerate() 417 f(&format_args!("${{{}:{}}}", index + 1, param_name))
418 .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name)) 418 });
419 .sep_by(", ");
420 format!("{}({})$0", name, function_params_snippet) 419 format!("{}({})$0", name, function_params_snippet)
421 } 420 }
422 _ => { 421 _ => {
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 5ce900bf4..79dbb0865 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -6,22 +6,21 @@
6 6
7use std::cell::RefCell; 7use std::cell::RefCell;
8 8
9use hir::{ 9use hir::{diagnostics::DiagnosticSinkBuilder, Semantics};
10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSinkBuilder},
11 HasSource, HirDisplay, Semantics, VariantDef,
12};
13use itertools::Itertools; 10use itertools::Itertools;
14use ra_db::SourceDatabase; 11use ra_db::SourceDatabase;
15use ra_ide_db::RootDatabase; 12use ra_ide_db::RootDatabase;
16use ra_prof::profile; 13use ra_prof::profile;
17use ra_syntax::{ 14use ra_syntax::{
18 algo, 15 ast::{self, AstNode},
19 ast::{self, edit::IndentLevel, make, AstNode},
20 SyntaxNode, TextRange, T, 16 SyntaxNode, TextRange, T,
21}; 17};
22use ra_text_edit::{TextEdit, TextEditBuilder}; 18use ra_text_edit::{TextEdit, TextEditBuilder};
23 19
24use crate::{AnalysisConfig, Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; 20use crate::{AnalysisConfig, Diagnostic, FileId, Fix, SourceFileEdit};
21
22mod diagnostics_with_fix;
23use diagnostics_with_fix::DiagnosticWithFix;
25 24
26#[derive(Debug, Copy, Clone)] 25#[derive(Debug, Copy, Clone)]
27pub enum Severity { 26pub enum Severity {
@@ -56,77 +55,16 @@ pub(crate) fn diagnostics(
56 let res = RefCell::new(res); 55 let res = RefCell::new(res);
57 let mut sink_builder = DiagnosticSinkBuilder::new() 56 let mut sink_builder = DiagnosticSinkBuilder::new()
58 .on::<hir::diagnostics::UnresolvedModule, _>(|d| { 57 .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
59 let original_file = d.source().file_id.original_file(db); 58 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
60 let fix = Fix::new(
61 "Create module",
62 FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }
63 .into(),
64 );
65 res.borrow_mut().push(Diagnostic {
66 name: Some(d.name().into()),
67 range: sema.diagnostics_range(d).range,
68 message: d.message(),
69 severity: Severity::Error,
70 fix: Some(fix),
71 })
72 }) 59 })
73 .on::<hir::diagnostics::MissingFields, _>(|d| { 60 .on::<hir::diagnostics::MissingFields, _>(|d| {
74 // Note that although we could add a diagnostics to 61 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
75 // fill the missing tuple field, e.g :
76 // `struct A(usize);`
77 // `let a = A { 0: () }`
78 // but it is uncommon usage and it should not be encouraged.
79 let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
80 None
81 } else {
82 let mut field_list = d.ast(db);
83 for f in d.missed_fields.iter() {
84 let field = make::record_expr_field(
85 make::name_ref(&f.to_string()),
86 Some(make::expr_unit()),
87 );
88 field_list = field_list.append_field(&field);
89 }
90
91 let edit = {
92 let mut builder = TextEditBuilder::default();
93 algo::diff(&d.ast(db).syntax(), &field_list.syntax())
94 .into_text_edit(&mut builder);
95 builder.finish()
96 };
97 Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
98 };
99
100 res.borrow_mut().push(Diagnostic {
101 name: Some(d.name().into()),
102 range: sema.diagnostics_range(d).range,
103 message: d.message(),
104 severity: Severity::Error,
105 fix,
106 })
107 }) 62 })
108 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { 63 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
109 let node = d.ast(db); 64 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
110 let replacement = format!("Ok({})", node.syntax());
111 let edit = TextEdit::replace(node.syntax().text_range(), replacement);
112 let source_change = SourceFileEdit { file_id, edit }.into();
113 let fix = Fix::new("Wrap with ok", source_change);
114 res.borrow_mut().push(Diagnostic {
115 name: Some(d.name().into()),
116 range: sema.diagnostics_range(d).range,
117 message: d.message(),
118 severity: Severity::Error,
119 fix: Some(fix),
120 })
121 }) 65 })
122 .on::<hir::diagnostics::NoSuchField, _>(|d| { 66 .on::<hir::diagnostics::NoSuchField, _>(|d| {
123 res.borrow_mut().push(Diagnostic { 67 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
124 name: Some(d.name().into()),
125 range: sema.diagnostics_range(d).range,
126 message: d.message(),
127 severity: Severity::Error,
128 fix: missing_struct_field_fix(&sema, file_id, d),
129 })
130 }) 68 })
131 // Only collect experimental diagnostics when they're enabled. 69 // Only collect experimental diagnostics when they're enabled.
132 .filter(|diag| !diag.is_experimental() || enable_experimental); 70 .filter(|diag| !diag.is_experimental() || enable_experimental);
@@ -144,7 +82,7 @@ pub(crate) fn diagnostics(
144 res.borrow_mut().push(Diagnostic { 82 res.borrow_mut().push(Diagnostic {
145 name: Some(d.name().into()), 83 name: Some(d.name().into()),
146 message: d.message(), 84 message: d.message(),
147 range: sema.diagnostics_range(d).range, 85 range: sema.diagnostics_display_range(d).range,
148 severity: Severity::Error, 86 severity: Severity::Error,
149 fix: None, 87 fix: None,
150 }) 88 })
@@ -157,77 +95,13 @@ pub(crate) fn diagnostics(
157 res.into_inner() 95 res.into_inner()
158} 96}
159 97
160fn missing_struct_field_fix( 98fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
161 sema: &Semantics<RootDatabase>, 99 Diagnostic {
162 usage_file_id: FileId, 100 name: Some(d.name().into()),
163 d: &hir::diagnostics::NoSuchField, 101 range: sema.diagnostics_display_range(d).range,
164) -> Option<Fix> { 102 message: d.message(),
165 let record_expr = sema.ast(d); 103 severity: Severity::Error,
166 104 fix: d.fix(&sema),
167 let record_lit = ast::RecordExpr::cast(record_expr.syntax().parent()?.parent()?)?;
168 let def_id = sema.resolve_variant(record_lit)?;
169 let module;
170 let def_file_id;
171 let record_fields = match VariantDef::from(def_id) {
172 VariantDef::Struct(s) => {
173 module = s.module(sema.db);
174 let source = s.source(sema.db);
175 def_file_id = source.file_id;
176 let fields = source.value.field_list()?;
177 record_field_list(fields)?
178 }
179 VariantDef::Union(u) => {
180 module = u.module(sema.db);
181 let source = u.source(sema.db);
182 def_file_id = source.file_id;
183 source.value.record_field_list()?
184 }
185 VariantDef::EnumVariant(e) => {
186 module = e.module(sema.db);
187 let source = e.source(sema.db);
188 def_file_id = source.file_id;
189 let fields = source.value.field_list()?;
190 record_field_list(fields)?
191 }
192 };
193 let def_file_id = def_file_id.original_file(sema.db);
194
195 let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
196 if new_field_type.is_unknown() {
197 return None;
198 }
199 let new_field = make::record_field(
200 record_expr.field_name()?,
201 make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
202 );
203
204 let last_field = record_fields.fields().last()?;
205 let last_field_syntax = last_field.syntax();
206 let indent = IndentLevel::from_node(last_field_syntax);
207
208 let mut new_field = new_field.to_string();
209 if usage_file_id != def_file_id {
210 new_field = format!("pub(crate) {}", new_field);
211 }
212 new_field = format!("\n{}{}", indent, new_field);
213
214 let needs_comma = !last_field_syntax.to_string().ends_with(',');
215 if needs_comma {
216 new_field = format!(",{}", new_field);
217 }
218
219 let source_change = SourceFileEdit {
220 file_id: def_file_id,
221 edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
222 };
223 let fix = Fix::new("Create field", source_change.into());
224 return Some(fix);
225
226 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
227 match field_def_list {
228 ast::FieldList::RecordFieldList(it) => Some(it),
229 ast::FieldList::TupleFieldList(_) => None,
230 }
231 } 105 }
232} 106}
233 107
@@ -238,25 +112,26 @@ fn check_unnecessary_braces_in_use_statement(
238) -> Option<()> { 112) -> Option<()> {
239 let use_tree_list = ast::UseTreeList::cast(node.clone())?; 113 let use_tree_list = ast::UseTreeList::cast(node.clone())?;
240 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { 114 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
241 let range = use_tree_list.syntax().text_range(); 115 let use_range = use_tree_list.syntax().text_range();
242 let edit = 116 let edit =
243 text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) 117 text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
244 .unwrap_or_else(|| { 118 .unwrap_or_else(|| {
245 let to_replace = single_use_tree.syntax().text().to_string(); 119 let to_replace = single_use_tree.syntax().text().to_string();
246 let mut edit_builder = TextEditBuilder::default(); 120 let mut edit_builder = TextEditBuilder::default();
247 edit_builder.delete(range); 121 edit_builder.delete(use_range);
248 edit_builder.insert(range.start(), to_replace); 122 edit_builder.insert(use_range.start(), to_replace);
249 edit_builder.finish() 123 edit_builder.finish()
250 }); 124 });
251 125
252 acc.push(Diagnostic { 126 acc.push(Diagnostic {
253 name: None, 127 name: None,
254 range, 128 range: use_range,
255 message: "Unnecessary braces in use statement".to_string(), 129 message: "Unnecessary braces in use statement".to_string(),
256 severity: Severity::WeakWarning, 130 severity: Severity::WeakWarning,
257 fix: Some(Fix::new( 131 fix: Some(Fix::new(
258 "Remove unnecessary braces", 132 "Remove unnecessary braces",
259 SourceFileEdit { file_id, edit }.into(), 133 SourceFileEdit { file_id, edit }.into(),
134 use_range,
260 )), 135 )),
261 }); 136 });
262 } 137 }
@@ -271,8 +146,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
271 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { 146 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] {
272 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); 147 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
273 let end = use_tree_list_node.text_range().end(); 148 let end = use_tree_list_node.text_range().end();
274 let range = TextRange::new(start, end); 149 return Some(TextEdit::delete(TextRange::new(start, end)));
275 return Some(TextEdit::delete(range));
276 } 150 }
277 None 151 None
278} 152}
@@ -295,14 +169,16 @@ fn check_struct_shorthand_initialization(
295 edit_builder.insert(record_field.syntax().text_range().start(), field_name); 169 edit_builder.insert(record_field.syntax().text_range().start(), field_name);
296 let edit = edit_builder.finish(); 170 let edit = edit_builder.finish();
297 171
172 let field_range = record_field.syntax().text_range();
298 acc.push(Diagnostic { 173 acc.push(Diagnostic {
299 name: None, 174 name: None,
300 range: record_field.syntax().text_range(), 175 range: field_range,
301 message: "Shorthand struct initialization".to_string(), 176 message: "Shorthand struct initialization".to_string(),
302 severity: Severity::WeakWarning, 177 severity: Severity::WeakWarning,
303 fix: Some(Fix::new( 178 fix: Some(Fix::new(
304 "Use struct shorthand initialization", 179 "Use struct shorthand initialization",
305 SourceFileEdit { file_id, edit }.into(), 180 SourceFileEdit { file_id, edit }.into(),
181 field_range,
306 )), 182 )),
307 }); 183 });
308 } 184 }
@@ -326,7 +202,7 @@ mod tests {
326 /// Takes a multi-file input fixture with annotated cursor positions, 202 /// Takes a multi-file input fixture with annotated cursor positions,
327 /// and checks that: 203 /// and checks that:
328 /// * a diagnostic is produced 204 /// * a diagnostic is produced
329 /// * this diagnostic touches the input cursor position 205 /// * this diagnostic fix trigger range touches the input cursor position
330 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied 206 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
331 fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { 207 fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
332 let after = trim_indent(ra_fixture_after); 208 let after = trim_indent(ra_fixture_after);
@@ -344,10 +220,10 @@ mod tests {
344 220
345 assert_eq_text!(&after, &actual); 221 assert_eq_text!(&after, &actual);
346 assert!( 222 assert!(
347 diagnostic.range.start() <= file_position.offset 223 fix.fix_trigger_range.start() <= file_position.offset
348 && diagnostic.range.end() >= file_position.offset, 224 && fix.fix_trigger_range.end() >= file_position.offset,
349 "diagnostic range {:?} does not touch cursor position {:?}", 225 "diagnostic fix range {:?} does not touch cursor position {:?}",
350 diagnostic.range, 226 fix.fix_trigger_range,
351 file_position.offset 227 file_position.offset
352 ); 228 );
353 } 229 }
@@ -712,6 +588,7 @@ fn test_fn() {
712 ], 588 ],
713 is_snippet: false, 589 is_snippet: false,
714 }, 590 },
591 fix_trigger_range: 0..8,
715 }, 592 },
716 ), 593 ),
717 }, 594 },
diff --git a/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs b/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs
new file mode 100644
index 000000000..f7c73773f
--- /dev/null
+++ b/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs
@@ -0,0 +1,171 @@
1//! Provides a way to attach fixes to the diagnostics.
2//! The same module also has all curret custom fixes for the diagnostics implemented.
3use crate::Fix;
4use ast::{edit::IndentLevel, make};
5use hir::{
6 db::AstDatabase,
7 diagnostics::{Diagnostic, MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule},
8 HasSource, HirDisplay, Semantics, VariantDef,
9};
10use ra_db::FileId;
11use ra_ide_db::{
12 source_change::{FileSystemEdit, SourceFileEdit},
13 RootDatabase,
14};
15use ra_syntax::{algo, ast, AstNode};
16use ra_text_edit::{TextEdit, TextEditBuilder};
17
18/// A [Diagnostic] that potentially has a fix available.
19///
20/// [Diagnostic]: hir::diagnostics::Diagnostic
21pub trait DiagnosticWithFix: Diagnostic {
22 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>;
23}
24
25impl DiagnosticWithFix for UnresolvedModule {
26 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
27 let root = sema.db.parse_or_expand(self.file)?;
28 let unresolved_module = self.decl.to_node(&root);
29 Some(Fix::new(
30 "Create module",
31 FileSystemEdit::CreateFile {
32 anchor: self.file.original_file(sema.db),
33 dst: self.candidate.clone(),
34 }
35 .into(),
36 unresolved_module.syntax().text_range(),
37 ))
38 }
39}
40
41impl DiagnosticWithFix for NoSuchField {
42 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
43 let root = sema.db.parse_or_expand(self.file)?;
44 missing_record_expr_field_fix(
45 &sema,
46 self.file.original_file(sema.db),
47 &self.field.to_node(&root),
48 )
49 }
50}
51
52impl DiagnosticWithFix for MissingFields {
53 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
54 // Note that although we could add a diagnostics to
55 // fill the missing tuple field, e.g :
56 // `struct A(usize);`
57 // `let a = A { 0: () }`
58 // but it is uncommon usage and it should not be encouraged.
59 if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
60 return None;
61 }
62
63 let root = sema.db.parse_or_expand(self.file)?;
64 let old_field_list = self.field_list_parent.to_node(&root).record_expr_field_list()?;
65 let mut new_field_list = old_field_list.clone();
66 for f in self.missed_fields.iter() {
67 let field =
68 make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
69 new_field_list = new_field_list.append_field(&field);
70 }
71
72 let edit = {
73 let mut builder = TextEditBuilder::default();
74 algo::diff(&old_field_list.syntax(), &new_field_list.syntax())
75 .into_text_edit(&mut builder);
76 builder.finish()
77 };
78 Some(Fix::new(
79 "Fill struct fields",
80 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(),
81 sema.original_range(&old_field_list.syntax()).range,
82 ))
83 }
84}
85
86impl DiagnosticWithFix for MissingOkInTailExpr {
87 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
88 let root = sema.db.parse_or_expand(self.file)?;
89 let tail_expr = self.expr.to_node(&root);
90 let tail_expr_range = tail_expr.syntax().text_range();
91 let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax()));
92 let source_change =
93 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
94 Some(Fix::new("Wrap with ok", source_change, tail_expr_range))
95 }
96}
97
98fn missing_record_expr_field_fix(
99 sema: &Semantics<RootDatabase>,
100 usage_file_id: FileId,
101 record_expr_field: &ast::RecordExprField,
102) -> Option<Fix> {
103 let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
104 let def_id = sema.resolve_variant(record_lit)?;
105 let module;
106 let def_file_id;
107 let record_fields = match VariantDef::from(def_id) {
108 VariantDef::Struct(s) => {
109 module = s.module(sema.db);
110 let source = s.source(sema.db);
111 def_file_id = source.file_id;
112 let fields = source.value.field_list()?;
113 record_field_list(fields)?
114 }
115 VariantDef::Union(u) => {
116 module = u.module(sema.db);
117 let source = u.source(sema.db);
118 def_file_id = source.file_id;
119 source.value.record_field_list()?
120 }
121 VariantDef::EnumVariant(e) => {
122 module = e.module(sema.db);
123 let source = e.source(sema.db);
124 def_file_id = source.file_id;
125 let fields = source.value.field_list()?;
126 record_field_list(fields)?
127 }
128 };
129 let def_file_id = def_file_id.original_file(sema.db);
130
131 let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?;
132 if new_field_type.is_unknown() {
133 return None;
134 }
135 let new_field = make::record_field(
136 record_expr_field.field_name()?,
137 make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
138 );
139
140 let last_field = record_fields.fields().last()?;
141 let last_field_syntax = last_field.syntax();
142 let indent = IndentLevel::from_node(last_field_syntax);
143
144 let mut new_field = new_field.to_string();
145 if usage_file_id != def_file_id {
146 new_field = format!("pub(crate) {}", new_field);
147 }
148 new_field = format!("\n{}{}", indent, new_field);
149
150 let needs_comma = !last_field_syntax.to_string().ends_with(',');
151 if needs_comma {
152 new_field = format!(",{}", new_field);
153 }
154
155 let source_change = SourceFileEdit {
156 file_id: def_file_id,
157 edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
158 };
159 return Some(Fix::new(
160 "Create field",
161 source_change.into(),
162 record_expr_field.syntax().text_range(),
163 ));
164
165 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
166 match field_def_list {
167 ast::FieldList::RecordFieldList(it) => Some(it),
168 ast::FieldList::TupleFieldList(_) => None,
169 }
170 }
171}
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs
index 0fdf8e9a5..010c34705 100644
--- a/crates/ra_ide/src/display/short_label.rs
+++ b/crates/ra_ide/src/display/short_label.rs
@@ -47,6 +47,12 @@ impl ShortLabel for ast::Module {
47 } 47 }
48} 48}
49 49
50impl ShortLabel for ast::SourceFile {
51 fn short_label(&self) -> Option<String> {
52 None
53 }
54}
55
50impl ShortLabel for ast::TypeAlias { 56impl ShortLabel for ast::TypeAlias {
51 fn short_label(&self) -> Option<String> { 57 fn short_label(&self) -> Option<String> {
52 short_label_from_node(self, "type ") 58 short_label_from_node(self, "type ")
@@ -55,7 +61,11 @@ impl ShortLabel for ast::TypeAlias {
55 61
56impl ShortLabel for ast::Const { 62impl ShortLabel for ast::Const {
57 fn short_label(&self) -> Option<String> { 63 fn short_label(&self) -> Option<String> {
58 short_label_from_ty(self, self.ty(), "const ") 64 let mut new_buf = short_label_from_ty(self, self.ty(), "const ")?;
65 if let Some(expr) = self.body() {
66 format_to!(new_buf, " = {}", expr.syntax());
67 }
68 Some(new_buf)
59 } 69 }
60} 70}
61 71
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 4e3f428fa..45389fd23 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -1,6 +1,6 @@
1use hir::Semantics; 1use hir::Semantics;
2use ra_ide_db::{ 2use ra_ide_db::{
3 defs::{classify_name, classify_name_ref, NameClass}, 3 defs::{classify_name, classify_name_ref},
4 symbol_index, RootDatabase, 4 symbol_index, RootDatabase,
5}; 5};
6use ra_syntax::{ 6use ra_syntax::{
@@ -40,10 +40,7 @@ pub(crate) fn goto_definition(
40 reference_definition(&sema, &name_ref).to_vec() 40 reference_definition(&sema, &name_ref).to_vec()
41 }, 41 },
42 ast::Name(name) => { 42 ast::Name(name) => {
43 let def = match classify_name(&sema, &name)? { 43 let def = classify_name(&sema, &name)?.definition(sema.db);
44 NameClass::Definition(def) | NameClass::ConstReference(def) => def,
45 NameClass::FieldShorthand { local: _, field } => field,
46 };
47 let nav = def.try_to_nav(sema.db)?; 44 let nav = def.try_to_nav(sema.db)?;
48 vec![nav] 45 vec![nav]
49 }, 46 },
@@ -86,8 +83,7 @@ pub(crate) fn reference_definition(
86) -> ReferenceResult { 83) -> ReferenceResult {
87 let name_kind = classify_name_ref(sema, name_ref); 84 let name_kind = classify_name_ref(sema, name_ref);
88 if let Some(def) = name_kind { 85 if let Some(def) = name_kind {
89 let def = def.definition(); 86 let def = def.definition(sema.db);
90
91 return match def.try_to_nav(sema.db) { 87 return match def.try_to_nav(sema.db) {
92 Some(nav) => ReferenceResult::Exact(nav), 88 Some(nav) => ReferenceResult::Exact(nav),
93 None => ReferenceResult::Approximate(Vec::new()), 89 None => ReferenceResult::Approximate(Vec::new()),
@@ -134,6 +130,32 @@ mod tests {
134 } 130 }
135 131
136 #[test] 132 #[test]
133 fn goto_def_for_extern_crate() {
134 check(
135 r#"
136 //- /main.rs
137 extern crate std<|>;
138 //- /std/lib.rs
139 // empty
140 //^ file
141 "#,
142 )
143 }
144
145 #[test]
146 fn goto_def_for_renamed_extern_crate() {
147 check(
148 r#"
149 //- /main.rs
150 extern crate std as abc<|>;
151 //- /std/lib.rs
152 // empty
153 //^ file
154 "#,
155 )
156 }
157
158 #[test]
137 fn goto_def_in_items() { 159 fn goto_def_in_items() {
138 check( 160 check(
139 r#" 161 r#"
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index aa48cb412..f66f62bfb 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -85,8 +85,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
85 let node = token.parent(); 85 let node = token.parent();
86 let definition = match_ast! { 86 let definition = match_ast! {
87 match node { 87 match node {
88 ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()), 88 ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)),
89 ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()), 89 ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition(sema.db)),
90 _ => None, 90 _ => None,
91 } 91 }
92 }; 92 };
@@ -304,7 +304,10 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
304 let docs = Documentation::from_ast(&it).map(Into::into); 304 let docs = Documentation::from_ast(&it).map(Into::into);
305 hover_markup(docs, it.short_label(), mod_path) 305 hover_markup(docs, it.short_label(), mod_path)
306 } 306 }
307 _ => None, 307 ModuleSource::SourceFile(it) => {
308 let docs = Documentation::from_ast(&it).map(Into::into);
309 hover_markup(docs, it.short_label(), mod_path)
310 }
308 }, 311 },
309 ModuleDef::Function(it) => from_def_source(db, it, mod_path), 312 ModuleDef::Function(it) => from_def_source(db, it, mod_path),
310 ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), 313 ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
@@ -509,6 +512,37 @@ fn main() { }
509 } 512 }
510 513
511 #[test] 514 #[test]
515 fn hover_shows_fn_doc() {
516 check(
517 r#"
518/// # Example
519/// ```
520/// # use std::path::Path;
521/// #
522/// foo(Path::new("hello, world!"))
523/// ```
524pub fn foo<|>(_: &Path) {}
525
526fn main() { }
527"#,
528 expect![[r#"
529 *foo*
530 ```rust
531 pub fn foo(_: &Path)
532 ```
533 ___
534
535 # Example
536 ```
537 # use std::path::Path;
538 #
539 foo(Path::new("hello, world!"))
540 ```
541 "#]],
542 );
543 }
544
545 #[test]
512 fn hover_shows_struct_field_info() { 546 fn hover_shows_struct_field_info() {
513 // Hovering over the field when instantiating 547 // Hovering over the field when instantiating
514 check( 548 check(
@@ -556,16 +590,16 @@ fn main() {
556 #[test] 590 #[test]
557 fn hover_const_static() { 591 fn hover_const_static() {
558 check( 592 check(
559 r#"const foo<|>: u32 = 0;"#, 593 r#"const foo<|>: u32 = 123;"#,
560 expect![[r#" 594 expect![[r#"
561 *foo* 595 *foo*
562 ```rust 596 ```rust
563 const foo: u32 597 const foo: u32 = 123
564 ``` 598 ```
565 "#]], 599 "#]],
566 ); 600 );
567 check( 601 check(
568 r#"static foo<|>: u32 = 0;"#, 602 r#"static foo<|>: u32 = 456;"#,
569 expect![[r#" 603 expect![[r#"
570 *foo* 604 *foo*
571 ```rust 605 ```rust
@@ -800,7 +834,7 @@ fn main() {
800 expect![[r#" 834 expect![[r#"
801 *C* 835 *C*
802 ```rust 836 ```rust
803 const C: u32 837 const C: u32 = 1
804 ``` 838 ```
805 "#]], 839 "#]],
806 ) 840 )
@@ -1107,6 +1141,46 @@ fn bar() { fo<|>o(); }
1107 } 1141 }
1108 1142
1109 #[test] 1143 #[test]
1144 fn test_hover_extern_crate() {
1145 check(
1146 r#"
1147//- /main.rs
1148extern crate st<|>d;
1149//- /std/lib.rs
1150//! Standard library for this test
1151//!
1152//! Printed?
1153//! abc123
1154 "#,
1155 expect![[r#"
1156 *std*
1157 Standard library for this test
1158
1159 Printed?
1160 abc123
1161 "#]],
1162 );
1163 check(
1164 r#"
1165//- /main.rs
1166extern crate std as ab<|>c;
1167//- /std/lib.rs
1168//! Standard library for this test
1169//!
1170//! Printed?
1171//! abc123
1172 "#,
1173 expect![[r#"
1174 *abc*
1175 Standard library for this test
1176
1177 Printed?
1178 abc123
1179 "#]],
1180 );
1181 }
1182
1183 #[test]
1110 fn test_hover_mod_with_same_name_as_function() { 1184 fn test_hover_mod_with_same_name_as_function() {
1111 check( 1185 check(
1112 r#" 1186 r#"
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 3822b9409..2cbd7e4f0 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -119,13 +119,19 @@ pub struct Diagnostic {
119pub struct Fix { 119pub struct Fix {
120 pub label: String, 120 pub label: String,
121 pub source_change: SourceChange, 121 pub source_change: SourceChange,
122 /// Allows to trigger the fix only when the caret is in the range given
123 pub fix_trigger_range: TextRange,
122} 124}
123 125
124impl Fix { 126impl Fix {
125 pub fn new(label: impl Into<String>, source_change: SourceChange) -> Self { 127 pub fn new(
128 label: impl Into<String>,
129 source_change: SourceChange,
130 fix_trigger_range: TextRange,
131 ) -> Self {
126 let label = label.into(); 132 let label = label.into();
127 assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); 133 assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.'));
128 Self { label, source_change } 134 Self { label, source_change, fix_trigger_range }
129 } 135 }
130} 136}
131 137
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index cf456630a..453985de3 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -130,13 +130,13 @@ fn find_name(
130 opt_name: Option<ast::Name>, 130 opt_name: Option<ast::Name>,
131) -> Option<RangeInfo<Definition>> { 131) -> Option<RangeInfo<Definition>> {
132 if let Some(name) = opt_name { 132 if let Some(name) = opt_name {
133 let def = classify_name(sema, &name)?.definition(); 133 let def = classify_name(sema, &name)?.definition(sema.db);
134 let range = name.syntax().text_range(); 134 let range = name.syntax().text_range();
135 return Some(RangeInfo::new(range, def)); 135 return Some(RangeInfo::new(range, def));
136 } 136 }
137 let name_ref = 137 let name_ref =
138 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; 138 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
139 let def = classify_name_ref(sema, &name_ref)?.definition(); 139 let def = classify_name_ref(sema, &name_ref)?.definition(sema.db);
140 let range = name_ref.syntax().text_range(); 140 let range = name_ref.syntax().text_range();
141 Some(RangeInfo::new(range, def)) 141 Some(RangeInfo::new(range, def))
142} 142}
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index 4348b43be..8be862fd6 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -21,8 +21,8 @@ use ra_ssr::{MatchFinder, SsrError, SsrRule};
21// replacement occurs. For example if our replacement template is `foo::Bar` and we match some 21// replacement occurs. For example if our replacement template is `foo::Bar` and we match some
22// code in the `foo` module, we'll insert just `Bar`. 22// code in the `foo` module, we'll insert just `Bar`.
23// 23//
24// Method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will match 24// Inherent method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will
25// `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. 25// match `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`.
26// 26//
27// The scope of the search / replace will be restricted to the current selection if any, otherwise 27// The scope of the search / replace will be restricted to the current selection if any, otherwise
28// it will apply to the whole workspace. 28// it will apply to the whole workspace.
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index a32ae0165..c10e15db8 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -4,7 +4,7 @@ mod injection;
4#[cfg(test)] 4#[cfg(test)]
5mod tests; 5mod tests;
6 6
7use hir::{Name, Semantics}; 7use hir::{Name, Semantics, VariantDef};
8use ra_ide_db::{ 8use ra_ide_db::{
9 defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, 9 defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
10 RootDatabase, 10 RootDatabase,
@@ -455,6 +455,18 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
455 Some(TextRange::new(range_start, range_end)) 455 Some(TextRange::new(range_start, range_end))
456} 456}
457 457
458fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool {
459 name_ref
460 .syntax()
461 .parent()
462 .and_then(|parent| {
463 ast::FieldExpr::cast(parent.clone())
464 .map(|_| true)
465 .or_else(|| ast::RecordPatField::cast(parent).map(|_| true))
466 })
467 .unwrap_or(false)
468}
469
458fn highlight_element( 470fn highlight_element(
459 sema: &Semantics<RootDatabase>, 471 sema: &Semantics<RootDatabase>,
460 bindings_shadow_count: &mut FxHashMap<Name, u32>, 472 bindings_shadow_count: &mut FxHashMap<Name, u32>,
@@ -483,11 +495,21 @@ fn highlight_element(
483 }; 495 };
484 496
485 match name_kind { 497 match name_kind {
498 Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
486 Some(NameClass::Definition(def)) => { 499 Some(NameClass::Definition(def)) => {
487 highlight_name(db, def) | HighlightModifier::Definition 500 highlight_name(sema, db, def, None, false) | HighlightModifier::Definition
501 }
502 Some(NameClass::ConstReference(def)) => highlight_name(sema, db, def, None, false),
503 Some(NameClass::FieldShorthand { field, .. }) => {
504 let mut h = HighlightTag::Field.into();
505 if let Definition::Field(field) = field {
506 if let VariantDef::Union(_) = field.parent_def(db) {
507 h |= HighlightModifier::Unsafe;
508 }
509 }
510
511 h
488 } 512 }
489 Some(NameClass::ConstReference(def)) => highlight_name(db, def),
490 Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(),
491 None => highlight_name_by_syntax(name) | HighlightModifier::Definition, 513 None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
492 } 514 }
493 } 515 }
@@ -498,8 +520,10 @@ fn highlight_element(
498 } 520 }
499 NAME_REF => { 521 NAME_REF => {
500 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); 522 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
523 let possibly_unsafe = is_possibly_unsafe(&name_ref);
501 match classify_name_ref(sema, &name_ref) { 524 match classify_name_ref(sema, &name_ref) {
502 Some(name_kind) => match name_kind { 525 Some(name_kind) => match name_kind {
526 NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
503 NameRefClass::Definition(def) => { 527 NameRefClass::Definition(def) => {
504 if let Definition::Local(local) = &def { 528 if let Definition::Local(local) = &def {
505 if let Some(name) = local.name(db) { 529 if let Some(name) = local.name(db) {
@@ -508,11 +532,13 @@ fn highlight_element(
508 binding_hash = Some(calc_binding_hash(&name, *shadow_count)) 532 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
509 } 533 }
510 }; 534 };
511 highlight_name(db, def) 535 highlight_name(sema, db, def, Some(name_ref), possibly_unsafe)
512 } 536 }
513 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 537 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
514 }, 538 },
515 None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), 539 None if syntactic_name_ref_highlighting => {
540 highlight_name_ref_by_syntax(name_ref, sema)
541 }
516 None => HighlightTag::UnresolvedReference.into(), 542 None => HighlightTag::UnresolvedReference.into(),
517 } 543 }
518 } 544 }
@@ -540,9 +566,20 @@ fn highlight_element(
540 } 566 }
541 } 567 }
542 p if p.is_punct() => match p { 568 p if p.is_punct() => match p {
543 T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { 569 T![&] => {
544 HighlightTag::Operator.into() 570 let h = HighlightTag::Operator.into();
571 let is_unsafe = element
572 .parent()
573 .and_then(ast::RefExpr::cast)
574 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
575 .unwrap_or(false);
576 if is_unsafe {
577 h | HighlightModifier::Unsafe
578 } else {
579 h
580 }
545 } 581 }
582 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] => HighlightTag::Operator.into(),
546 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 583 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
547 HighlightTag::Macro.into() 584 HighlightTag::Macro.into()
548 } 585 }
@@ -623,6 +660,18 @@ fn highlight_element(
623 HighlightTag::SelfKeyword.into() 660 HighlightTag::SelfKeyword.into()
624 } 661 }
625 } 662 }
663 T![ref] => element
664 .parent()
665 .and_then(ast::IdentPat::cast)
666 .and_then(|ident_pat| {
667 if sema.is_unsafe_ident_pat(&ident_pat) {
668 Some(HighlightModifier::Unsafe)
669 } else {
670 None
671 }
672 })
673 .map(|modifier| h | modifier)
674 .unwrap_or(h),
626 _ => h, 675 _ => h,
627 } 676 }
628 } 677 }
@@ -652,16 +701,40 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool {
652 } 701 }
653} 702}
654 703
655fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { 704fn highlight_name(
705 sema: &Semantics<RootDatabase>,
706 db: &RootDatabase,
707 def: Definition,
708 name_ref: Option<ast::NameRef>,
709 possibly_unsafe: bool,
710) -> Highlight {
656 match def { 711 match def {
657 Definition::Macro(_) => HighlightTag::Macro, 712 Definition::Macro(_) => HighlightTag::Macro,
658 Definition::Field(_) => HighlightTag::Field, 713 Definition::Field(field) => {
714 let mut h = HighlightTag::Field.into();
715 if possibly_unsafe {
716 if let VariantDef::Union(_) = field.parent_def(db) {
717 h |= HighlightModifier::Unsafe;
718 }
719 }
720
721 return h;
722 }
659 Definition::ModuleDef(def) => match def { 723 Definition::ModuleDef(def) => match def {
660 hir::ModuleDef::Module(_) => HighlightTag::Module, 724 hir::ModuleDef::Module(_) => HighlightTag::Module,
661 hir::ModuleDef::Function(func) => { 725 hir::ModuleDef::Function(func) => {
662 let mut h = HighlightTag::Function.into(); 726 let mut h = HighlightTag::Function.into();
663 if func.is_unsafe(db) { 727 if func.is_unsafe(db) {
664 h |= HighlightModifier::Unsafe; 728 h |= HighlightModifier::Unsafe;
729 } else {
730 let is_unsafe = name_ref
731 .and_then(|name_ref| name_ref.syntax().parent())
732 .and_then(ast::MethodCallExpr::cast)
733 .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr))
734 .unwrap_or(false);
735 if is_unsafe {
736 h |= HighlightModifier::Unsafe;
737 }
665 } 738 }
666 return h; 739 return h;
667 } 740 }
@@ -677,6 +750,7 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight {
677 let mut h = Highlight::new(HighlightTag::Static); 750 let mut h = Highlight::new(HighlightTag::Static);
678 if s.is_mut(db) { 751 if s.is_mut(db) {
679 h |= HighlightModifier::Mutable; 752 h |= HighlightModifier::Mutable;
753 h |= HighlightModifier::Unsafe;
680 } 754 }
681 return h; 755 return h;
682 } 756 }
@@ -724,7 +798,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
724 tag.into() 798 tag.into()
725} 799}
726 800
727fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { 801fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
728 let default = HighlightTag::UnresolvedReference; 802 let default = HighlightTag::UnresolvedReference;
729 803
730 let parent = match name.syntax().parent() { 804 let parent = match name.syntax().parent() {
@@ -732,9 +806,36 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
732 _ => return default.into(), 806 _ => return default.into(),
733 }; 807 };
734 808
735 let tag = match parent.kind() { 809 match parent.kind() {
736 METHOD_CALL_EXPR => HighlightTag::Function, 810 METHOD_CALL_EXPR => {
737 FIELD_EXPR => HighlightTag::Field, 811 let mut h = Highlight::new(HighlightTag::Function);
812 let is_unsafe = ast::MethodCallExpr::cast(parent)
813 .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr))
814 .unwrap_or(false);
815 if is_unsafe {
816 h |= HighlightModifier::Unsafe;
817 }
818
819 h
820 }
821 FIELD_EXPR => {
822 let h = HighlightTag::Field;
823 let is_union = ast::FieldExpr::cast(parent)
824 .and_then(|field_expr| {
825 let field = sema.resolve_field(&field_expr)?;
826 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
827 true
828 } else {
829 false
830 })
831 })
832 .unwrap_or(false);
833 if is_union {
834 h | HighlightModifier::Unsafe
835 } else {
836 h.into()
837 }
838 }
738 PATH_SEGMENT => { 839 PATH_SEGMENT => {
739 let path = match parent.parent().and_then(ast::Path::cast) { 840 let path = match parent.parent().and_then(ast::Path::cast) {
740 Some(it) => it, 841 Some(it) => it,
@@ -758,18 +859,15 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
758 }; 859 };
759 860
760 match parent.kind() { 861 match parent.kind() {
761 CALL_EXPR => HighlightTag::Function, 862 CALL_EXPR => HighlightTag::Function.into(),
762 _ => { 863 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
763 if name.text().chars().next().unwrap_or_default().is_uppercase() { 864 HighlightTag::Struct.into()
764 HighlightTag::Struct 865 } else {
765 } else { 866 HighlightTag::Constant
766 HighlightTag::Constant
767 }
768 } 867 }
868 .into(),
769 } 869 }
770 } 870 }
771 _ => default, 871 _ => default.into(),
772 }; 872 }
773
774 tag.into()
775} 873}
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index 8665b480f..6046643ef 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -4,8 +4,8 @@ use std::{collections::BTreeMap, convert::TryFrom};
4 4
5use ast::{HasQuotes, HasStringValue}; 5use ast::{HasQuotes, HasStringValue};
6use hir::Semantics; 6use hir::Semantics;
7use itertools::Itertools;
7use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; 8use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
8use stdx::SepBy;
9 9
10use crate::{ 10use crate::{
11 call_info::ActiveParameter, Analysis, Highlight, HighlightModifier, HighlightTag, 11 call_info::ActiveParameter, Analysis, Highlight, HighlightModifier, HighlightTag,
@@ -129,8 +129,7 @@ pub(super) fn extract_doc_comments(
129 129
130 line[pos..].to_owned() 130 line[pos..].to_owned()
131 }) 131 })
132 .sep_by("\n") 132 .join("\n");
133 .to_string();
134 133
135 if doctest.is_empty() { 134 if doctest.is_empty() {
136 return None; 135 return None;
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 2deee404c..a8087635a 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -275,19 +275,64 @@ fn test_unsafe_highlighting() {
275 r#" 275 r#"
276unsafe fn unsafe_fn() {} 276unsafe fn unsafe_fn() {}
277 277
278union Union {
279 a: u32,
280 b: f32,
281}
282
278struct HasUnsafeFn; 283struct HasUnsafeFn;
279 284
280impl HasUnsafeFn { 285impl HasUnsafeFn {
281 unsafe fn unsafe_method(&self) {} 286 unsafe fn unsafe_method(&self) {}
282} 287}
283 288
289struct TypeForStaticMut {
290 a: u8
291}
292
293static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 };
294
295#[repr(packed)]
296struct Packed {
297 a: u16,
298}
299
300trait DoTheAutoref {
301 fn calls_autoref(&self);
302}
303
304impl DoTheAutoref for u16 {
305 fn calls_autoref(&self) {}
306}
307
284fn main() { 308fn main() {
285 let x = &5 as *const usize; 309 let x = &5 as *const _ as *const usize;
310 let u = Union { b: 0 };
286 unsafe { 311 unsafe {
312 // unsafe fn and method calls
287 unsafe_fn(); 313 unsafe_fn();
314 let b = u.b;
315 match u {
316 Union { b: 0 } => (),
317 Union { a } => (),
318 }
288 HasUnsafeFn.unsafe_method(); 319 HasUnsafeFn.unsafe_method();
289 let y = *(x); 320
290 let z = -x; 321 // unsafe deref
322 let y = *x;
323
324 // unsafe access to a static mut
325 let a = global_mut.a;
326
327 // unsafe ref of packed fields
328 let packed = Packed { a: 0 };
329 let a = &packed.a;
330 let ref a = packed.a;
331 let Packed { ref a } = packed;
332 let Packed { a: ref _a } = packed;
333
334 // unsafe auto ref of packed field
335 packed.a.calls_autoref();
291 } 336 }
292} 337}
293"# 338"#
@@ -373,6 +418,23 @@ macro_rules! noop {
373 ); 418 );
374} 419}
375 420
421#[test]
422fn test_extern_crate() {
423 check_highlighting(
424 r#"
425 //- /main.rs
426 extern crate std;
427 extern crate alloc as abc;
428 //- /std/lib.rs
429 pub struct S;
430 //- /alloc/lib.rs
431 pub struct A
432 "#,
433 expect_file!["crates/ra_ide/test_data/highlight_extern_crate.html"],
434 false,
435 );
436}
437
376/// Highlights the code given by the `ra_fixture` argument, renders the 438/// Highlights the code given by the `ra_fixture` argument, renders the
377/// result as HTML, and compares it with the HTML file given as `snapshot`. 439/// result as HTML, and compares it with the HTML file given as `snapshot`.
378/// Note that the `snapshot` file is overwritten by the rendered HTML. 440/// Note that the `snapshot` file is overwritten by the rendered HTML.
diff --git a/crates/ra_ide/test_data/highlight_extern_crate.html b/crates/ra_ide/test_data/highlight_extern_crate.html
new file mode 100644
index 000000000..800d894c7
--- /dev/null
+++ b/crates/ra_ide/test_data/highlight_extern_crate.html
@@ -0,0 +1,40 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
28.variable { color: #DCDCCC; }
29.format_specifier { color: #CC696B; }
30.mutable { text-decoration: underline; }
31.escape_sequence { color: #94BFF3; }
32.keyword { color: #F0DFAF; font-weight: bold; }
33.keyword.unsafe { color: #BC8383; font-weight: bold; }
34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
37</style>
38<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span>
39<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span>
40</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/test_data/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html
index b81b6f1c3..552fea668 100644
--- a/crates/ra_ide/test_data/highlight_unsafe.html
+++ b/crates/ra_ide/test_data/highlight_unsafe.html
@@ -37,18 +37,63 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
37</style> 37</style>
38<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 38<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
39 39
40<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span>
41 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span>
42 <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span>
43<span class="punctuation">}</span>
44
40<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> 45<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span>
41 46
42<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> 47<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span>
43 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 48 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
44<span class="punctuation">}</span> 49<span class="punctuation">}</span>
45 50
51<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span>
52 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u8</span>
53<span class="punctuation">}</span>
54
55<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
56
57<span class="attribute">#</span><span class="attribute">[</span><span class="function attribute">repr</span><span class="punctuation">(</span><span class="attribute">packed</span><span class="punctuation">)</span><span class="attribute">]</span>
58<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="punctuation">{</span>
59 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u16</span><span class="punctuation">,</span>
60<span class="punctuation">}</span>
61
62<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span>
63 <span class="keyword">fn</span> <span class="function declaration">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span><span class="punctuation">;</span>
64<span class="punctuation">}</span>
65
66<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="punctuation">{</span>
67 <span class="keyword">fn</span> <span class="function declaration">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
68<span class="punctuation">}</span>
69
46<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 70<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
47 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> 71 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span>
72 <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
48 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 73 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
74 <span class="comment">// unsafe fn and method calls</span>
49 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 75 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
76 <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="punctuation">.</span><span class="field unsafe">b</span><span class="punctuation">;</span>
77 <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span>
78 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
79 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
80 <span class="punctuation">}</span>
50 <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 81 <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
51 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="punctuation">(</span><span class="variable">x</span><span class="punctuation">)</span><span class="punctuation">;</span> 82
52 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="variable">x</span><span class="punctuation">;</span> 83 <span class="comment">// unsafe deref</span>
84 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="punctuation">;</span>
85
86 <span class="comment">// unsafe access to a static mut</span>
87 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">;</span>
88
89 <span class="comment">// unsafe ref of packed fields</span>
90 <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
91 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">;</span>
92 <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">;</span>
93 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span>
94 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span>
95
96 <span class="comment">// unsafe auto ref of packed field</span>
97 <span class="variable">packed</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">.</span><span class="function unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
53 <span class="punctuation">}</span> 98 <span class="punctuation">}</span>
54<span class="punctuation">}</span></code></pre> \ No newline at end of file 99<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/test_data/highlighting.html b/crates/ra_ide/test_data/highlighting.html
index 23c25ad8c..8e0160eee 100644
--- a/crates/ra_ide/test_data/highlighting.html
+++ b/crates/ra_ide/test_data/highlighting.html
@@ -64,7 +64,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
64 <span class="punctuation">}</span> 64 <span class="punctuation">}</span>
65<span class="punctuation">}</span> 65<span class="punctuation">}</span>
66 66
67<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 67<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span>
68 68
69<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">&lt;</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="punctuation">{</span> 69<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">&lt;</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="punctuation">{</span>
70 <span class="function">foo</span><span class="operator">::</span><span class="punctuation">&lt;</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> 70 <span class="function">foo</span><span class="operator">::</span><span class="punctuation">&lt;</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span>
@@ -97,7 +97,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
97 <span class="punctuation">}</span> 97 <span class="punctuation">}</span>
98 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 98 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
99 <span class="variable mutable">vec</span><span class="punctuation">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> 99 <span class="variable mutable">vec</span><span class="punctuation">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span>
100 <span class="static mutable">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> 100 <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span>
101 <span class="punctuation">}</span> 101 <span class="punctuation">}</span>
102 102
103 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> 103 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span>
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index b51000b03..9bb95277d 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -6,8 +6,8 @@
6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). 6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
7 7
8use hir::{ 8use hir::{
9 Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution, 9 db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef,
10 Semantics, TypeParam, Visibility, 10 Name, PathResolution, Semantics, TypeParam, Visibility,
11}; 11};
12use ra_prof::profile; 12use ra_prof::profile;
13use ra_syntax::{ 13use ra_syntax::{
@@ -80,6 +80,7 @@ impl Definition {
80 80
81#[derive(Debug)] 81#[derive(Debug)]
82pub enum NameClass { 82pub enum NameClass {
83 ExternCrate(Crate),
83 Definition(Definition), 84 Definition(Definition),
84 /// `None` in `if let None = Some(82) {}` 85 /// `None` in `if let None = Some(82) {}`
85 ConstReference(Definition), 86 ConstReference(Definition),
@@ -90,16 +91,18 @@ pub enum NameClass {
90} 91}
91 92
92impl NameClass { 93impl NameClass {
93 pub fn into_definition(self) -> Option<Definition> { 94 pub fn into_definition(self, db: &dyn HirDatabase) -> Option<Definition> {
94 match self { 95 Some(match self {
95 NameClass::Definition(it) => Some(it), 96 NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
96 NameClass::ConstReference(_) => None, 97 NameClass::Definition(it) => it,
97 NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)), 98 NameClass::ConstReference(_) => return None,
98 } 99 NameClass::FieldShorthand { local, field: _ } => Definition::Local(local),
100 })
99 } 101 }
100 102
101 pub fn definition(self) -> Definition { 103 pub fn definition(self, db: &dyn HirDatabase) -> Definition {
102 match self { 104 match self {
105 NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
103 NameClass::Definition(it) | NameClass::ConstReference(it) => it, 106 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
104 NameClass::FieldShorthand { local: _, field } => field, 107 NameClass::FieldShorthand { local: _, field } => field,
105 } 108 }
@@ -120,32 +123,37 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
120 match_ast! { 123 match_ast! {
121 match parent { 124 match parent {
122 ast::Rename(it) => { 125 ast::Rename(it) => {
123 let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?; 126 if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
124 let path = use_tree.path()?; 127 let path = use_tree.path()?;
125 let path_segment = path.segment()?; 128 let path_segment = path.segment()?;
126 let name_ref_class = path_segment 129 let name_ref_class = path_segment
127 .name_ref() 130 .name_ref()
128 // The rename might be from a `self` token, so fallback to the name higher 131 // The rename might be from a `self` token, so fallback to the name higher
129 // in the use tree. 132 // in the use tree.
130 .or_else(||{ 133 .or_else(||{
131 if path_segment.self_token().is_none() { 134 if path_segment.self_token().is_none() {
132 return None; 135 return None;
133 } 136 }
134 137
135 let use_tree = use_tree 138 let use_tree = use_tree
136 .syntax() 139 .syntax()
137 .parent() 140 .parent()
138 .as_ref() 141 .as_ref()
139 // Skip over UseTreeList 142 // Skip over UseTreeList
140 .and_then(SyntaxNode::parent) 143 .and_then(SyntaxNode::parent)
141 .and_then(ast::UseTree::cast)?; 144 .and_then(ast::UseTree::cast)?;
142 let path = use_tree.path()?; 145 let path = use_tree.path()?;
143 let path_segment = path.segment()?; 146 let path_segment = path.segment()?;
144 path_segment.name_ref() 147 path_segment.name_ref()
145 }) 148 })
146 .and_then(|name_ref| classify_name_ref(sema, &name_ref))?; 149 .and_then(|name_ref| classify_name_ref(sema, &name_ref))?;
147 150
148 Some(NameClass::Definition(name_ref_class.definition())) 151 Some(NameClass::Definition(name_ref_class.definition(sema.db)))
152 } else {
153 let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
154 let resolved = sema.resolve_extern_crate(&extern_crate)?;
155 Some(NameClass::ExternCrate(resolved))
156 }
149 }, 157 },
150 ast::IdentPat(it) => { 158 ast::IdentPat(it) => {
151 let local = sema.to_def(&it)?; 159 let local = sema.to_def(&it)?;
@@ -220,13 +228,15 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
220 228
221#[derive(Debug)] 229#[derive(Debug)]
222pub enum NameRefClass { 230pub enum NameRefClass {
231 ExternCrate(Crate),
223 Definition(Definition), 232 Definition(Definition),
224 FieldShorthand { local: Local, field: Definition }, 233 FieldShorthand { local: Local, field: Definition },
225} 234}
226 235
227impl NameRefClass { 236impl NameRefClass {
228 pub fn definition(self) -> Definition { 237 pub fn definition(self, db: &dyn HirDatabase) -> Definition {
229 match self { 238 match self {
239 NameRefClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
230 NameRefClass::Definition(def) => def, 240 NameRefClass::Definition(def) => def,
231 NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), 241 NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
232 } 242 }
@@ -307,9 +317,15 @@ pub fn classify_name_ref(
307 } 317 }
308 } 318 }
309 319
310 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; 320 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
311 let resolved = sema.resolve_path(&path)?; 321 if let Some(resolved) = sema.resolve_path(&path) {
312 Some(NameRefClass::Definition(resolved.into())) 322 return Some(NameRefClass::Definition(resolved.into()));
323 }
324 }
325
326 let extern_crate = ast::ExternCrate::cast(parent)?;
327 let resolved = sema.resolve_extern_crate(&extern_crate)?;
328 Some(NameRefClass::ExternCrate(resolved))
313} 329}
314 330
315impl From<PathResolution> for Definition { 331impl From<PathResolution> for Definition {
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
index 1fba71ff8..9e040973b 100644
--- a/crates/ra_ide_db/src/imports_locator.rs
+++ b/crates/ra_ide_db/src/imports_locator.rs
@@ -61,5 +61,5 @@ fn get_name_definition<'a>(
61 candidate_node 61 candidate_node
62 }; 62 };
63 let name = ast::Name::cast(candidate_name_node)?; 63 let name = ast::Name::cast(candidate_name_node)?;
64 classify_name(sema, &name)?.into_definition() 64 classify_name(sema, &name)?.into_definition(sema.db)
65} 65}
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index f9e515b81..933a3a3b5 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -276,7 +276,7 @@ impl<'a> TtIter<'a> {
276 Ok(tt::Subtree { 276 Ok(tt::Subtree {
277 delimiter: None, 277 delimiter: None,
278 token_trees: vec![ 278 token_trees: vec![
279 tt::Leaf::Punct(punct.clone()).into(), 279 tt::Leaf::Punct(*punct).into(),
280 tt::Leaf::Ident(ident.clone()).into(), 280 tt::Leaf::Ident(ident.clone()).into(),
281 ], 281 ],
282 } 282 }
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index c2e1d701e..88468bc97 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -110,7 +110,7 @@ pub(crate) mod fragments {
110 } 110 }
111 111
112 pub(crate) fn item(p: &mut Parser) { 112 pub(crate) fn item(p: &mut Parser) {
113 items::item_or_macro(p, true, items::ItemFlavor::Mod) 113 items::item_or_macro(p, true)
114 } 114 }
115 115
116 pub(crate) fn macro_items(p: &mut Parser) { 116 pub(crate) fn macro_items(p: &mut Parser) {
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index e1c25a838..3291e3f14 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -73,7 +73,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
73 73
74 // test block_items 74 // test block_items
75 // fn a() { fn b() {} } 75 // fn a() { fn b() {} }
76 let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { 76 let m = match items::maybe_item(p, m) {
77 Ok(()) => return, 77 Ok(()) => return,
78 Err(m) => m, 78 Err(m) => m,
79 }; 79 };
@@ -509,7 +509,6 @@ fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
509// x.1i32; 509// x.1i32;
510// x.0x01; 510// x.0x01;
511// } 511// }
512#[allow(clippy::if_same_then_else)]
513fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 512fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
514 assert!(p.at(T![.])); 513 assert!(p.at(T![.]));
515 let m = lhs.precede(p); 514 let m = lhs.precede(p);
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index cca524cea..d091b0fbb 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -22,24 +22,19 @@ use super::*;
22pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { 22pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
23 attributes::inner_attributes(p); 23 attributes::inner_attributes(p);
24 while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) { 24 while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) {
25 item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod) 25 item_or_macro(p, stop_on_r_curly)
26 } 26 }
27} 27}
28 28
29pub(super) enum ItemFlavor {
30 Mod,
31 Trait,
32}
33
34pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ 29pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
35 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, 30 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
36 CRATE_KW, USE_KW, MACRO_KW 31 CRATE_KW, USE_KW, MACRO_KW
37]; 32];
38 33
39pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { 34pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
40 let m = p.start(); 35 let m = p.start();
41 attributes::outer_attributes(p); 36 attributes::outer_attributes(p);
42 let m = match maybe_item(p, m, flavor) { 37 let m = match maybe_item(p, m) {
43 Ok(()) => { 38 Ok(()) => {
44 if p.at(T![;]) { 39 if p.at(T![;]) {
45 p.err_and_bump( 40 p.err_and_bump(
@@ -76,7 +71,7 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
76 } 71 }
77} 72}
78 73
79pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Result<(), Marker> { 74pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
80 // test_err pub_expr 75 // test_err pub_expr
81 // fn foo() { pub 92; } 76 // fn foo() { pub 92; }
82 let has_visibility = opt_visibility(p); 77 let has_visibility = opt_visibility(p);
@@ -114,38 +109,31 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
114 has_mods = true; 109 has_mods = true;
115 } 110 }
116 111
117 if p.at(IDENT) 112 // test default_item
118 && p.at_contextual_kw("default") 113 // default impl T for Foo {}
119 && (match p.nth(1) { 114 if p.at(IDENT) && p.at_contextual_kw("default") {
120 T![impl] => true, 115 match p.nth(1) {
116 T![fn] | T![type] | T![const] | T![impl] => {
117 p.bump_remap(T![default]);
118 has_mods = true;
119 }
121 T![unsafe] => { 120 T![unsafe] => {
122 // test default_unsafe_impl 121 // test default_unsafe_item
123 // default unsafe impl Foo {} 122 // default unsafe impl T for Foo {
124
125 // test default_unsafe_fn
126 // impl T for Foo {
127 // default unsafe fn foo() {} 123 // default unsafe fn foo() {}
128 // } 124 // }
129 if p.nth(2) == T![impl] || p.nth(2) == T![fn] { 125 if matches!(p.nth(2), T![impl] | T![fn]) {
130 p.bump_remap(T![default]); 126 p.bump_remap(T![default]);
131 p.bump(T![unsafe]); 127 p.bump(T![unsafe]);
132 has_mods = true; 128 has_mods = true;
133 } 129 }
134 false
135 } 130 }
136 T![fn] | T![type] | T![const] => { 131 _ => (),
137 if let ItemFlavor::Mod = flavor { 132 }
138 true
139 } else {
140 false
141 }
142 }
143 _ => false,
144 })
145 {
146 p.bump_remap(T![default]);
147 has_mods = true;
148 } 133 }
134
135 // test existential_type
136 // existential type Foo: Fn() -> usize;
149 if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] { 137 if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] {
150 p.bump_remap(T![existential]); 138 p.bump_remap(T![existential]);
151 has_mods = true; 139 has_mods = true;
@@ -153,79 +141,31 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
153 141
154 // items 142 // items
155 match p.current() { 143 match p.current() {
156 // test async_fn 144 // test fn
157 // async fn foo() {} 145 // fn foo() {}
158
159 // test extern_fn
160 // extern fn foo() {}
161
162 // test const_fn
163 // const fn foo() {}
164
165 // test const_unsafe_fn
166 // const unsafe fn foo() {}
167
168 // test unsafe_extern_fn
169 // unsafe extern "C" fn foo() {}
170
171 // test unsafe_fn
172 // unsafe fn foo() {}
173
174 // test combined_fns
175 // async unsafe fn foo() {}
176 // const unsafe fn bar() {}
177
178 // test_err wrong_order_fns
179 // unsafe async fn foo() {}
180 // unsafe const fn bar() {}
181 T![fn] => { 146 T![fn] => {
182 fn_def(p); 147 fn_def(p);
183 m.complete(p, FN); 148 m.complete(p, FN);
184 } 149 }
185 150
186 // test unsafe_trait 151 // test trait
187 // unsafe trait T {} 152 // trait T {}
188
189 // test auto_trait
190 // auto trait T {}
191
192 // test unsafe_auto_trait
193 // unsafe auto trait T {}
194 T![trait] => { 153 T![trait] => {
195 traits::trait_def(p); 154 traits::trait_def(p);
196 m.complete(p, TRAIT); 155 m.complete(p, TRAIT);
197 } 156 }
198 157
199 // test unsafe_impl
200 // unsafe impl Foo {}
201
202 // test default_impl
203 // default impl Foo {}
204
205 // test_err default_fn_type
206 // trait T {
207 // default type T = Bar;
208 // default fn foo() {}
209 // }
210
211 // test default_fn_type
212 // impl T for Foo {
213 // default type T = Bar;
214 // default fn foo() {}
215 // }
216 T![const] => { 158 T![const] => {
217 consts::const_def(p, m); 159 consts::const_def(p, m);
218 } 160 }
219 161
220 // test unsafe_default_impl 162 // test impl
221 // unsafe default impl Foo {} 163 // impl T for S {}
222 T![impl] => { 164 T![impl] => {
223 traits::impl_def(p); 165 traits::impl_def(p);
224 m.complete(p, IMPL); 166 m.complete(p, IMPL);
225 } 167 }
226 168
227 // test existential_type
228 // existential type Foo: Fn() -> usize;
229 T![type] => { 169 T![type] => {
230 type_def(p, m); 170 type_def(p, m);
231 } 171 }
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
index ef9c8ff5b..751ce65f2 100644
--- a/crates/ra_parser/src/grammar/items/traits.rs
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -47,7 +47,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) {
47 error_block(p, "expected an item"); 47 error_block(p, "expected an item");
48 continue; 48 continue;
49 } 49 }
50 item_or_macro(p, true, ItemFlavor::Trait); 50 item_or_macro(p, true);
51 } 51 }
52 p.expect(T!['}']); 52 p.expect(T!['}']);
53 m.complete(p, ASSOC_ITEM_LIST); 53 m.complete(p, ASSOC_ITEM_LIST);
@@ -104,7 +104,7 @@ pub(crate) fn impl_item_list(p: &mut Parser) {
104 error_block(p, "expected an item"); 104 error_block(p, "expected an item");
105 continue; 105 continue;
106 } 106 }
107 item_or_macro(p, true, ItemFlavor::Mod); 107 item_or_macro(p, true);
108 } 108 }
109 p.expect(T!['}']); 109 p.expect(T!['}']);
110 m.complete(p, ASSOC_ITEM_LIST); 110 m.complete(p, ASSOC_ITEM_LIST);
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index d797f2cc9..d2487acc3 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -269,8 +269,8 @@ impl Marker {
269 pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { 269 pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
270 self.bomb.defuse(); 270 self.bomb.defuse();
271 let idx = self.pos as usize; 271 let idx = self.pos as usize;
272 match p.events[idx] { 272 match &mut p.events[idx] {
273 Event::Start { kind: ref mut slot, .. } => { 273 Event::Start { kind: slot, .. } => {
274 *slot = kind; 274 *slot = kind;
275 } 275 }
276 _ => unreachable!(), 276 _ => unreachable!(),
@@ -320,8 +320,8 @@ impl CompletedMarker {
320 pub(crate) fn precede(self, p: &mut Parser) -> Marker { 320 pub(crate) fn precede(self, p: &mut Parser) -> Marker {
321 let new_pos = p.start(); 321 let new_pos = p.start();
322 let idx = self.start_pos as usize; 322 let idx = self.start_pos as usize;
323 match p.events[idx] { 323 match &mut p.events[idx] {
324 Event::Start { ref mut forward_parent, .. } => { 324 Event::Start { forward_parent, .. } => {
325 *forward_parent = Some(new_pos.pos - self.start_pos); 325 *forward_parent = Some(new_pos.pos - self.start_pos);
326 } 326 }
327 _ => unreachable!(), 327 _ => unreachable!(),
@@ -333,12 +333,12 @@ impl CompletedMarker {
333 pub(crate) fn undo_completion(self, p: &mut Parser) -> Marker { 333 pub(crate) fn undo_completion(self, p: &mut Parser) -> Marker {
334 let start_idx = self.start_pos as usize; 334 let start_idx = self.start_pos as usize;
335 let finish_idx = self.finish_pos as usize; 335 let finish_idx = self.finish_pos as usize;
336 match p.events[start_idx] { 336 match &mut p.events[start_idx] {
337 Event::Start { ref mut kind, forward_parent: None } => *kind = TOMBSTONE, 337 Event::Start { kind, forward_parent: None } => *kind = TOMBSTONE,
338 _ => unreachable!(), 338 _ => unreachable!(),
339 } 339 }
340 match p.events[finish_idx] { 340 match &mut p.events[finish_idx] {
341 ref mut slot @ Event::Finish => *slot = Event::tombstone(), 341 slot @ Event::Finish => *slot = Event::tombstone(),
342 _ => unreachable!(), 342 _ => unreachable!(),
343 } 343 }
344 Marker::new(self.start_pos) 344 Marker::new(self.start_pos)
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs
index 5bcdacb48..37dd3f496 100644
--- a/crates/ra_proc_macro/src/process.rs
+++ b/crates/ra_proc_macro/src/process.rs
@@ -90,7 +90,7 @@ impl ProcMacroProcessSrv {
90 } 90 }
91 Some(it) => it, 91 Some(it) => it,
92 }; 92 };
93 sender.send(Task { req: req.into(), result_tx }).unwrap(); 93 sender.send(Task { req, result_tx }).unwrap();
94 let res = result_rx 94 let res = result_rx
95 .recv() 95 .recv()
96 .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?; 96 .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs
index c2ecbd33c..83390212a 100644
--- a/crates/ra_prof/src/memory_usage.rs
+++ b/crates/ra_prof/src/memory_usage.rs
@@ -24,7 +24,7 @@ impl std::ops::Sub for MemoryUsage {
24impl MemoryUsage { 24impl MemoryUsage {
25 pub fn current() -> MemoryUsage { 25 pub fn current() -> MemoryUsage {
26 cfg_if! { 26 cfg_if! {
27 if #[cfg(target_os = "linux")] { 27 if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
28 // Note: This is incredibly slow. 28 // Note: This is incredibly slow.
29 let alloc = unsafe { libc::mallinfo() }.uordblks as isize; 29 let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
30 MemoryUsage { allocated: Bytes(alloc) } 30 MemoryUsage { allocated: Bytes(alloc) }
diff --git a/crates/ra_ssr/src/resolving.rs b/crates/ra_ssr/src/resolving.rs
index df60048eb..d53bd46c7 100644
--- a/crates/ra_ssr/src/resolving.rs
+++ b/crates/ra_ssr/src/resolving.rs
@@ -5,7 +5,7 @@ use crate::{parsing, SsrError};
5use parsing::Placeholder; 5use parsing::Placeholder;
6use ra_db::FilePosition; 6use ra_db::FilePosition;
7use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; 7use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken};
8use rustc_hash::{FxHashMap, FxHashSet}; 8use rustc_hash::FxHashMap;
9use test_utils::mark; 9use test_utils::mark;
10 10
11pub(crate) struct ResolutionScope<'db> { 11pub(crate) struct ResolutionScope<'db> {
@@ -124,8 +124,10 @@ impl Resolver<'_, '_> {
124 .resolution_scope 124 .resolution_scope
125 .resolve_path(&path) 125 .resolve_path(&path)
126 .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?; 126 .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?;
127 resolved_paths.insert(node, ResolvedPath { resolution, depth }); 127 if self.ok_to_use_path_resolution(&resolution) {
128 return Ok(()); 128 resolved_paths.insert(node, ResolvedPath { resolution, depth });
129 return Ok(());
130 }
129 } 131 }
130 } 132 }
131 for node in node.children() { 133 for node in node.children() {
@@ -149,6 +151,27 @@ impl Resolver<'_, '_> {
149 } 151 }
150 false 152 false
151 } 153 }
154
155 fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool {
156 match resolution {
157 hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) => {
158 if function.has_self_param(self.resolution_scope.scope.db) {
159 // If we don't use this path resolution, then we won't be able to match method
160 // calls. e.g. `Foo::bar($s)` should match `x.bar()`.
161 true
162 } else {
163 mark::hit!(replace_associated_trait_default_function_call);
164 false
165 }
166 }
167 hir::PathResolution::AssocItem(_) => {
168 // Not a function. Could be a constant or an associated type.
169 mark::hit!(replace_associated_trait_constant);
170 false
171 }
172 _ => true,
173 }
174 }
152} 175}
153 176
154impl<'db> ResolutionScope<'db> { 177impl<'db> ResolutionScope<'db> {
@@ -195,7 +218,7 @@ impl<'db> ResolutionScope<'db> {
195 adt.ty(self.scope.db).iterate_path_candidates( 218 adt.ty(self.scope.db).iterate_path_candidates(
196 self.scope.db, 219 self.scope.db,
197 self.scope.module()?.krate(), 220 self.scope.module()?.krate(),
198 &FxHashSet::default(), 221 &self.scope.traits_in_scope(),
199 Some(hir_path.segments().last()?.name), 222 Some(hir_path.segments().last()?.name),
200 |_ty, assoc_item| Some(hir::PathResolution::AssocItem(assoc_item)), 223 |_ty, assoc_item| Some(hir::PathResolution::AssocItem(assoc_item)),
201 ) 224 )
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index d483640df..7d4d470c0 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -550,6 +550,70 @@ fn replace_associated_function_call() {
550} 550}
551 551
552#[test] 552#[test]
553fn replace_associated_trait_default_function_call() {
554 mark::check!(replace_associated_trait_default_function_call);
555 assert_ssr_transform(
556 "Bar2::foo() ==>> Bar2::foo2()",
557 r#"
558 trait Foo { fn foo() {} }
559 pub struct Bar {}
560 impl Foo for Bar {}
561 pub struct Bar2 {}
562 impl Foo for Bar2 {}
563 impl Bar2 { fn foo2() {} }
564 fn main() {
565 Bar::foo();
566 Bar2::foo();
567 }
568 "#,
569 expect![[r#"
570 trait Foo { fn foo() {} }
571 pub struct Bar {}
572 impl Foo for Bar {}
573 pub struct Bar2 {}
574 impl Foo for Bar2 {}
575 impl Bar2 { fn foo2() {} }
576 fn main() {
577 Bar::foo();
578 Bar2::foo2();
579 }
580 "#]],
581 );
582}
583
584#[test]
585fn replace_associated_trait_constant() {
586 mark::check!(replace_associated_trait_constant);
587 assert_ssr_transform(
588 "Bar2::VALUE ==>> Bar2::VALUE_2222",
589 r#"
590 trait Foo { const VALUE: i32; const VALUE_2222: i32; }
591 pub struct Bar {}
592 impl Foo for Bar { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; }
593 pub struct Bar2 {}
594 impl Foo for Bar2 { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; }
595 impl Bar2 { fn foo2() {} }
596 fn main() {
597 Bar::VALUE;
598 Bar2::VALUE;
599 }
600 "#,
601 expect![[r#"
602 trait Foo { const VALUE: i32; const VALUE_2222: i32; }
603 pub struct Bar {}
604 impl Foo for Bar { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; }
605 pub struct Bar2 {}
606 impl Foo for Bar2 { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; }
607 impl Bar2 { fn foo2() {} }
608 fn main() {
609 Bar::VALUE;
610 Bar2::VALUE_2222;
611 }
612 "#]],
613 );
614}
615
616#[test]
553fn replace_path_in_different_contexts() { 617fn replace_path_in_different_contexts() {
554 // Note the <|> inside module a::b which marks the point where the rule is interpreted. We 618 // Note the <|> inside module a::b which marks the point where the rule is interpreted. We
555 // replace foo with bar, but both need different path qualifiers in different contexts. In f4, 619 // replace foo with bar, but both need different path qualifiers in different contexts. In f4,
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index 3a56b1674..0bdc22d95 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -1,7 +1,7 @@
1//! Various traits that are implemented by ast nodes. 1//! Various traits that are implemented by ast nodes.
2//! 2//!
3//! The implementations are usually trivial, and live in generated.rs 3//! The implementations are usually trivial, and live in generated.rs
4use stdx::SepBy; 4use itertools::Itertools;
5 5
6use crate::{ 6use crate::{
7 ast::{self, support, AstChildren, AstNode, AstToken}, 7 ast::{self, support, AstChildren, AstNode, AstToken},
@@ -119,8 +119,7 @@ impl CommentIter {
119 // of a line in markdown. 119 // of a line in markdown.
120 line[pos..end].to_owned() 120 line[pos..end].to_owned()
121 }) 121 })
122 .sep_by("\n") 122 .join("\n");
123 .to_string();
124 123
125 if has_comments { 124 if has_comments {
126 Some(docs) 125 Some(docs)
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
deleted file mode 100644
index 51ad2a846..000000000
--- a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast
+++ /dev/null
@@ -1,40 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "trait"
4 [email protected] " "
5 [email protected]
6 [email protected] "T"
7 [email protected] " "
8 [email protected]
9 [email protected] "{"
10 [email protected] "\n "
11 [email protected]
12 [email protected]
13 [email protected]
14 [email protected]
15 [email protected] "default"
16 [email protected] " "
17 [email protected]
18 [email protected] "const"
19 [email protected] " "
20 [email protected]
21 [email protected] "f"
22 [email protected] ":"
23 [email protected] " "
24 [email protected]
25 [email protected]
26 [email protected]
27 [email protected]
28 [email protected] "u8"
29 [email protected] " "
30 [email protected] "="
31 [email protected] " "
32 [email protected]
33 [email protected] "0"
34 [email protected] ";"
35 [email protected] "\n"
36 [email protected] "}"
37 [email protected] "\n"
38error 19..19: expected BANG
39error 19..19: expected `{`, `[`, `(`
40error 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
deleted file mode 100644
index 80f15474a..000000000
--- a/crates/ra_syntax/test_data/parser/err/0043_default_const.rs
+++ /dev/null
@@ -1,3 +0,0 @@
1trait T {
2 default const f: u8 = 0;
3}
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rast
index df29017e7..df29017e7 100644
--- a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast
+++ b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rast
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rs
index 8fa324c1a..8fa324c1a 100644
--- a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs
+++ b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rs
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rast
index a6e6552a9..a6e6552a9 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast
+++ b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rast
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rs
index 731e58013..731e58013 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs
+++ b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rs
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast
deleted file mode 100644
index acd72094b..000000000
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast
+++ /dev/null
@@ -1,58 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "trait"
4 [email protected] " "
5 [email protected]
6 [email protected] "T"
7 [email protected] " "
8 [email protected]
9 [email protected] "{"
10 [email protected] "\n "
11 [email protected]
12 [email protected]
13 [email protected]
14 [email protected]
15 [email protected] "default"
16 [email protected] " "
17 [email protected]
18 [email protected] "type"
19 [email protected] " "
20 [email protected]
21 [email protected] "T"
22 [email protected] " "
23 [email protected] "="
24 [email protected] " "
25 [email protected]
26 [email protected]
27 [email protected]
28 [email protected]
29 [email protected] "Bar"
30 [email protected] ";"
31 [email protected] "\n "
32 [email protected]
33 [email protected]
34 [email protected]
35 [email protected]
36 [email protected] "default"
37 [email protected] " "
38 [email protected]
39 [email protected] "fn"
40 [email protected] " "
41 [email protected]
42 [email protected] "foo"
43 [email protected]
44 [email protected] "("
45 [email protected] ")"
46 [email protected] " "
47 [email protected]
48 [email protected] "{"
49 [email protected] "}"
50 [email protected] "\n"
51 [email protected] "}"
52 [email protected] "\n"
53error 21..21: expected BANG
54error 21..21: expected `{`, `[`, `(`
55error 21..21: expected SEMICOLON
56error 47..47: expected BANG
57error 47..47: expected `{`, `[`, `(`
58error 47..47: expected SEMICOLON
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs
deleted file mode 100644
index 15ba8f4a8..000000000
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs
+++ /dev/null
@@ -1,4 +0,0 @@
1trait T {
2 default type T = Bar;
3 default fn foo() {}
4}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast
deleted file mode 100644
index 625ab4c2d..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast
+++ /dev/null
@@ -1,13 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "unsafe"
4 [email protected] " "
5 [email protected] "trait"
6 [email protected] " "
7 [email protected]
8 [email protected] "T"
9 [email protected] " "
10 [email protected]
11 [email protected] "{"
12 [email protected] "}"
13 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs
deleted file mode 100644
index 04e021550..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs
+++ /dev/null
@@ -1 +0,0 @@
1unsafe trait T {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast
deleted file mode 100644
index 293b1d64c..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast
+++ /dev/null
@@ -1,21 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "unsafe"
4 [email protected] " "
5 [email protected]
6 [email protected] "extern"
7 [email protected] " "
8 [email protected] "\"C\""
9 [email protected] " "
10 [email protected] "fn"
11 [email protected] " "
12 [email protected]
13 [email protected] "foo"
14 [email protected]
15 [email protected] "("
16 [email protected] ")"
17 [email protected] " "
18 [email protected]
19 [email protected] "{"
20 [email protected] "}"
21 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs
deleted file mode 100644
index 1295c2cd2..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
1unsafe extern "C" fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast
deleted file mode 100644
index d6dfa83b7..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast
+++ /dev/null
@@ -1,18 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "unsafe"
4 [email protected] " "
5 [email protected] "default"
6 [email protected] " "
7 [email protected] "impl"
8 [email protected] " "
9 [email protected]
10 [email protected]
11 [email protected]
12 [email protected]
13 [email protected] "Foo"
14 [email protected] " "
15 [email protected]
16 [email protected] "{"
17 [email protected] "}"
18 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs
deleted file mode 100644
index 9cd6c57bd..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs
+++ /dev/null
@@ -1 +0,0 @@
1unsafe default impl Foo {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast
deleted file mode 100644
index 97548a5ee..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast
+++ /dev/null
@@ -1,16 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "const"
4 [email protected] " "
5 [email protected] "fn"
6 [email protected] " "
7 [email protected]
8 [email protected] "foo"
9 [email protected]
10 [email protected] "("
11 [email protected] ")"
12 [email protected] " "
13 [email protected]
14 [email protected] "{"
15 [email protected] "}"
16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs
deleted file mode 100644
index 8c84d9cd7..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
1const fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast
deleted file mode 100644
index 43c09affe..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast
+++ /dev/null
@@ -1,16 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "unsafe"
4 [email protected] " "
5 [email protected] "impl"
6 [email protected] " "
7 [email protected]
8 [email protected]
9 [email protected]
10 [email protected]
11 [email protected] "Foo"
12 [email protected] " "
13 [email protected]
14 [email protected] "{"
15 [email protected] "}"
16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs
deleted file mode 100644
index 41055f41d..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs
+++ /dev/null
@@ -1 +0,0 @@
1unsafe impl Foo {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast
deleted file mode 100644
index 405b6a259..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast
+++ /dev/null
@@ -1,17 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected] "extern"
5 [email protected] " "
6 [email protected] "fn"
7 [email protected] " "
8 [email protected]
9 [email protected] "foo"
10 [email protected]
11 [email protected] "("
12 [email protected] ")"
13 [email protected] " "
14 [email protected]
15 [email protected] "{"
16 [email protected] "}"
17 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs
deleted file mode 100644
index 394a049f0..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
1extern fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast
deleted file mode 100644
index 0cac9ac43..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast
+++ /dev/null
@@ -1,13 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "auto"
4 [email protected] " "
5 [email protected] "trait"
6 [email protected] " "
7 [email protected]
8 [email protected] "T"
9 [email protected] " "
10 [email protected]
11 [email protected] "{"
12 [email protected] "}"
13 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs
deleted file mode 100644
index 72adf6035..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs
+++ /dev/null
@@ -1 +0,0 @@
1auto trait T {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast
deleted file mode 100644
index 0ef11c682..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast
+++ /dev/null
@@ -1,15 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "unsafe"
4 [email protected] " "
5 [email protected] "auto"
6 [email protected] " "
7 [email protected] "trait"
8 [email protected] " "
9 [email protected]
10 [email protected] "T"
11 [email protected] " "
12 [email protected]
13 [email protected] "{"
14 [email protected] "}"
15 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs
deleted file mode 100644
index 03d29f324..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs
+++ /dev/null
@@ -1 +0,0 @@
1unsafe auto trait T {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast
deleted file mode 100644
index 0a1b21d6e..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast
+++ /dev/null
@@ -1,16 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "default"
4 [email protected] " "
5 [email protected] "impl"
6 [email protected] " "
7 [email protected]
8 [email protected]
9 [email protected]
10 [email protected]
11 [email protected] "Foo"
12 [email protected] " "
13 [email protected]
14 [email protected] "{"
15 [email protected] "}"
16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs
deleted file mode 100644
index ef6aa84a2..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs
+++ /dev/null
@@ -1 +0,0 @@
1default impl Foo {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast
deleted file mode 100644
index 32a77ba49..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast
+++ /dev/null
@@ -1,18 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "const"
4 [email protected] " "
5 [email protected] "unsafe"
6 [email protected] " "
7 [email protected] "fn"
8 [email protected] " "
9 [email protected]
10 [email protected] "foo"
11 [email protected]
12 [email protected] "("
13 [email protected] ")"
14 [email protected] " "
15 [email protected]
16 [email protected] "{"
17 [email protected] "}"
18 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs
deleted file mode 100644
index 31a1e435f..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
1const unsafe fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast
deleted file mode 100644
index 73c94e5d4..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast
+++ /dev/null
@@ -1,16 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "unsafe"
4 [email protected] " "
5 [email protected] "fn"
6 [email protected] " "
7 [email protected]
8 [email protected] "foo"
9 [email protected]
10 [email protected] "("
11 [email protected] ")"
12 [email protected] " "
13 [email protected]
14 [email protected] "{"
15 [email protected] "}"
16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs
deleted file mode 100644
index 33cfc4cd7..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
1unsafe fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast
deleted file mode 100644
index a7df188bd..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast
+++ /dev/null
@@ -1,16 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "async"
4 [email protected] " "
5 [email protected] "fn"
6 [email protected] " "
7 [email protected]
8 [email protected] "foo"
9 [email protected]
10 [email protected] "("
11 [email protected] ")"
12 [email protected] " "
13 [email protected]
14 [email protected] "{"
15 [email protected] "}"
16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs
deleted file mode 100644
index f4adcb62b..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
1async fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast
deleted file mode 100644
index 98a20f36d..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast
+++ /dev/null
@@ -1,35 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "async"
4 [email protected] " "
5 [email protected] "unsafe"
6 [email protected] " "
7 [email protected] "fn"
8 [email protected] " "
9 [email protected]
10 [email protected] "foo"
11 [email protected]
12 [email protected] "("
13 [email protected] ")"
14 [email protected] " "
15 [email protected]
16 [email protected] "{"
17 [email protected] "}"
18 [email protected] "\n"
19 [email protected]
20 [email protected] "const"
21 [email protected] " "
22 [email protected] "unsafe"
23 [email protected] " "
24 [email protected] "fn"
25 [email protected] " "
26 [email protected]
27 [email protected] "bar"
28 [email protected]
29 [email protected] "("
30 [email protected] ")"
31 [email protected] " "
32 [email protected]
33 [email protected] "{"
34 [email protected] "}"
35 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs
deleted file mode 100644
index 126287145..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs
+++ /dev/null
@@ -1,2 +0,0 @@
1async unsafe fn foo() {}
2const unsafe fn bar() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast
deleted file mode 100644
index b8d26a53a..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast
+++ /dev/null
@@ -1,55 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "impl"
4 [email protected] " "
5 [email protected]
6 [email protected]
7 [email protected]
8 [email protected]
9 [email protected] "T"
10 [email protected] " "
11 [email protected] "for"
12 [email protected] " "
13 [email protected]
14 [email protected]
15 [email protected]
16 [email protected]
17 [email protected] "Foo"
18 [email protected] " "
19 [email protected]
20 [email protected] "{"
21 [email protected] "\n "
22 [email protected]
23 [email protected] "default"
24 [email protected] " "
25 [email protected] "type"
26 [email protected] " "
27 [email protected]
28 [email protected] "T"
29 [email protected] " "
30 [email protected] "="
31 [email protected] " "
32 [email protected]
33 [email protected]
34 [email protected]
35 [email protected]
36 [email protected] "Bar"
37 [email protected] ";"
38 [email protected] "\n "
39 [email protected]
40 [email protected] "default"
41 [email protected] " "
42 [email protected] "fn"
43 [email protected] " "
44 [email protected]
45 [email protected] "foo"
46 [email protected]
47 [email protected] "("
48 [email protected] ")"
49 [email protected] " "
50 [email protected]
51 [email protected] "{"
52 [email protected] "}"
53 [email protected] "\n"
54 [email protected] "}"
55 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs b/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs
deleted file mode 100644
index 8f5d61113..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs
+++ /dev/null
@@ -1,4 +0,0 @@
1impl T for Foo {
2 default type T = Bar;
3 default fn foo() {}
4}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast
new file mode 100644
index 000000000..23c4269b3
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast
@@ -0,0 +1,14 @@
1[email protected]
2 [email protected]
3 [email protected] "fn"
4 [email protected] " "
5 [email protected]
6 [email protected] "foo"
7 [email protected]
8 [email protected] "("
9 [email protected] ")"
10 [email protected] " "
11 [email protected]
12 [email protected] "{"
13 [email protected] "}"
14 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs
new file mode 100644
index 000000000..8f3b7ef11
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs
@@ -0,0 +1 @@
fn foo() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast
new file mode 100644
index 000000000..7968cf9ff
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast
@@ -0,0 +1,22 @@
1[email protected]
2 [email protected]
3 [email protected] "impl"
4 [email protected] " "
5 [email protected]
6 [email protected]
7 [email protected]
8 [email protected]
9 [email protected] "T"
10 [email protected] " "
11 [email protected] "for"
12 [email protected] " "
13 [email protected]
14 [email protected]
15 [email protected]
16 [email protected]
17 [email protected] "S"
18 [email protected] " "
19 [email protected]
20 [email protected] "{"
21 [email protected] "}"
22 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs
new file mode 100644
index 000000000..a1a550d8a
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs
@@ -0,0 +1 @@
impl T for S {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast
new file mode 100644
index 000000000..9881e5048
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast
@@ -0,0 +1,11 @@
1[email protected]
2 [email protected]
3 [email protected] "trait"
4 [email protected] " "
5 [email protected]
6 [email protected] "T"
7 [email protected] " "
8 [email protected]
9 [email protected] "{"
10 [email protected] "}"
11 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs
new file mode 100644
index 000000000..8d183dbb5
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs
@@ -0,0 +1 @@
trait T {}
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
deleted file mode 100644
index 1269621dc..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
+++ /dev/null
@@ -1,40 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "impl"
4 [email protected] " "
5 [email protected]
6 [email protected]
7 [email protected]
8 [email protected]
9 [email protected] "T"
10 [email protected] " "
11 [email protected] "for"
12 [email protected] " "
13 [email protected]
14 [email protected]
15 [email protected]
16 [email protected]
17 [email protected] "Foo"
18 [email protected] " "
19 [email protected]
20 [email protected] "{"
21 [email protected] "\n "
22 [email protected]
23 [email protected] "default"
24 [email protected] " "
25 [email protected] "unsafe"
26 [email protected] " "
27 [email protected] "fn"
28 [email protected] " "
29 [email protected]
30 [email protected] "foo"
31 [email protected]
32 [email protected] "("
33 [email protected] ")"
34 [email protected] " "
35 [email protected]
36 [email protected] "{"
37 [email protected] "}"
38 [email protected] "\n"
39 [email protected] "}"
40 [email protected] "\n"
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
deleted file mode 100644
index 6bfe925af..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast
+++ /dev/null
@@ -1,18 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "default"
4 [email protected] " "
5 [email protected] "unsafe"
6 [email protected] " "
7 [email protected] "impl"
8 [email protected] " "
9 [email protected]
10 [email protected]
11 [email protected]
12 [email protected]
13 [email protected] "Foo"
14 [email protected] " "
15 [email protected]
16 [email protected] "{"
17 [email protected] "}"
18 [email protected] "\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
deleted file mode 100644
index ba0998ff4..000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs
+++ /dev/null
@@ -1 +0,0 @@
1default unsafe impl Foo {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast
new file mode 100644
index 000000000..f2e201460
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast
@@ -0,0 +1,44 @@
1[email protected]
2 [email protected]
3 [email protected] "default"
4 [email protected] " "
5 [email protected] "unsafe"
6 [email protected] " "
7 [email protected] "impl"
8 [email protected] " "
9 [email protected]
10 [email protected]
11 [email protected]
12 [email protected]
13 [email protected] "T"
14 [email protected] " "
15 [email protected] "for"
16 [email protected] " "
17 [email protected]
18 [email protected]
19 [email protected]
20 [email protected]
21 [email protected] "Foo"
22 [email protected] " "
23 [email protected]
24 [email protected] "{"
25 [email protected] "\n "
26 [email protected]
27 [email protected] "default"
28 [email protected] " "
29 [email protected] "unsafe"
30 [email protected] " "
31 [email protected] "fn"
32 [email protected] " "
33 [email protected]
34 [email protected] "foo"
35 [email protected]
36 [email protected] "("
37 [email protected] ")"
38 [email protected] " "
39 [email protected]
40 [email protected] "{"
41 [email protected] "}"
42 [email protected] "\n"
43 [email protected] "}"
44 [email protected] "\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_item.rs
index 12926cd8a..96340f84a 100644
--- 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_item.rs
@@ -1,3 +1,3 @@
1impl T for Foo { 1default unsafe impl T for Foo {
2 default unsafe fn foo() {} 2 default unsafe fn foo() {}
3} 3}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast
new file mode 100644
index 000000000..9282772f3
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast
@@ -0,0 +1,24 @@
1[email protected]
2 [email protected]
3 [email protected] "default"
4 [email protected] " "
5 [email protected] "impl"
6 [email protected] " "
7 [email protected]
8 [email protected]
9 [email protected]
10 [email protected]
11 [email protected] "T"
12 [email protected] " "
13 [email protected] "for"
14 [email protected] " "
15 [email protected]
16 [email protected]
17 [email protected]
18 [email protected]
19 [email protected] "Foo"
20 [email protected] " "
21 [email protected]
22 [email protected] "{"
23 [email protected] "}"
24 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs
new file mode 100644
index 000000000..a6836cbd5
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs
@@ -0,0 +1 @@
default impl T for Foo {}
diff --git a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast b/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast
deleted file mode 100644
index 5524efaaf..000000000
--- a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast
+++ /dev/null
@@ -1,56 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected] "extern"
5 [email protected] " "
6 [email protected] "fn"
7 [email protected] " "
8 [email protected]
9 [email protected] "foo"
10 [email protected]
11 [email protected] "("
12 [email protected] ")"
13 [email protected] " "
14 [email protected]
15 [email protected] "{"
16 [email protected] "\n"
17 [email protected] "}"
18 [email protected] "\n\n"
19 [email protected]
20 [email protected]
21 [email protected] "extern"
22 [email protected] " "
23 [email protected] "\"C\""
24 [email protected] " "
25 [email protected] "fn"
26 [email protected] " "
27 [email protected]
28 [email protected] "bar"
29 [email protected]
30 [email protected] "("
31 [email protected] ")"
32 [email protected] " "
33 [email protected]
34 [email protected] "{"
35 [email protected] "\n"
36 [email protected] "}"
37 [email protected] "\n\n"
38 [email protected]
39 [email protected]
40 [email protected] "extern"
41 [email protected] " "
42 [email protected] "r\"D\""
43 [email protected] " "
44 [email protected] "fn"
45 [email protected] " "
46 [email protected]
47 [email protected] "baz"
48 [email protected]
49 [email protected] "("
50 [email protected] ")"
51 [email protected] " "
52 [email protected]
53 [email protected] "{"
54 [email protected] "\n"
55 [email protected] "}"
56 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs b/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs
deleted file mode 100644
index e929eef74..000000000
--- a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs
+++ /dev/null
@@ -1,8 +0,0 @@
1extern fn foo() {
2}
3
4extern "C" fn bar() {
5}
6
7extern r"D" fn baz() {
8}
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
deleted file mode 100644
index 6246a31a6..000000000
--- a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast
+++ /dev/null
@@ -1,44 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "impl"
4 [email protected] " "
5 [email protected]
6 [email protected]
7 [email protected]
8 [email protected]
9 [email protected] "T"
10 [email protected] " "
11 [email protected] "for"
12 [email protected] " "
13 [email protected]
14 [email protected]
15 [email protected]
16 [email protected]
17 [email protected] "Foo"
18 [email protected] " "
19 [email protected]
20 [email protected] "{"
21 [email protected] "\n "
22 [email protected]
23 [email protected] "default"
24 [email protected] " "
25 [email protected] "const"
26 [email protected] " "
27 [email protected]
28 [email protected] "f"
29 [email protected] ":"
30 [email protected] " "
31 [email protected]
32 [email protected]
33 [email protected]
34 [email protected]
35 [email protected] "u8"
36 [email protected] " "
37 [email protected] "="
38 [email protected] " "
39 [email protected]
40 [email protected] "0"
41 [email protected] ";"
42 [email protected] "\n"
43 [email protected] "}"
44 [email protected] "\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
deleted file mode 100644
index dfb3b92dc..000000000
--- a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs
+++ /dev/null
@@ -1,3 +0,0 @@
1impl T for Foo {
2 default const f: u8 = 0;
3}
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast
new file mode 100644
index 000000000..e9b57ec3b
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast
@@ -0,0 +1,218 @@
1[email protected]
2 [email protected]
3 [email protected] "trait"
4 [email protected] " "
5 [email protected]
6 [email protected] "T"
7 [email protected] " "
8 [email protected]
9 [email protected] "{"
10 [email protected] "\n "
11 [email protected]
12 [email protected] "default"
13 [email protected] " "
14 [email protected] "type"
15 [email protected] " "
16 [email protected]
17 [email protected] "T"
18 [email protected] " "
19 [email protected] "="
20 [email protected] " "
21 [email protected]
22 [email protected]
23 [email protected]
24 [email protected]
25 [email protected] "Bar"
26 [email protected] ";"
27 [email protected] "\n "
28 [email protected]
29 [email protected] "default"
30 [email protected] " "
31 [email protected] "const"
32 [email protected] " "
33 [email protected]
34 [email protected] "f"
35 [email protected] ":"
36 [email protected] " "
37 [email protected]
38 [email protected]
39 [email protected]
40 [email protected]
41 [email protected] "u8"
42 [email protected] " "
43 [email protected] "="
44 [email protected] " "
45 [email protected]
46 [email protected] "0"
47 [email protected] ";"
48 [email protected] "\n "
49 [email protected]
50 [email protected] "default"
51 [email protected] " "
52 [email protected] "fn"
53 [email protected] " "
54 [email protected]
55 [email protected] "foo"
56 [email protected]
57 [email protected] "("
58 [email protected] ")"
59 [email protected] " "
60 [email protected]
61 [email protected] "{"
62 [email protected] "}"
63 [email protected] "\n "
64 [email protected]
65 [email protected] "default"
66 [email protected] " "
67 [email protected] "unsafe"
68 [email protected] " "
69 [email protected] "fn"
70 [email protected] " "
71 [email protected]
72 [email protected] "bar"
73 [email protected]
74 [email protected] "("
75 [email protected] ")"
76 [email protected] " "
77 [email protected]
78 [email protected] "{"
79 [email protected] "}"
80 [email protected] "\n"
81 [email protected] "}"
82 [email protected] "\n\n"
83 [email protected]
84 [email protected] "impl"
85 [email protected] " "
86 [email protected]
87 [email protected]
88 [email protected]
89 [email protected]
90 [email protected] "T"
91 [email protected] " "
92 [email protected] "for"
93 [email protected] " "
94 [email protected]
95 [email protected]
96 [email protected]
97 [email protected]
98 [email protected] "Foo"
99 [email protected] " "
100 [email protected]
101 [email protected] "{"
102 [email protected] "\n "
103 [email protected]
104 [email protected] "default"
105 [email protected] " "
106 [email protected] "type"
107 [email protected] " "
108 [email protected]
109 [email protected] "T"
110 [email protected] " "
111 [email protected] "="
112 [email protected] " "
113 [email protected]
114 [email protected]
115 [email protected]
116 [email protected]
117 [email protected] "Bar"
118 [email protected] ";"
119 [email protected] "\n "
120 [email protected]
121 [email protected] "default"
122 [email protected] " "
123 [email protected] "const"
124 [email protected] " "
125 [email protected]
126 [email protected] "f"
127 [email protected] ":"
128 [email protected] " "
129 [email protected]
130 [email protected]
131 [email protected]
132 [email protected]
133 [email protected] "u8"
134 [email protected] " "
135 [email protected] "="
136 [email protected] " "
137 [email protected]
138 [email protected] "0"
139 [email protected] ";"
140 [email protected] "\n "
141 [email protected]
142 [email protected] "default"
143 [email protected] " "
144 [email protected] "fn"
145 [email protected] " "
146 [email protected]
147 [email protected] "foo"
148 [email protected]
149 [email protected] "("
150 [email protected] ")"
151 [email protected] " "
152 [email protected]
153 [email protected] "{"
154 [email protected] "}"
155 [email protected] "\n "
156 [email protected]
157 [email protected] "default"
158 [email protected] " "
159 [email protected] "unsafe"
160 [email protected] " "
161 [email protected] "fn"
162 [email protected] " "
163 [email protected]
164 [email protected] "bar"
165 [email protected]
166 [email protected] "("
167 [email protected] ")"
168 [email protected] " "
169 [email protected]
170 [email protected] "{"
171 [email protected] "}"
172 [email protected] "\n"
173 [email protected] "}"
174 [email protected] "\n\n"
175 [email protected]
176 [email protected] "default"
177 [email protected] " "
178 [email protected] "impl"
179 [email protected] " "
180 [email protected]
181 [email protected]
182 [email protected]
183 [email protected]
184 [email protected] "T"
185 [email protected] " "
186 [email protected] "for"
187 [email protected] " "
188 [email protected]
189 [email protected] "("
190 [email protected] ")"
191 [email protected] " "
192 [email protected]
193 [email protected] "{"
194 [email protected] "}"
195 [email protected] "\n"
196 [email protected]
197 [email protected] "default"
198 [email protected] " "
199 [email protected] "unsafe"
200 [email protected] " "
201 [email protected] "impl"
202 [email protected] " "
203 [email protected]
204 [email protected]
205 [email protected]
206 [email protected]
207 [email protected] "T"
208 [email protected] " "
209 [email protected] "for"
210 [email protected] " "
211 [email protected]
212 [email protected] "("
213 [email protected] ")"
214 [email protected] " "
215 [email protected]
216 [email protected] "{"
217 [email protected] "}"
218 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs
new file mode 100644
index 000000000..e443e3495
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs
@@ -0,0 +1,16 @@
1trait T {
2 default type T = Bar;
3 default const f: u8 = 0;
4 default fn foo() {}
5 default unsafe fn bar() {}
6}
7
8impl T for Foo {
9 default type T = Bar;
10 default const f: u8 = 0;
11 default fn foo() {}
12 default unsafe fn bar() {}
13}
14
15default impl T for () {}
16default unsafe impl T for () {}
diff --git a/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast
new file mode 100644
index 000000000..50a6d8ee9
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast
@@ -0,0 +1,218 @@
1[email protected]
2 [email protected]
3 [email protected] "async"
4 [email protected] " "
5 [email protected] "fn"
6 [email protected] " "
7 [email protected]
8 [email protected] "foo"
9 [email protected]
10 [email protected] "("
11 [email protected] ")"
12 [email protected] " "
13 [email protected]
14 [email protected] "{"
15 [email protected] "}"
16 [email protected] "\n"
17 [email protected]
18 [email protected]
19 [email protected] "extern"
20 [email protected] " "
21 [email protected] "fn"
22 [email protected] " "
23 [email protected]
24 [email protected] "foo"
25 [email protected]
26 [email protected] "("
27 [email protected] ")"
28 [email protected] " "
29 [email protected]
30 [email protected] "{"
31 [email protected] "}"
32 [email protected] "\n"
33 [email protected]
34 [email protected] "const"
35 [email protected] " "
36 [email protected] "fn"
37 [email protected] " "
38 [email protected]
39 [email protected] "foo"
40 [email protected]
41 [email protected] "("
42 [email protected] ")"
43 [email protected] " "
44 [email protected]
45 [email protected] "{"
46 [email protected] "}"
47 [email protected] "\n"
48 [email protected]
49 [email protected] "const"
50 [email protected] " "
51 [email protected] "unsafe"
52 [email protected] " "
53 [email protected] "fn"
54 [email protected] " "
55 [email protected]
56 [email protected] "foo"
57 [email protected]
58 [email protected] "("
59 [email protected] ")"
60 [email protected] " "
61 [email protected]
62 [email protected] "{"
63 [email protected] "}"
64 [email protected] "\n"
65 [email protected]
66 [email protected] "unsafe"
67 [email protected] " "
68 [email protected]
69 [email protected] "extern"
70 [email protected] " "
71 [email protected] "\"C\""
72 [email protected] " "
73 [email protected] "fn"
74 [email protected] " "
75 [email protected]
76 [email protected] "foo"
77 [email protected]
78 [email protected] "("
79 [email protected] ")"
80 [email protected] " "
81 [email protected]
82 [email protected] "{"
83 [email protected] "}"
84 [email protected] "\n"
85 [email protected]
86 [email protected] "unsafe"
87 [email protected] " "
88 [email protected] "fn"
89 [email protected] " "
90 [email protected]
91 [email protected] "foo"
92 [email protected]
93 [email protected] "("
94 [email protected] ")"
95 [email protected] " "
96 [email protected]
97 [email protected] "{"
98 [email protected] "}"
99 [email protected] "\n"
100 [email protected]
101 [email protected] "async"
102 [email protected] " "
103 [email protected] "unsafe"
104 [email protected] " "
105 [email protected] "fn"
106 [email protected] " "
107 [email protected]
108 [email protected] "foo"
109 [email protected]
110 [email protected] "("
111 [email protected] ")"
112 [email protected] " "
113 [email protected]
114 [email protected] "{"
115 [email protected] "}"
116 [email protected] "\n"
117 [email protected]
118 [email protected] "const"
119 [email protected] " "
120 [email protected] "unsafe"
121 [email protected] " "
122 [email protected] "fn"
123 [email protected] " "
124 [email protected]
125 [email protected] "bar"
126 [email protected]
127 [email protected] "("
128 [email protected] ")"
129 [email protected] " "
130 [email protected]
131 [email protected] "{"
132 [email protected] "}"
133 [email protected] "\n\n"
134 [email protected]
135 [email protected] "unsafe"
136 [email protected] " "
137 [email protected] "trait"
138 [email protected] " "
139 [email protected]
140 [email protected] "T"
141 [email protected] " "
142 [email protected]
143 [email protected] "{"
144 [email protected] "}"
145 [email protected] "\n"
146 [email protected]
147 [email protected] "auto"
148 [email protected] " "
149 [email protected] "trait"
150 [email protected] " "
151 [email protected]
152 [email protected] "T"
153 [email protected] " "
154 [email protected]
155 [email protected] "{"
156 [email protected] "}"
157 [email protected] "\n"
158 [email protected]
159 [email protected] "unsafe"
160 [email protected] " "
161 [email protected] "auto"
162 [email protected] " "
163 [email protected] "trait"
164 [email protected] " "
165 [email protected]
166 [email protected] "T"
167 [email protected] " "
168 [email protected]
169 [email protected] "{"
170 [email protected] "}"
171 [email protected] "\n\n"
172 [email protected]
173 [email protected] "unsafe"
174 [email protected] " "
175 [email protected] "impl"
176 [email protected] " "
177 [email protected]
178 [email protected]
179 [email protected]
180 [email protected]
181 [email protected] "Foo"
182 [email protected] " "
183 [email protected]
184 [email protected] "{"
185 [email protected] "}"
186 [email protected] "\n"
187 [email protected]
188 [email protected] "default"
189 [email protected] " "
190 [email protected] "impl"
191 [email protected] " "
192 [email protected]
193 [email protected]
194 [email protected]
195 [email protected]
196 [email protected] "Foo"
197 [email protected] " "
198 [email protected]
199 [email protected] "{"
200 [email protected] "}"
201 [email protected] "\n"
202 [email protected]
203 [email protected] "unsafe"
204 [email protected] " "
205 [email protected] "default"
206 [email protected] " "
207 [email protected] "impl"
208 [email protected] " "
209 [email protected]
210 [email protected]
211 [email protected]
212 [email protected]
213 [email protected] "Foo"
214 [email protected] " "
215 [email protected]
216 [email protected] "{"
217 [email protected] "}"
218 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs
new file mode 100644
index 000000000..8d697c04b
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs
@@ -0,0 +1,16 @@
1async fn foo() {}
2extern fn foo() {}
3const fn foo() {}
4const unsafe fn foo() {}
5unsafe extern "C" fn foo() {}
6unsafe fn foo() {}
7async unsafe fn foo() {}
8const unsafe fn bar() {}
9
10unsafe trait T {}
11auto trait T {}
12unsafe auto trait T {}
13
14unsafe impl Foo {}
15default impl Foo {}
16unsafe default impl Foo {}
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs
index 25554f583..d68791cf1 100644
--- a/crates/ra_text_edit/src/lib.rs
+++ b/crates/ra_text_edit/src/lib.rs
@@ -76,10 +76,6 @@ impl TextEdit {
76 self.indels.iter() 76 self.indels.iter()
77 } 77 }
78 78
79 pub fn into_iter(self) -> vec::IntoIter<Indel> {
80 self.indels.into_iter()
81 }
82
83 pub fn apply(&self, text: &mut String) { 79 pub fn apply(&self, text: &mut String) {
84 match self.len() { 80 match self.len() {
85 0 => return, 81 0 => return,
@@ -141,6 +137,15 @@ impl TextEdit {
141 } 137 }
142} 138}
143 139
140impl IntoIterator for TextEdit {
141 type Item = Indel;
142 type IntoIter = vec::IntoIter<Self::Item>;
143
144 fn into_iter(self) -> Self::IntoIter {
145 self.indels.into_iter()
146 }
147}
148
144impl TextEditBuilder { 149impl TextEditBuilder {
145 pub fn replace(&mut self, range: TextRange, replace_with: String) { 150 pub fn replace(&mut self, range: TextRange, replace_with: String) {
146 self.indels.push(Indel::replace(range, replace_with)) 151 self.indels.push(Indel::replace(range, replace_with))
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 8faf1cc67..20c3f5eab 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -107,7 +107,7 @@ fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usi
107 for (idx, child) in subtree.token_trees.iter().enumerate() { 107 for (idx, child) in subtree.token_trees.iter().enumerate() {
108 print_debug_token(f, child, level + 1)?; 108 print_debug_token(f, child, level + 1)?;
109 if idx != subtree.token_trees.len() - 1 { 109 if idx != subtree.token_trees.len() - 1 {
110 writeln!(f, "")?; 110 writeln!(f)?;
111 } 111 }
112 } 112 }
113 } 113 }
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 721d41a58..0d386841e 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -72,7 +72,7 @@ impl AnalysisStatsCmd {
72 shuffle(&mut rng, &mut krates); 72 shuffle(&mut rng, &mut krates);
73 } 73 }
74 for krate in krates { 74 for krate in krates {
75 let module = krate.root_module(db).expect("crate without root module"); 75 let module = krate.root_module(db);
76 let file_id = module.definition_source(db).file_id; 76 let file_id = module.definition_source(db).file_id;
77 let file_id = file_id.original_file(db); 77 let file_id = file_id.original_file(db);
78 let source_root = db.file_source_root(file_id); 78 let source_root = db.file_source_root(file_id);
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 4ac8c8772..f17fc5dfe 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -28,7 +28,7 @@ pub fn diagnostics(
28 let mut work = Vec::new(); 28 let mut work = Vec::new();
29 let krates = Crate::all(db); 29 let krates = Crate::all(db);
30 for krate in krates { 30 for krate in krates {
31 let module = krate.root_module(db).expect("crate without root module"); 31 let module = krate.root_module(db);
32 let file_id = module.definition_source(db).file_id; 32 let file_id = module.definition_source(db).file_id;
33 let file_id = file_id.original_file(db); 33 let file_id = file_id.original_file(db);
34 let source_root = db.file_source_root(file_id); 34 let source_root = db.file_source_root(file_id);
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 46cb7ebe2..f9f045f13 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -73,6 +73,7 @@ pub(crate) struct GlobalState {
73 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, 73 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
74 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, 74 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
75 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, 75 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
76 pub(crate) shutdown_requested: bool,
76 pub(crate) status: Status, 77 pub(crate) status: Status,
77 pub(crate) source_root_config: SourceRootConfig, 78 pub(crate) source_root_config: SourceRootConfig,
78 pub(crate) proc_macro_client: ProcMacroClient, 79 pub(crate) proc_macro_client: ProcMacroClient,
@@ -124,6 +125,7 @@ impl GlobalState {
124 mem_docs: FxHashMap::default(), 125 mem_docs: FxHashMap::default(),
125 semantic_tokens_cache: Arc::new(Default::default()), 126 semantic_tokens_cache: Arc::new(Default::default()),
126 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), 127 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
128 shutdown_requested: false,
127 status: Status::default(), 129 status: Status::default(),
128 source_root_config: SourceRootConfig::default(), 130 source_root_config: SourceRootConfig::default(),
129 proc_macro_client: ProcMacroClient::dummy(), 131 proc_macro_client: ProcMacroClient::dummy(),
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 067259e24..785dd2a26 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -773,12 +773,11 @@ fn handle_fixes(
773 773
774 let diagnostics = snap.analysis.diagnostics(file_id, snap.config.experimental_diagnostics)?; 774 let diagnostics = snap.analysis.diagnostics(file_id, snap.config.experimental_diagnostics)?;
775 775
776 let fixes_from_diagnostics = diagnostics 776 for fix in diagnostics
777 .into_iter() 777 .into_iter()
778 .filter_map(|d| Some((d.range, d.fix?))) 778 .filter_map(|d| d.fix)
779 .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) 779 .filter(|fix| fix.fix_trigger_range.intersect(range).is_some())
780 .map(|(_range, fix)| fix); 780 {
781 for fix in fixes_from_diagnostics {
782 let title = fix.label; 781 let title = fix.label;
783 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; 782 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
784 let action = lsp_ext::CodeAction { 783 let action = lsp_ext::CodeAction {
@@ -864,7 +863,7 @@ pub(crate) fn handle_resolve_code_action(
864 let (id_string, index) = split_once(&params.id, ':').unwrap(); 863 let (id_string, index) = split_once(&params.id, ':').unwrap();
865 let index = index.parse::<usize>().unwrap(); 864 let index = index.parse::<usize>().unwrap();
866 let assist = &assists[index]; 865 let assist = &assists[index];
867 assert!(assist.assist.id.0 == id_string); 866 assert!(assist.assist.id().0 == id_string);
868 Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit) 867 Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit)
869} 868}
870 869
@@ -892,7 +891,7 @@ pub(crate) fn handle_code_lens(
892 } 891 }
893 892
894 let action = runnable.action(); 893 let action = runnable.action();
895 let range = to_proto::range(&line_index, runnable.nav.focus_or_full_range()); 894 let range = to_proto::range(&line_index, runnable.nav.full_range);
896 let r = to_proto::runnable(&snap, file_id, runnable)?; 895 let r = to_proto::runnable(&snap, file_id, runnable)?;
897 if snap.config.lens.run { 896 if snap.config.lens.run {
898 let lens = CodeLens { 897 let lens = CodeLens {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ceddb2b05..e6cf46df2 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -47,7 +47,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
47 SetThreadPriority(thread, thread_priority_above_normal); 47 SetThreadPriority(thread, thread_priority_above_normal);
48 } 48 }
49 49
50 GlobalState::new(connection.sender.clone(), config).run(connection.receiver) 50 GlobalState::new(connection.sender, config).run(connection.receiver)
51} 51}
52 52
53enum Event { 53enum Event {
@@ -337,11 +337,34 @@ impl GlobalState {
337 fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { 337 fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> {
338 self.register_request(&req, request_received); 338 self.register_request(&req, request_received);
339 339
340 if self.shutdown_requested {
341 self.respond(Response::new_err(
342 req.id,
343 lsp_server::ErrorCode::InvalidRequest as i32,
344 "Shutdown already requested.".to_owned(),
345 ));
346
347 return Ok(());
348 }
349
350 if self.status == Status::Loading && req.method != "shutdown" {
351 self.respond(lsp_server::Response::new_err(
352 req.id,
353 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
354 lsp_server::ErrorCode::ContentModified as i32,
355 "Rust Analyzer is still loading...".to_owned(),
356 ));
357 return Ok(());
358 }
359
340 RequestDispatcher { req: Some(req), global_state: self } 360 RequestDispatcher { req: Some(req), global_state: self }
341 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? 361 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))?
342 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 362 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
343 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 363 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
344 .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))? 364 .on_sync::<lsp_types::request::Shutdown>(|s, ()| {
365 s.shutdown_requested = true;
366 Ok(())
367 })?
345 .on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| { 368 .on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| {
346 handlers::handle_selection_range(s.snapshot(), p) 369 handlers::handle_selection_range(s.snapshot(), p)
347 })? 370 })?
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 5eba1f155..62fda8a1f 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -704,10 +704,10 @@ pub(crate) fn unresolved_code_action(
704 index: usize, 704 index: usize,
705) -> Result<lsp_ext::CodeAction> { 705) -> Result<lsp_ext::CodeAction> {
706 let res = lsp_ext::CodeAction { 706 let res = lsp_ext::CodeAction {
707 title: assist.label, 707 title: assist.label(),
708 id: Some(format!("{}:{}", assist.id.0.to_owned(), index.to_string())), 708 id: Some(format!("{}:{}", assist.id().0.to_owned(), index.to_string())),
709 group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), 709 group: assist.group().filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0),
710 kind: Some(code_action_kind(assist.id.1)), 710 kind: Some(code_action_kind(assist.id().1)),
711 edit: None, 711 edit: None,
712 is_preferred: None, 712 is_preferred: None,
713 }; 713 };
@@ -755,7 +755,8 @@ pub(crate) fn runnable(
755} 755}
756 756
757pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent { 757pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent {
758 lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value: markup.into() } 758 let value = crate::markdown::format_docs(markup.as_str());
759 lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value }
759} 760}
760 761
761#[cfg(test)] 762#[cfg(test)]
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index b65875c96..3c5027fe5 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,5 +1,5 @@
1//! Missing batteries for standard libraries. 1//! Missing batteries for standard libraries.
2use std::{cell::Cell, fmt, time::Instant}; 2use std::time::Instant;
3 3
4mod macros; 4mod macros;
5 5
@@ -8,69 +8,6 @@ pub fn is_ci() -> bool {
8 option_env!("CI").is_some() 8 option_env!("CI").is_some()
9} 9}
10 10
11pub trait SepBy: Sized {
12 /// Returns an `impl fmt::Display`, which joins elements via a separator.
13 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>;
14}
15
16impl<I> SepBy for I
17where
18 I: Iterator,
19 I::Item: fmt::Display,
20{
21 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self> {
22 SepByBuilder::new(sep, self)
23 }
24}
25
26pub struct SepByBuilder<'a, I> {
27 sep: &'a str,
28 prefix: &'a str,
29 suffix: &'a str,
30 iter: Cell<Option<I>>,
31}
32
33impl<'a, I> SepByBuilder<'a, I> {
34 fn new(sep: &'a str, iter: I) -> SepByBuilder<'a, I> {
35 SepByBuilder { sep, prefix: "", suffix: "", iter: Cell::new(Some(iter)) }
36 }
37
38 pub fn prefix(mut self, prefix: &'a str) -> Self {
39 self.prefix = prefix;
40 self
41 }
42
43 pub fn suffix(mut self, suffix: &'a str) -> Self {
44 self.suffix = suffix;
45 self
46 }
47
48 /// Set both suffix and prefix.
49 pub fn surround_with(self, prefix: &'a str, suffix: &'a str) -> Self {
50 self.prefix(prefix).suffix(suffix)
51 }
52}
53
54impl<I> fmt::Display for SepByBuilder<'_, I>
55where
56 I: Iterator,
57 I::Item: fmt::Display,
58{
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.write_str(self.prefix)?;
61 let mut first = true;
62 for item in self.iter.take().unwrap() {
63 if !first {
64 f.write_str(self.sep)?;
65 }
66 first = false;
67 fmt::Display::fmt(&item, f)?;
68 }
69 f.write_str(self.suffix)?;
70 Ok(())
71 }
72}
73
74#[must_use] 11#[must_use]
75pub fn timeit(label: &'static str) -> impl Drop { 12pub fn timeit(label: &'static str) -> impl Drop {
76 struct Guard { 13 struct Guard {