aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/attr.rs4
-rw-r--r--crates/hir_def/src/find_path.rs63
-rw-r--r--crates/hir_expand/src/eager.rs18
-rw-r--r--crates/ide/src/expand_macro.rs23
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs33
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs37
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/main.rs2
-rw-r--r--crates/syntax/src/ast/node_ext.rs12
-rw-r--r--crates/syntax/src/validation/block.rs2
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_attrs.rast218
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_attrs.rs (renamed from crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs)6
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast178
-rw-r--r--docs/dev/lsp-extensions.md13
17 files changed, 376 insertions, 243 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 786fad6e1..d9294d93a 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -545,7 +545,7 @@ fn inner_attributes(
545 _ => return None, 545 _ => return None,
546 } 546 }
547 }; 547 };
548 let attrs = attrs.filter(|attr| attr.excl_token().is_some()); 548 let attrs = attrs.filter(|attr| attr.kind().is_inner());
549 let docs = docs.filter(|doc| doc.is_inner()); 549 let docs = docs.filter(|doc| doc.is_inner());
550 Some((attrs, docs)) 550 Some((attrs, docs))
551} 551}
@@ -740,7 +740,7 @@ fn collect_attrs(
740 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) 740 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
741 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); 741 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
742 742
743 let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); 743 let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer());
744 let attrs = outer_attrs 744 let attrs = outer_attrs
745 .chain(inner_attrs.into_iter().flatten()) 745 .chain(inner_attrs.into_iter().flatten())
746 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); 746 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr)));
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 2c4bbe585..dc3f2908f 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -119,8 +119,7 @@ fn find_path_inner(
119 119
120 // - if the item is the crate root, return `crate` 120 // - if the item is the crate root, return `crate`
121 let root = def_map.crate_root(db); 121 let root = def_map.crate_root(db);
122 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { 122 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) {
123 // FIXME: the `block_id()` check should be unnecessary, but affects the result
124 return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); 123 return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
125 } 124 }
126 125
@@ -131,7 +130,7 @@ fn find_path_inner(
131 } 130 }
132 131
133 // - if the item is the crate root of a dependency crate, return the name from the extern prelude 132 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
134 for (name, def_id) in def_map.extern_prelude() { 133 for (name, def_id) in root.def_map(db).extern_prelude() {
135 if item == ItemInNs::Types(*def_id) { 134 if item == ItemInNs::Types(*def_id) {
136 let name = scope_name.unwrap_or_else(|| name.clone()); 135 let name = scope_name.unwrap_or_else(|| name.clone());
137 return Some(ModPath::from_segments(PathKind::Plain, vec![name])); 136 return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
@@ -298,6 +297,7 @@ fn find_local_import_locations(
298 let data = &def_map[from.local_id]; 297 let data = &def_map[from.local_id];
299 let mut worklist = 298 let mut worklist =
300 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>(); 299 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
300 // FIXME: do we need to traverse out of block expressions here?
301 for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) { 301 for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
302 worklist.push(ancestor); 302 worklist.push(ancestor);
303 } 303 }
@@ -947,10 +947,11 @@ fn main() {
947 $0 947 $0
948} 948}
949 "#, 949 "#,
950 // FIXME: these could use fewer/better prefixes
950 "module::CompleteMe", 951 "module::CompleteMe",
951 "module::CompleteMe",
952 "crate::module::CompleteMe", 952 "crate::module::CompleteMe",
953 "self::module::CompleteMe", 953 "crate::module::CompleteMe",
954 "crate::module::CompleteMe",
954 ) 955 )
955 } 956 }
956 957
@@ -978,6 +979,28 @@ mod bar {
978 } 979 }
979 980
980 #[test] 981 #[test]
982 fn from_inside_module_with_inner_items() {
983 check_found_path(
984 r#"
985mod baz {
986 pub struct Foo {}
987}
988
989mod bar {
990 fn bar() {
991 fn inner() {}
992 $0
993 }
994}
995 "#,
996 "crate::baz::Foo",
997 "crate::baz::Foo",
998 "crate::baz::Foo",
999 "crate::baz::Foo",
1000 )
1001 }
1002
1003 #[test]
981 fn recursive_pub_mod_reexport() { 1004 fn recursive_pub_mod_reexport() {
982 cov_mark::check!(recursive_imports); 1005 cov_mark::check!(recursive_imports);
983 check_found_path( 1006 check_found_path(
@@ -1004,4 +1027,34 @@ pub mod name {
1004 "self::name::AsName", 1027 "self::name::AsName",
1005 ); 1028 );
1006 } 1029 }
1030
1031 #[test]
1032 fn extern_crate() {
1033 check_found_path(
1034 r#"
1035//- /main.rs crate:main deps:dep
1036$0
1037//- /dep.rs crate:dep
1038"#,
1039 "dep",
1040 "dep",
1041 "dep",
1042 "dep",
1043 );
1044
1045 check_found_path(
1046 r#"
1047//- /main.rs crate:main deps:dep
1048fn f() {
1049 fn inner() {}
1050 $0
1051}
1052//- /dep.rs crate:dep
1053"#,
1054 "dep",
1055 "dep",
1056 "dep",
1057 "dep",
1058 );
1059 }
1007} 1060}
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index a5ac32d3c..f12132f84 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -29,7 +29,7 @@ use base_db::CrateId;
29use mbe::ExpandResult; 29use mbe::ExpandResult;
30use parser::FragmentKind; 30use parser::FragmentKind;
31use std::sync::Arc; 31use std::sync::Arc;
32use syntax::{algo::SyntaxRewriter, SyntaxNode}; 32use syntax::{ted, SyntaxNode};
33 33
34#[derive(Debug)] 34#[derive(Debug)]
35pub struct ErrorEmitted { 35pub struct ErrorEmitted {
@@ -192,10 +192,10 @@ fn eager_macro_recur(
192 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 192 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
193 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError), 193 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
194) -> Result<SyntaxNode, ErrorEmitted> { 194) -> Result<SyntaxNode, ErrorEmitted> {
195 let original = curr.value.clone(); 195 let original = curr.value.clone().clone_for_update();
196 196
197 let children = curr.value.descendants().filter_map(ast::MacroCall::cast); 197 let children = original.descendants().filter_map(ast::MacroCall::cast);
198 let mut rewriter = SyntaxRewriter::default(); 198 let mut replacements = Vec::new();
199 199
200 // Collect replacement 200 // Collect replacement
201 for child in children { 201 for child in children {
@@ -214,6 +214,7 @@ fn eager_macro_recur(
214 .into(); 214 .into();
215 db.parse_or_expand(id.as_file()) 215 db.parse_or_expand(id.as_file())
216 .expect("successful macro expansion should be parseable") 216 .expect("successful macro expansion should be parseable")
217 .clone_for_update()
217 } 218 }
218 MacroDefKind::Declarative(_) 219 MacroDefKind::Declarative(_)
219 | MacroDefKind::BuiltIn(..) 220 | MacroDefKind::BuiltIn(..)
@@ -227,15 +228,14 @@ fn eager_macro_recur(
227 } 228 }
228 }; 229 };
229 230
230 // check if the whole original sytnax is replaced 231 // check if the whole original syntax is replaced
231 // Note that SyntaxRewriter cannot replace the root node itself
232 if child.syntax() == &original { 232 if child.syntax() == &original {
233 return Ok(insert); 233 return Ok(insert);
234 } 234 }
235 235
236 rewriter.replace(child.syntax(), &insert); 236 replacements.push((child, insert));
237 } 237 }
238 238
239 let res = rewriter.rewrite(&original); 239 replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
240 Ok(res) 240 Ok(original)
241} 241}
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index be0ee03bf..eebae5ebe 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -3,9 +3,7 @@ use std::iter;
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::RootDatabase; 4use ide_db::RootDatabase;
5use syntax::{ 5use syntax::{
6 algo::{find_node_at_offset, SyntaxRewriter}, 6 algo::find_node_at_offset, ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*,
7 ast, AstNode, NodeOrToken, SyntaxKind,
8 SyntaxKind::*,
9 SyntaxNode, WalkEvent, T, 7 SyntaxNode, WalkEvent, T,
10}; 8};
11 9
@@ -46,26 +44,23 @@ fn expand_macro_recur(
46 sema: &Semantics<RootDatabase>, 44 sema: &Semantics<RootDatabase>,
47 macro_call: &ast::MacroCall, 45 macro_call: &ast::MacroCall,
48) -> Option<SyntaxNode> { 46) -> Option<SyntaxNode> {
49 let mut expanded = sema.expand(macro_call)?; 47 let expanded = sema.expand(macro_call)?.clone_for_update();
50 48
51 let children = expanded.descendants().filter_map(ast::MacroCall::cast); 49 let children = expanded.descendants().filter_map(ast::MacroCall::cast);
52 let mut rewriter = SyntaxRewriter::default(); 50 let mut replacements = Vec::new();
53 51
54 for child in children.into_iter() { 52 for child in children {
55 if let Some(new_node) = expand_macro_recur(sema, &child) { 53 if let Some(new_node) = expand_macro_recur(sema, &child) {
56 // Replace the whole node if it is root 54 // check if the whole original syntax is replaced
57 // `replace_descendants` will not replace the parent node
58 // but `SyntaxNode::descendants include itself
59 if expanded == *child.syntax() { 55 if expanded == *child.syntax() {
60 expanded = new_node; 56 return Some(new_node);
61 } else {
62 rewriter.replace(child.syntax(), &new_node)
63 } 57 }
58 replacements.push((child, new_node));
64 } 59 }
65 } 60 }
66 61
67 let res = rewriter.rewrite(&expanded); 62 replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
68 Some(res) 63 Some(expanded)
69} 64}
70 65
71// FIXME: It would also be cool to share logic here and in the mbe tests, 66// FIXME: It would also be cool to share logic here and in the mbe tests,
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 8cc877c1c..18552459b 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -222,7 +222,7 @@ pub(super) fn element(
222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=] 222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=]
223 if element.parent().and_then(ast::BinExpr::cast).is_some() => 223 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
224 { 224 {
225 HlTag::Operator(HlOperator::Comparision).into() 225 HlTag::Operator(HlOperator::Comparison).into()
226 } 226 }
227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { 227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
228 HlTag::Operator(HlOperator::Other).into() 228 HlTag::Operator(HlOperator::Other).into()
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 8128d231d..e58392d67 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -96,7 +96,7 @@ pub enum HlOperator {
96 /// &&, ||, ! 96 /// &&, ||, !
97 Logical, 97 Logical,
98 /// >, <, ==, >=, <=, != 98 /// >, <, ==, >=, <=, !=
99 Comparision, 99 Comparison,
100 /// 100 ///
101 Other, 101 Other,
102} 102}
@@ -151,7 +151,7 @@ impl HlTag {
151 HlOperator::Bitwise => "bitwise", 151 HlOperator::Bitwise => "bitwise",
152 HlOperator::Arithmetic => "arithmetic", 152 HlOperator::Arithmetic => "arithmetic",
153 HlOperator::Logical => "logical", 153 HlOperator::Logical => "logical",
154 HlOperator::Comparision => "comparision", 154 HlOperator::Comparison => "comparison",
155 HlOperator::Other => "operator", 155 HlOperator::Other => "operator",
156 }, 156 },
157 HlTag::StringLiteral => "string_literal", 157 HlTag::StringLiteral => "string_literal",
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 5ccd7f7a2..49aa70f74 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -934,4 +934,37 @@ fn main() {
934", 934",
935 ); 935 );
936 } 936 }
937
938 #[test]
939 fn inner_items() {
940 check_assist(
941 auto_import,
942 r#"
943mod baz {
944 pub struct Foo {}
945}
946
947mod bar {
948 fn bar() {
949 Foo$0;
950 println!("Hallo");
951 }
952}
953"#,
954 r#"
955mod baz {
956 pub struct Foo {}
957}
958
959mod bar {
960 use crate::baz::Foo;
961
962 fn bar() {
963 Foo;
964 println!("Hallo");
965 }
966}
967"#,
968 );
969 }
937} 970}
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index f872d20c8..870a8d4ff 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -5,7 +5,6 @@ use itertools::Itertools;
5use syntax::{ 5use syntax::{
6 ast::{self, make, AstNode, NameOwner}, 6 ast::{self, make, AstNode, NameOwner},
7 SyntaxKind::{IDENT, WHITESPACE}, 7 SyntaxKind::{IDENT, WHITESPACE},
8 TextSize,
9}; 8};
10 9
11use crate::{ 10use crate::{
@@ -43,32 +42,23 @@ pub(crate) fn replace_derive_with_manual_impl(
43 ctx: &AssistContext, 42 ctx: &AssistContext,
44) -> Option<()> { 43) -> Option<()> {
45 let attr = ctx.find_node_at_offset::<ast::Attr>()?; 44 let attr = ctx.find_node_at_offset::<ast::Attr>()?;
46 45 let (name, args) = attr.as_simple_call()?;
47 let has_derive = attr 46 if name != "derive" {
48 .syntax()
49 .descendants_with_tokens()
50 .filter(|t| t.kind() == IDENT)
51 .find_map(syntax::NodeOrToken::into_token)
52 .filter(|t| t.text() == "derive")
53 .is_some();
54 if !has_derive {
55 return None; 47 return None;
56 } 48 }
57 49
58 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; 50 let trait_token = args.syntax().token_at_offset(ctx.offset()).find(|t| t.kind() == IDENT)?;
59 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); 51 let trait_name = trait_token.text();
60 52
61 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; 53 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
62 let annotated_name = adt.name()?;
63 let insert_pos = adt.syntax().text_range().end();
64 54
65 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; 55 let current_module = ctx.sema.scope(adt.syntax()).module()?;
66 let current_crate = current_module.krate(); 56 let current_crate = current_module.krate();
67 57
68 let found_traits = items_locator::items_with_name( 58 let found_traits = items_locator::items_with_name(
69 &ctx.sema, 59 &ctx.sema,
70 current_crate, 60 current_crate,
71 NameToImport::Exact(trait_token.text().to_string()), 61 NameToImport::Exact(trait_name.to_string()),
72 items_locator::AssocItemSearch::Exclude, 62 items_locator::AssocItemSearch::Exclude,
73 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT), 63 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
74 ) 64 )
@@ -86,10 +76,11 @@ pub(crate) fn replace_derive_with_manual_impl(
86 76
87 let mut no_traits_found = true; 77 let mut no_traits_found = true;
88 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { 78 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
89 add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?; 79 add_assist(acc, ctx, &attr, &args, &trait_path, Some(trait_), &adt)?;
90 } 80 }
91 if no_traits_found { 81 if no_traits_found {
92 add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?; 82 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_name)));
83 add_assist(acc, ctx, &attr, &args, &trait_path, None, &adt)?;
93 } 84 }
94 Some(()) 85 Some(())
95} 86}
@@ -98,15 +89,14 @@ fn add_assist(
98 acc: &mut Assists, 89 acc: &mut Assists,
99 ctx: &AssistContext, 90 ctx: &AssistContext,
100 attr: &ast::Attr, 91 attr: &ast::Attr,
92 input: &ast::TokenTree,
101 trait_path: &ast::Path, 93 trait_path: &ast::Path,
102 trait_: Option<hir::Trait>, 94 trait_: Option<hir::Trait>,
103 adt: &ast::Adt, 95 adt: &ast::Adt,
104 annotated_name: &ast::Name,
105 insert_pos: TextSize,
106) -> Option<()> { 96) -> Option<()> {
107 let target = attr.syntax().text_range(); 97 let target = attr.syntax().text_range();
108 let input = attr.token_tree()?; 98 let annotated_name = adt.name()?;
109 let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name); 99 let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name);
110 let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?; 100 let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;
111 101
112 acc.add( 102 acc.add(
@@ -114,8 +104,9 @@ fn add_assist(
114 label, 104 label,
115 target, 105 target,
116 |builder| { 106 |builder| {
107 let insert_pos = adt.syntax().text_range().end();
117 let impl_def_with_items = 108 let impl_def_with_items =
118 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); 109 impl_def_from_trait(&ctx.sema, &annotated_name, trait_, trait_path);
119 update_attribute(builder, &input, &trait_name, &attr); 110 update_attribute(builder, &input, &trait_name, &attr);
120 let trait_path = format!("{}", trait_path); 111 let trait_path = format!("{}", trait_path);
121 match (ctx.config.snippet_cap, impl_def_with_items) { 112 match (ctx.config.snippet_cap, impl_def_with_items) {
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index adc059817..ecab89b2a 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -49,7 +49,7 @@ define_semantic_token_types![
49 (CHAR_LITERAL, "characterLiteral"), 49 (CHAR_LITERAL, "characterLiteral"),
50 (COLON, "colon"), 50 (COLON, "colon"),
51 (COMMA, "comma"), 51 (COMMA, "comma"),
52 (COMPARISION, "comparision"), 52 (COMPARISON, "comparison"),
53 (CONST_PARAMETER, "constParameter"), 53 (CONST_PARAMETER, "constParameter"),
54 (DOT, "dot"), 54 (DOT, "dot"),
55 (ESCAPE_SEQUENCE, "escapeSequence"), 55 (ESCAPE_SEQUENCE, "escapeSequence"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index fe4d0733d..c2361b32e 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -469,7 +469,7 @@ fn semantic_token_type_and_modifiers(
469 HlOperator::Bitwise => semantic_tokens::BITWISE, 469 HlOperator::Bitwise => semantic_tokens::BITWISE,
470 HlOperator::Arithmetic => semantic_tokens::ARITHMETIC, 470 HlOperator::Arithmetic => semantic_tokens::ARITHMETIC,
471 HlOperator::Logical => semantic_tokens::LOGICAL, 471 HlOperator::Logical => semantic_tokens::LOGICAL,
472 HlOperator::Comparision => semantic_tokens::COMPARISION, 472 HlOperator::Comparison => semantic_tokens::COMPARISON,
473 HlOperator::Other => semantic_tokens::OPERATOR, 473 HlOperator::Other => semantic_tokens::OPERATOR,
474 }, 474 },
475 HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, 475 HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs
index 52a2674d5..9e89209ea 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/main.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs
@@ -525,7 +525,7 @@ version = \"0.0.0\"
525#[test] 525#[test]
526fn out_dirs_check() { 526fn out_dirs_check() {
527 if skip_slow_tests() { 527 if skip_slow_tests() {
528 // return; 528 return;
529 } 529 }
530 530
531 let server = Project::with_fixture( 531 let server = Project::with_fixture(
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index ae98dbd26..171099661 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -125,6 +125,18 @@ pub enum AttrKind {
125 Outer, 125 Outer,
126} 126}
127 127
128impl AttrKind {
129 /// Returns `true` if the attr_kind is [`Inner`].
130 pub fn is_inner(&self) -> bool {
131 matches!(self, Self::Inner)
132 }
133
134 /// Returns `true` if the attr_kind is [`Outer`].
135 pub fn is_outer(&self) -> bool {
136 matches!(self, Self::Outer)
137 }
138}
139
128impl ast::Attr { 140impl ast::Attr {
129 pub fn as_simple_atom(&self) -> Option<SmolStr> { 141 pub fn as_simple_atom(&self) -> Option<SmolStr> {
130 if self.eq_token().is_some() || self.token_tree().is_some() { 142 if self.eq_token().is_some() || self.token_tree().is_some() {
diff --git a/crates/syntax/src/validation/block.rs b/crates/syntax/src/validation/block.rs
index ad9901468..40170014f 100644
--- a/crates/syntax/src/validation/block.rs
+++ b/crates/syntax/src/validation/block.rs
@@ -13,7 +13,7 @@ pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<Syntax
13 _ => {} 13 _ => {}
14 } 14 }
15 } 15 }
16 errors.extend(block.attrs().map(|attr| { 16 errors.extend(block.attrs().filter(|attr| attr.kind().is_inner()).map(|attr| {
17 SyntaxError::new( 17 SyntaxError::new(
18 "A block in this position cannot accept inner attributes", 18 "A block in this position cannot accept inner attributes",
19 attr.syntax().text_range(), 19 attr.syntax().text_range(),
diff --git a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
new file mode 100644
index 000000000..50ab52d32
--- /dev/null
+++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
@@ -0,0 +1,218 @@
1[email protected]
2 [email protected]
3 [email protected] "fn"
4 [email protected] " "
5 [email protected]
6 [email protected] "inner"
7 [email protected]
8 [email protected] "("
9 [email protected] ")"
10 [email protected] " "
11 [email protected]
12 [email protected] "{"
13 [email protected] "\n "
14 [email protected]
15 [email protected] "#"
16 [email protected] "!"
17 [email protected] "["
18 [email protected]
19 [email protected]
20 [email protected]
21 [email protected] "doc"
22 [email protected]
23 [email protected] "("
24 [email protected] "\"Inner attributes all ..."
25 [email protected] ")"
26 [email protected] "]"
27 [email protected] "\n "
28 [email protected] "//! As are ModuleDoc ..."
29 [email protected] "\n "
30 [email protected]
31 [email protected]
32 [email protected] "{"
33 [email protected] "\n "
34 [email protected]
35 [email protected] "#"
36 [email protected] "!"
37 [email protected] "["
38 [email protected]
39 [email protected]
40 [email protected]
41 [email protected] "doc"
42 [email protected]
43 [email protected] "("
44 [email protected] "\"Inner attributes are ..."
45 [email protected] ")"
46 [email protected] "]"
47 [email protected] "\n "
48 [email protected]
49 [email protected] "#"
50 [email protected] "!"
51 [email protected] "["
52 [email protected]
53 [email protected]
54 [email protected]
55 [email protected] "doc"
56 [email protected]
57 [email protected] "("
58 [email protected] "\"Being validated is n ..."
59 [email protected] ")"
60 [email protected] "]"
61 [email protected] "\n "
62 [email protected] "//! As are ModuleDoc ..."
63 [email protected] "\n "
64 [email protected] "}"
65 [email protected] ";"
66 [email protected] "\n "
67 [email protected]
68 [email protected] "{"
69 [email protected] "\n "
70 [email protected]
71 [email protected] "#"
72 [email protected] "!"
73 [email protected] "["
74 [email protected]
75 [email protected]
76 [email protected]
77 [email protected] "doc"
78 [email protected]
79 [email protected] "("
80 [email protected] "\"Inner attributes are ..."
81 [email protected] ")"
82 [email protected] "]"
83 [email protected] "\n "
84 [email protected] "//! As are ModuleDoc ..."
85 [email protected] "\n "
86 [email protected] "}"
87 [email protected] "\n"
88 [email protected] "}"
89 [email protected] "\n\n"
90 [email protected]
91 [email protected] "fn"
92 [email protected] " "
93 [email protected]
94 [email protected] "outer"
95 [email protected]
96 [email protected] "("
97 [email protected] ")"
98 [email protected] " "
99 [email protected]
100 [email protected] "{"
101 [email protected] "\n "
102 [email protected]
103 [email protected] "let"
104 [email protected] " "
105 [email protected]
106 [email protected] "_"
107 [email protected] " "
108 [email protected] "="
109 [email protected] " "
110 [email protected]
111 [email protected]
112 [email protected] "#"
113 [email protected] "["
114 [email protected]
115 [email protected]
116 [email protected]
117 [email protected] "doc"
118 [email protected]
119 [email protected] "("
120 [email protected] "\"Outer attributes are ..."
121 [email protected] ")"
122 [email protected] "]"
123 [email protected] " "
124 [email protected] "{"
125 [email protected] "}"
126 [email protected] ";"
127 [email protected] "\n"
128 [email protected] "}"
129 [email protected] "\n\n"
130 [email protected] "// https://github.com ..."
131 [email protected] "\n"
132 [email protected]
133 [email protected] "impl"
134 [email protected] " "
135 [email protected]
136 [email protected]
137 [email protected]
138 [email protected]
139 [email protected] "Whatever"
140 [email protected] " "
141 [email protected]
142 [email protected] "{"
143 [email protected] "\n "
144 [email protected]
145 [email protected] "fn"
146 [email protected] " "
147 [email protected]
148 [email protected] "salsa_event"
149 [email protected]
150 [email protected] "("
151 [email protected]
152 [email protected] "&"
153 [email protected]
154 [email protected] "self"
155 [email protected] ","
156 [email protected] " "
157 [email protected]
158 [email protected]
159 [email protected]
160 [email protected] "event_fn"
161 [email protected] ":"
162 [email protected] " "
163 [email protected]
164 [email protected] "impl"
165 [email protected] " "
166 [email protected]
167 [email protected]
168 [email protected]
169 [email protected]
170 [email protected]
171 [email protected]
172 [email protected] "Fn"
173 [email protected]
174 [email protected] "("
175 [email protected] ")"
176 [email protected] " "
177 [email protected]
178 [email protected] "->"
179 [email protected] " "
180 [email protected]
181 [email protected]
182 [email protected]
183 [email protected]
184 [email protected] "Event"
185 [email protected]
186 [email protected] "<"
187 [email protected]
188 [email protected]
189 [email protected]
190 [email protected]
191 [email protected]
192 [email protected] "Self"
193 [email protected] ">"
194 [email protected] ")"
195 [email protected] " "
196 [email protected]
197 [email protected] "{"
198 [email protected] "\n "
199 [email protected]
200 [email protected] "#"
201 [email protected] "!"
202 [email protected] "["
203 [email protected]
204 [email protected]
205 [email protected]
206 [email protected] "allow"
207 [email protected]
208 [email protected] "("
209 [email protected] "unused_variables"
210 [email protected] ")"
211 [email protected] "]"
212 [email protected] " "
213 [email protected] "// this is `inner_at ..."
214 [email protected] "\n "
215 [email protected] "}"
216 [email protected] "\n"
217 [email protected] "}"
218 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs b/crates/syntax/test_data/parser/ok/0045_block_attrs.rs
index 88df8138e..ed4593759 100644
--- a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs
+++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rs
@@ -1,4 +1,4 @@
1fn block() { 1fn inner() {
2 #![doc("Inner attributes allowed here")] 2 #![doc("Inner attributes allowed here")]
3 //! As are ModuleDoc style comments 3 //! As are ModuleDoc style comments
4 { 4 {
@@ -12,6 +12,10 @@ fn block() {
12 } 12 }
13} 13}
14 14
15fn outer() {
16 let _ = #[doc("Outer attributes are always allowed")] {};
17}
18
15// https://github.com/rust-analyzer/rust-analyzer/issues/689 19// https://github.com/rust-analyzer/rust-analyzer/issues/689
16impl Whatever { 20impl Whatever {
17 fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) { 21 fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) {
diff --git a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast
deleted file mode 100644
index 6afed5f05..000000000
--- a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast
+++ /dev/null
@@ -1,178 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "fn"
4 [email protected] " "
5 [email protected]
6 [email protected] "block"
7 [email protected]
8 [email protected] "("
9 [email protected] ")"
10 [email protected] " "
11 [email protected]
12 [email protected] "{"
13 [email protected] "\n "
14 [email protected]
15 [email protected] "#"
16 [email protected] "!"
17 [email protected] "["
18 [email protected]
19 [email protected]
20 [email protected]
21 [email protected] "doc"
22 [email protected]
23 [email protected] "("
24 [email protected] "\"Inner attributes all ..."
25 [email protected] ")"
26 [email protected] "]"
27 [email protected] "\n "
28 [email protected] "//! As are ModuleDoc ..."
29 [email protected] "\n "
30 [email protected]
31 [email protected]
32 [email protected] "{"
33 [email protected] "\n "
34 [email protected]
35 [email protected] "#"
36 [email protected] "!"
37 [email protected] "["
38 [email protected]
39 [email protected]
40 [email protected]
41 [email protected] "doc"
42 [email protected]
43 [email protected] "("
44 [email protected] "\"Inner attributes are ..."
45 [email protected] ")"
46 [email protected] "]"
47 [email protected] "\n "
48 [email protected]
49 [email protected] "#"
50 [email protected] "!"
51 [email protected] "["
52 [email protected]
53 [email protected]
54 [email protected]
55 [email protected] "doc"
56 [email protected]
57 [email protected] "("
58 [email protected] "\"Being validated is n ..."
59 [email protected] ")"
60 [email protected] "]"
61 [email protected] "\n "
62 [email protected] "//! As are ModuleDoc ..."
63 [email protected] "\n "
64 [email protected] "}"
65 [email protected] ";"
66 [email protected] "\n "
67 [email protected]
68 [email protected] "{"
69 [email protected] "\n "
70 [email protected]
71 [email protected] "#"
72 [email protected] "!"
73 [email protected] "["
74 [email protected]
75 [email protected]
76 [email protected]
77 [email protected] "doc"
78 [email protected]
79 [email protected] "("
80 [email protected] "\"Inner attributes are ..."
81 [email protected] ")"
82 [email protected] "]"
83 [email protected] "\n "
84 [email protected] "//! As are ModuleDoc ..."
85 [email protected] "\n "
86 [email protected] "}"
87 [email protected] "\n"
88 [email protected] "}"
89 [email protected] "\n\n"
90 [email protected] "// https://github.com ..."
91 [email protected] "\n"
92 [email protected]
93 [email protected] "impl"
94 [email protected] " "
95 [email protected]
96 [email protected]
97 [email protected]
98 [email protected]
99 [email protected] "Whatever"
100 [email protected] " "
101 [email protected]
102 [email protected] "{"
103 [email protected] "\n "
104 [email protected]
105 [email protected] "fn"
106 [email protected] " "
107 [email protected]
108 [email protected] "salsa_event"
109 [email protected]
110 [email protected] "("
111 [email protected]
112 [email protected] "&"
113 [email protected]
114 [email protected] "self"
115 [email protected] ","
116 [email protected] " "
117 [email protected]
118 [email protected]
119 [email protected]
120 [email protected] "event_fn"
121 [email protected] ":"
122 [email protected] " "
123 [email protected]
124 [email protected] "impl"
125 [email protected] " "
126 [email protected]
127 [email protected]
128 [email protected]
129 [email protected]
130 [email protected]
131 [email protected]
132 [email protected] "Fn"
133 [email protected]
134 [email protected] "("
135 [email protected] ")"
136 [email protected] " "
137 [email protected]
138 [email protected] "->"
139 [email protected] " "
140 [email protected]
141 [email protected]
142 [email protected]
143 [email protected]
144 [email protected] "Event"
145 [email protected]
146 [email protected] "<"
147 [email protected]
148 [email protected]
149 [email protected]
150 [email protected]
151 [email protected]
152 [email protected] "Self"
153 [email protected] ">"
154 [email protected] ")"
155 [email protected] " "
156 [email protected]
157 [email protected] "{"
158 [email protected] "\n "
159 [email protected]
160 [email protected] "#"
161 [email protected] "!"
162 [email protected] "["
163 [email protected]
164 [email protected]
165 [email protected]
166 [email protected] "allow"
167 [email protected]
168 [email protected] "("
169 [email protected] "unused_variables"
170 [email protected] ")"
171 [email protected] "]"
172 [email protected] " "
173 [email protected] "// this is `inner_at ..."
174 [email protected] "\n "
175 [email protected] "}"
176 [email protected] "\n"
177 [email protected] "}"
178 [email protected] "\n"
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index a112477de..f0f981802 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -422,7 +422,7 @@ Reloads project information (that is, re-executes `cargo metadata`).
422 422
423## Server Status 423## Server Status
424 424
425**Experimental Client Capability:** `{ "serverStatus": boolean }` 425**Experimental Client Capability:** `{ "serverStatusNotification": boolean }`
426 426
427**Method:** `experimental/serverStatus` 427**Method:** `experimental/serverStatus`
428 428
@@ -433,11 +433,13 @@ interface ServerStatusParams {
433 /// `ok` means that the server is completely functional. 433 /// `ok` means that the server is completely functional.
434 /// 434 ///
435 /// `warning` means that the server is partially functional. 435 /// `warning` means that the server is partially functional.
436 /// It can server requests, but some results might be wrong due to, 436 /// It can answer correctly to most requests, but some results
437 /// for example, some missing dependencies. 437 /// might be wrong due to, for example, some missing dependencies.
438 /// 438 ///
439 /// `error` means that the server is not functional. For example, 439 /// `error` means that the server is not functional. For example,
440 /// there's a fatal build configuration problem. 440 /// there's a fatal build configuration problem. The server might
441 /// still give correct answers to simple requests, but most results
442 /// will be incomplete or wrong.
441 health: "ok" | "warning" | "error", 443 health: "ok" | "warning" | "error",
442 /// Is there any pending background work which might change the status? 444 /// Is there any pending background work which might change the status?
443 /// For example, are dependencies being downloaded? 445 /// For example, are dependencies being downloaded?
@@ -451,6 +453,9 @@ This notification is sent from server to client.
451The client can use it to display *persistent* status to the user (in modline). 453The client can use it to display *persistent* status to the user (in modline).
452It is similar to the `showMessage`, but is intended for stares rather than point-in-time events. 454It is similar to the `showMessage`, but is intended for stares rather than point-in-time events.
453 455
456Note that this functionality is intended primarily to inform the end user about the state of the server.
457In particular, it's valid for the client to completely ignore this extension.
458Clients are discouraged from but are allowed to use the `health` status to decide if it's worth sending a request to the server.
454 459
455## Syntax Tree 460## Syntax Tree
456 461