diff options
-rw-r--r-- | crates/hir/src/display.rs | 4 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 26 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 131 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 186 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/pretty.rs | 48 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/tests.rs | 21 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 66 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/diagnostics.rs | 16 | ||||
-rw-r--r-- | crates/hir_def/src/path.rs | 20 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower/lower_use.rs | 78 | ||||
-rw-r--r-- | crates/hir_def/src/test_db.rs | 8 | ||||
-rw-r--r-- | crates/ide/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting.rs | 78 | ||||
-rw-r--r-- | crates/rust-analyzer/src/semantic_tokens.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 2 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 18 | ||||
-rw-r--r-- | xtask/src/dist.rs | 6 |
19 files changed, 447 insertions, 271 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index c5cf803fd..72f0d9b5f 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs | |||
@@ -427,10 +427,6 @@ impl HirDisplay for Trait { | |||
427 | write!(f, "trait {}", data.name)?; | 427 | write!(f, "trait {}", data.name)?; |
428 | let def_id = GenericDefId::TraitId(self.id); | 428 | let def_id = GenericDefId::TraitId(self.id); |
429 | write_generic_params(def_id, f)?; | 429 | write_generic_params(def_id, f)?; |
430 | if !data.bounds.is_empty() { | ||
431 | write!(f, ": ")?; | ||
432 | f.write_joined(&*data.bounds, " + ")?; | ||
433 | } | ||
434 | write_where_clause(def_id, f)?; | 430 | write_where_clause(def_id, f)?; |
435 | Ok(()) | 431 | Ok(()) |
436 | } | 432 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1ecd2391b..01b2de515 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -472,27 +472,13 @@ impl Module { | |||
472 | }); | 472 | }); |
473 | } | 473 | } |
474 | 474 | ||
475 | DefDiagnosticKind::UnresolvedImport { ast, index } => { | 475 | DefDiagnosticKind::UnresolvedImport { id, index } => { |
476 | let use_item = ast.to_node(db.upcast()); | 476 | let file_id = id.file_id(); |
477 | let hygiene = Hygiene::new(db.upcast(), ast.file_id); | 477 | let item_tree = id.item_tree(db.upcast()); |
478 | let mut cur = 0; | 478 | let import = &item_tree[id.value]; |
479 | let mut tree = None; | ||
480 | ModPath::expand_use_item( | ||
481 | db.upcast(), | ||
482 | InFile::new(ast.file_id, use_item), | ||
483 | &hygiene, | ||
484 | |_mod_path, use_tree, _is_glob, _alias| { | ||
485 | if cur == *index { | ||
486 | tree = Some(use_tree.clone()); | ||
487 | } | ||
488 | |||
489 | cur += 1; | ||
490 | }, | ||
491 | ); | ||
492 | 479 | ||
493 | if let Some(tree) = tree { | 480 | let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); |
494 | sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) }); | 481 | sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) }); |
495 | } | ||
496 | } | 482 | } |
497 | 483 | ||
498 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { | 484 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 8bcac60ef..a04f73352 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -141,7 +141,6 @@ pub struct TraitData { | |||
141 | pub is_auto: bool, | 141 | pub is_auto: bool, |
142 | pub is_unsafe: bool, | 142 | pub is_unsafe: bool, |
143 | pub visibility: RawVisibility, | 143 | pub visibility: RawVisibility, |
144 | pub bounds: Box<[Interned<TypeBound>]>, | ||
145 | } | 144 | } |
146 | 145 | ||
147 | impl TraitData { | 146 | impl TraitData { |
@@ -155,7 +154,6 @@ impl TraitData { | |||
155 | let module_id = tr_loc.container; | 154 | let module_id = tr_loc.container; |
156 | let container = AssocContainerId::TraitId(tr); | 155 | let container = AssocContainerId::TraitId(tr); |
157 | let visibility = item_tree[tr_def.visibility].clone(); | 156 | let visibility = item_tree[tr_def.visibility].clone(); |
158 | let bounds = tr_def.bounds.clone(); | ||
159 | let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); | 157 | let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); |
160 | 158 | ||
161 | let items = collect_items( | 159 | let items = collect_items( |
@@ -168,7 +166,7 @@ impl TraitData { | |||
168 | 100, | 166 | 100, |
169 | ); | 167 | ); |
170 | 168 | ||
171 | Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds }) | 169 | Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility }) |
172 | } | 170 | } |
173 | 171 | ||
174 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | 172 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 11767d100..c4d20c416 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -523,21 +523,38 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | |||
523 | } | 523 | } |
524 | } | 524 | } |
525 | 525 | ||
526 | /// A desugared `use` import. | ||
527 | #[derive(Debug, Clone, Eq, PartialEq)] | 526 | #[derive(Debug, Clone, Eq, PartialEq)] |
528 | pub struct Import { | 527 | pub struct Import { |
529 | pub path: Interned<ModPath>, | ||
530 | pub alias: Option<ImportAlias>, | ||
531 | pub visibility: RawVisibilityId, | 528 | pub visibility: RawVisibilityId, |
532 | pub is_glob: bool, | ||
533 | /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to | ||
534 | /// the same `use` item. | ||
535 | pub ast_id: FileAstId<ast::Use>, | 529 | pub ast_id: FileAstId<ast::Use>, |
536 | /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. | 530 | pub use_tree: UseTree, |
537 | /// | 531 | } |
538 | /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting | 532 | |
539 | /// precise diagnostics. | 533 | #[derive(Debug, Clone, Eq, PartialEq)] |
540 | pub index: usize, | 534 | pub struct UseTree { |
535 | pub index: Idx<ast::UseTree>, | ||
536 | kind: UseTreeKind, | ||
537 | } | ||
538 | |||
539 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
540 | pub enum UseTreeKind { | ||
541 | /// ``` | ||
542 | /// use path::to::Item; | ||
543 | /// use path::to::Item as Renamed; | ||
544 | /// use path::to::Trait as _; | ||
545 | /// ``` | ||
546 | Single { path: Interned<ModPath>, alias: Option<ImportAlias> }, | ||
547 | |||
548 | /// ``` | ||
549 | /// use *; // (invalid, but can occur in nested tree) | ||
550 | /// use path::*; | ||
551 | /// ``` | ||
552 | Glob { path: Option<Interned<ModPath>> }, | ||
553 | |||
554 | /// ``` | ||
555 | /// use prefix::{self, Item, ...}; | ||
556 | /// ``` | ||
557 | Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> }, | ||
541 | } | 558 | } |
542 | 559 | ||
543 | #[derive(Debug, Clone, Eq, PartialEq)] | 560 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -644,7 +661,6 @@ pub struct Trait { | |||
644 | pub generic_params: Interned<GenericParams>, | 661 | pub generic_params: Interned<GenericParams>, |
645 | pub is_auto: bool, | 662 | pub is_auto: bool, |
646 | pub is_unsafe: bool, | 663 | pub is_unsafe: bool, |
647 | pub bounds: Box<[Interned<TypeBound>]>, | ||
648 | pub items: Box<[AssocItem]>, | 664 | pub items: Box<[AssocItem]>, |
649 | pub ast_id: FileAstId<ast::Trait>, | 665 | pub ast_id: FileAstId<ast::Trait>, |
650 | } | 666 | } |
@@ -711,6 +727,97 @@ pub struct MacroDef { | |||
711 | pub ast_id: FileAstId<ast::MacroDef>, | 727 | pub ast_id: FileAstId<ast::MacroDef>, |
712 | } | 728 | } |
713 | 729 | ||
730 | impl Import { | ||
731 | /// Maps a `UseTree` contained in this import back to its AST node. | ||
732 | pub fn use_tree_to_ast( | ||
733 | &self, | ||
734 | db: &dyn DefDatabase, | ||
735 | file_id: HirFileId, | ||
736 | index: Idx<ast::UseTree>, | ||
737 | ) -> ast::UseTree { | ||
738 | // Re-lower the AST item and get the source map. | ||
739 | // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. | ||
740 | let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); | ||
741 | let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); | ||
742 | let hygiene = Hygiene::new(db.upcast(), file_id); | ||
743 | let (_, source_map) = | ||
744 | lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree"); | ||
745 | source_map[index].clone() | ||
746 | } | ||
747 | } | ||
748 | |||
749 | impl UseTree { | ||
750 | /// Expands the `UseTree` into individually imported `ModPath`s. | ||
751 | pub fn expand( | ||
752 | &self, | ||
753 | mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, /* is_glob */ bool, Option<ImportAlias>), | ||
754 | ) { | ||
755 | self.expand_impl(None, &mut cb) | ||
756 | } | ||
757 | |||
758 | fn expand_impl( | ||
759 | &self, | ||
760 | prefix: Option<ModPath>, | ||
761 | cb: &mut dyn FnMut( | ||
762 | Idx<ast::UseTree>, | ||
763 | ModPath, | ||
764 | /* is_glob */ bool, | ||
765 | Option<ImportAlias>, | ||
766 | ), | ||
767 | ) { | ||
768 | fn concat_mod_paths(prefix: Option<ModPath>, path: &ModPath) -> Option<ModPath> { | ||
769 | match (prefix, &path.kind) { | ||
770 | (None, _) => Some(path.clone()), | ||
771 | (Some(mut prefix), PathKind::Plain) => { | ||
772 | for segment in path.segments() { | ||
773 | prefix.push_segment(segment.clone()); | ||
774 | } | ||
775 | Some(prefix) | ||
776 | } | ||
777 | (Some(prefix), PathKind::Super(0)) => { | ||
778 | // `some::path::self` == `some::path` | ||
779 | if path.segments().is_empty() { | ||
780 | Some(prefix) | ||
781 | } else { | ||
782 | None | ||
783 | } | ||
784 | } | ||
785 | (Some(_), _) => None, | ||
786 | } | ||
787 | } | ||
788 | |||
789 | match &self.kind { | ||
790 | UseTreeKind::Single { path, alias } => { | ||
791 | if let Some(path) = concat_mod_paths(prefix, path) { | ||
792 | cb(self.index, path, false, alias.clone()); | ||
793 | } | ||
794 | } | ||
795 | UseTreeKind::Glob { path: Some(path) } => { | ||
796 | if let Some(path) = concat_mod_paths(prefix, path) { | ||
797 | cb(self.index, path, true, None); | ||
798 | } | ||
799 | } | ||
800 | UseTreeKind::Glob { path: None } => { | ||
801 | if let Some(prefix) = prefix { | ||
802 | cb(self.index, prefix, true, None); | ||
803 | } | ||
804 | } | ||
805 | UseTreeKind::Prefixed { prefix: additional_prefix, list } => { | ||
806 | let prefix = match additional_prefix { | ||
807 | Some(path) => match concat_mod_paths(prefix, path) { | ||
808 | Some(path) => Some(path), | ||
809 | None => return, | ||
810 | }, | ||
811 | None => prefix, | ||
812 | }; | ||
813 | for tree in &**list { | ||
814 | tree.expand_impl(prefix.clone(), cb); | ||
815 | } | ||
816 | } | ||
817 | } | ||
818 | } | ||
819 | } | ||
820 | |||
714 | macro_rules! impl_froms { | 821 | macro_rules! impl_froms { |
715 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | 822 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { |
716 | $( | 823 | $( |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index b4389371f..b83adec46 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | use std::{collections::hash_map::Entry, mem, sync::Arc}; | 3 | use std::{collections::hash_map::Entry, mem, sync::Arc}; |
4 | 4 | ||
5 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; | 5 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; |
6 | use smallvec::SmallVec; | ||
7 | use syntax::{ | 6 | use syntax::{ |
8 | ast::{self, ModuleItemOwner}, | 7 | ast::{self, ModuleItemOwner}, |
9 | SyntaxNode, WalkEvent, | 8 | SyntaxNode, WalkEvent, |
@@ -20,22 +19,10 @@ fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { | |||
20 | FileItemTreeId { index, _p: PhantomData } | 19 | FileItemTreeId { index, _p: PhantomData } |
21 | } | 20 | } |
22 | 21 | ||
23 | struct ModItems(SmallVec<[ModItem; 1]>); | ||
24 | |||
25 | impl<T> From<T> for ModItems | ||
26 | where | ||
27 | T: Into<ModItem>, | ||
28 | { | ||
29 | fn from(t: T) -> Self { | ||
30 | ModItems(SmallVec::from_buf([t.into(); 1])) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | pub(super) struct Ctx<'a> { | 22 | pub(super) struct Ctx<'a> { |
35 | db: &'a dyn DefDatabase, | 23 | db: &'a dyn DefDatabase, |
36 | tree: ItemTree, | 24 | tree: ItemTree, |
37 | hygiene: Hygiene, | 25 | hygiene: Hygiene, |
38 | file: HirFileId, | ||
39 | source_ast_id_map: Arc<AstIdMap>, | 26 | source_ast_id_map: Arc<AstIdMap>, |
40 | body_ctx: crate::body::LowerCtx<'a>, | 27 | body_ctx: crate::body::LowerCtx<'a>, |
41 | forced_visibility: Option<RawVisibilityId>, | 28 | forced_visibility: Option<RawVisibilityId>, |
@@ -47,7 +34,6 @@ impl<'a> Ctx<'a> { | |||
47 | db, | 34 | db, |
48 | tree: ItemTree::default(), | 35 | tree: ItemTree::default(), |
49 | hygiene, | 36 | hygiene, |
50 | file, | ||
51 | source_ast_id_map: db.ast_id_map(file), | 37 | source_ast_id_map: db.ast_id_map(file), |
52 | body_ctx: crate::body::LowerCtx::new(db, file), | 38 | body_ctx: crate::body::LowerCtx::new(db, file), |
53 | forced_visibility: None, | 39 | forced_visibility: None, |
@@ -55,11 +41,8 @@ impl<'a> Ctx<'a> { | |||
55 | } | 41 | } |
56 | 42 | ||
57 | pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { | 43 | pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { |
58 | self.tree.top_level = item_owner | 44 | self.tree.top_level = |
59 | .items() | 45 | item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect(); |
60 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
61 | .flat_map(|items| items.0) | ||
62 | .collect(); | ||
63 | self.tree | 46 | self.tree |
64 | } | 47 | } |
65 | 48 | ||
@@ -71,7 +54,6 @@ impl<'a> Ctx<'a> { | |||
71 | _ => None, | 54 | _ => None, |
72 | }) | 55 | }) |
73 | .flat_map(|item| self.lower_mod_item(&item, false)) | 56 | .flat_map(|item| self.lower_mod_item(&item, false)) |
74 | .flat_map(|items| items.0) | ||
75 | .collect(); | 57 | .collect(); |
76 | 58 | ||
77 | // Non-items need to have their inner items collected. | 59 | // Non-items need to have their inner items collected. |
@@ -98,7 +80,7 @@ impl<'a> Ctx<'a> { | |||
98 | self.tree.data_mut() | 80 | self.tree.data_mut() |
99 | } | 81 | } |
100 | 82 | ||
101 | fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { | 83 | fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> { |
102 | // Collect inner items for 1-to-1-lowered items. | 84 | // Collect inner items for 1-to-1-lowered items. |
103 | match item { | 85 | match item { |
104 | ast::Item::Struct(_) | 86 | ast::Item::Struct(_) |
@@ -129,34 +111,28 @@ impl<'a> Ctx<'a> { | |||
129 | }; | 111 | }; |
130 | 112 | ||
131 | let attrs = RawAttrs::new(self.db, item, &self.hygiene); | 113 | let attrs = RawAttrs::new(self.db, item, &self.hygiene); |
132 | let items = match item { | 114 | let item: ModItem = match item { |
133 | ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), | 115 | ast::Item::Struct(ast) => self.lower_struct(ast)?.into(), |
134 | ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), | 116 | ast::Item::Union(ast) => self.lower_union(ast)?.into(), |
135 | ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into), | 117 | ast::Item::Enum(ast) => self.lower_enum(ast)?.into(), |
136 | ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into), | 118 | ast::Item::Fn(ast) => self.lower_function(ast)?.into(), |
137 | ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), | 119 | ast::Item::TypeAlias(ast) => self.lower_type_alias(ast)?.into(), |
138 | ast::Item::Static(ast) => self.lower_static(ast).map(Into::into), | 120 | ast::Item::Static(ast) => self.lower_static(ast)?.into(), |
139 | ast::Item::Const(ast) => Some(self.lower_const(ast).into()), | 121 | ast::Item::Const(ast) => self.lower_const(ast).into(), |
140 | ast::Item::Module(ast) => self.lower_module(ast).map(Into::into), | 122 | ast::Item::Module(ast) => self.lower_module(ast)?.into(), |
141 | ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into), | 123 | ast::Item::Trait(ast) => self.lower_trait(ast)?.into(), |
142 | ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into), | 124 | ast::Item::Impl(ast) => self.lower_impl(ast)?.into(), |
143 | ast::Item::Use(ast) => Some(ModItems( | 125 | ast::Item::Use(ast) => self.lower_use(ast)?.into(), |
144 | self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), | 126 | ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(), |
145 | )), | 127 | ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(), |
146 | ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), | 128 | ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(), |
147 | ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | 129 | ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(), |
148 | ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), | 130 | ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), |
149 | ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into), | ||
150 | ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()), | ||
151 | }; | 131 | }; |
152 | 132 | ||
153 | if !attrs.is_empty() { | 133 | self.add_attrs(item.into(), attrs.clone()); |
154 | for item in items.iter().flat_map(|items| &items.0) { | ||
155 | self.add_attrs((*item).into(), attrs.clone()); | ||
156 | } | ||
157 | } | ||
158 | 134 | ||
159 | items | 135 | Some(item) |
160 | } | 136 | } |
161 | 137 | ||
162 | fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { | 138 | fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { |
@@ -190,12 +166,10 @@ impl<'a> Ctx<'a> { | |||
190 | }, | 166 | }, |
191 | ast::Item(item) => { | 167 | ast::Item(item) => { |
192 | // FIXME: This triggers for macro calls in expression/pattern/type position | 168 | // FIXME: This triggers for macro calls in expression/pattern/type position |
193 | let mod_items = self.lower_mod_item(&item, true); | 169 | let mod_item = self.lower_mod_item(&item, true); |
194 | let current_block = block_stack.last(); | 170 | let current_block = block_stack.last(); |
195 | if let (Some(mod_items), Some(block)) = (mod_items, current_block) { | 171 | if let (Some(mod_item), Some(block)) = (mod_item, current_block) { |
196 | if !mod_items.0.is_empty() { | 172 | self.data().inner_items.entry(*block).or_default().push(mod_item); |
197 | self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied()); | ||
198 | } | ||
199 | } | 173 | } |
200 | }, | 174 | }, |
201 | _ => {} | 175 | _ => {} |
@@ -480,10 +454,7 @@ impl<'a> Ctx<'a> { | |||
480 | items: module | 454 | items: module |
481 | .item_list() | 455 | .item_list() |
482 | .map(|list| { | 456 | .map(|list| { |
483 | list.items() | 457 | list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect() |
484 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
485 | .flat_map(|items| items.0) | ||
486 | .collect() | ||
487 | }) | 458 | }) |
488 | .unwrap_or_else(|| { | 459 | .unwrap_or_else(|| { |
489 | cov_mark::hit!(name_res_works_for_broken_modules); | 460 | cov_mark::hit!(name_res_works_for_broken_modules); |
@@ -503,7 +474,6 @@ impl<'a> Ctx<'a> { | |||
503 | self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); | 474 | self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); |
504 | let is_auto = trait_def.auto_token().is_some(); | 475 | let is_auto = trait_def.auto_token().is_some(); |
505 | let is_unsafe = trait_def.unsafe_token().is_some(); | 476 | let is_unsafe = trait_def.unsafe_token().is_some(); |
506 | let bounds = self.lower_type_bounds(trait_def); | ||
507 | let items = trait_def.assoc_item_list().map(|list| { | 477 | let items = trait_def.assoc_item_list().map(|list| { |
508 | let db = self.db; | 478 | let db = self.db; |
509 | self.with_inherited_visibility(visibility, |this| { | 479 | self.with_inherited_visibility(visibility, |this| { |
@@ -526,7 +496,6 @@ impl<'a> Ctx<'a> { | |||
526 | generic_params, | 496 | generic_params, |
527 | is_auto, | 497 | is_auto, |
528 | is_unsafe, | 498 | is_unsafe, |
529 | bounds: bounds.into(), | ||
530 | items: items.unwrap_or_default(), | 499 | items: items.unwrap_or_default(), |
531 | ast_id, | 500 | ast_id, |
532 | }; | 501 | }; |
@@ -561,30 +530,13 @@ impl<'a> Ctx<'a> { | |||
561 | Some(id(self.data().impls.alloc(res))) | 530 | Some(id(self.data().impls.alloc(res))) |
562 | } | 531 | } |
563 | 532 | ||
564 | fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { | 533 | fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> { |
565 | let visibility = self.lower_visibility(use_item); | 534 | let visibility = self.lower_visibility(use_item); |
566 | let ast_id = self.source_ast_id_map.ast_id(use_item); | 535 | let ast_id = self.source_ast_id_map.ast_id(use_item); |
536 | let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?; | ||
567 | 537 | ||
568 | // Every use item can expand to many `Import`s. | 538 | let res = Import { visibility, ast_id, use_tree }; |
569 | let mut imports = Vec::new(); | 539 | Some(id(self.data().imports.alloc(res))) |
570 | let tree = self.tree.data_mut(); | ||
571 | ModPath::expand_use_item( | ||
572 | self.db, | ||
573 | InFile::new(self.file, use_item.clone()), | ||
574 | &self.hygiene, | ||
575 | |path, _use_tree, is_glob, alias| { | ||
576 | imports.push(id(tree.imports.alloc(Import { | ||
577 | path: Interned::new(path), | ||
578 | alias, | ||
579 | visibility, | ||
580 | is_glob, | ||
581 | ast_id, | ||
582 | index: imports.len(), | ||
583 | }))); | ||
584 | }, | ||
585 | ); | ||
586 | |||
587 | imports | ||
588 | } | 540 | } |
589 | 541 | ||
590 | fn lower_extern_crate( | 542 | fn lower_extern_crate( |
@@ -884,3 +836,81 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> { | |||
884 | } | 836 | } |
885 | } | 837 | } |
886 | } | 838 | } |
839 | |||
840 | struct UseTreeLowering<'a> { | ||
841 | db: &'a dyn DefDatabase, | ||
842 | hygiene: &'a Hygiene, | ||
843 | mapping: Arena<ast::UseTree>, | ||
844 | } | ||
845 | |||
846 | impl UseTreeLowering<'_> { | ||
847 | fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> { | ||
848 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
849 | let prefix = match tree.path() { | ||
850 | // E.g. use something::{{{inner}}}; | ||
851 | None => None, | ||
852 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
853 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
854 | Some(path) => { | ||
855 | match ModPath::from_src(self.db, path, &self.hygiene) { | ||
856 | Some(it) => Some(it), | ||
857 | None => return None, // FIXME: report errors somewhere | ||
858 | } | ||
859 | } | ||
860 | }; | ||
861 | |||
862 | let list = | ||
863 | use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect(); | ||
864 | |||
865 | Some( | ||
866 | self.use_tree( | ||
867 | UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list }, | ||
868 | tree, | ||
869 | ), | ||
870 | ) | ||
871 | } else { | ||
872 | let is_glob = tree.star_token().is_some(); | ||
873 | let path = match tree.path() { | ||
874 | Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?), | ||
875 | None => None, | ||
876 | }; | ||
877 | let alias = tree.rename().map(|a| { | ||
878 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
879 | }); | ||
880 | if alias.is_some() && is_glob { | ||
881 | return None; | ||
882 | } | ||
883 | |||
884 | match (path, alias, is_glob) { | ||
885 | (path, None, true) => { | ||
886 | if path.is_none() { | ||
887 | cov_mark::hit!(glob_enum_group); | ||
888 | } | ||
889 | Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree)) | ||
890 | } | ||
891 | // Globs can't be renamed | ||
892 | (_, Some(_), true) | (None, None, false) => None, | ||
893 | // `bla::{ as Name}` is invalid | ||
894 | (None, Some(_), false) => None, | ||
895 | (Some(path), alias, false) => Some( | ||
896 | self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree), | ||
897 | ), | ||
898 | } | ||
899 | } | ||
900 | } | ||
901 | |||
902 | fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree { | ||
903 | let index = self.mapping.alloc(ast); | ||
904 | UseTree { index, kind } | ||
905 | } | ||
906 | } | ||
907 | |||
908 | pub(super) fn lower_use_tree( | ||
909 | db: &dyn DefDatabase, | ||
910 | hygiene: &Hygiene, | ||
911 | tree: ast::UseTree, | ||
912 | ) -> Option<(UseTree, Arena<ast::UseTree>)> { | ||
913 | let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() }; | ||
914 | let tree = lowering.lower_use_tree(tree)?; | ||
915 | Some((tree, lowering.mapping)) | ||
916 | } | ||
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index 9394a5de6..d1ee697cb 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs | |||
@@ -163,21 +163,46 @@ impl<'a> Printer<'a> { | |||
163 | } | 163 | } |
164 | } | 164 | } |
165 | 165 | ||
166 | fn print_use_tree(&mut self, use_tree: &UseTree) { | ||
167 | match &use_tree.kind { | ||
168 | UseTreeKind::Single { path, alias } => { | ||
169 | w!(self, "{}", path); | ||
170 | if let Some(alias) = alias { | ||
171 | w!(self, " as {}", alias); | ||
172 | } | ||
173 | } | ||
174 | UseTreeKind::Glob { path } => { | ||
175 | if let Some(path) = path { | ||
176 | w!(self, "{}::", path); | ||
177 | } | ||
178 | w!(self, "*"); | ||
179 | } | ||
180 | UseTreeKind::Prefixed { prefix, list } => { | ||
181 | if let Some(prefix) = prefix { | ||
182 | w!(self, "{}::", prefix); | ||
183 | } | ||
184 | w!(self, "{{"); | ||
185 | for (i, tree) in list.iter().enumerate() { | ||
186 | if i != 0 { | ||
187 | w!(self, ", "); | ||
188 | } | ||
189 | self.print_use_tree(tree); | ||
190 | } | ||
191 | w!(self, "}}"); | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
166 | fn print_mod_item(&mut self, item: ModItem) { | 196 | fn print_mod_item(&mut self, item: ModItem) { |
167 | self.print_attrs_of(item); | 197 | self.print_attrs_of(item); |
168 | 198 | ||
169 | match item { | 199 | match item { |
170 | ModItem::Import(it) => { | 200 | ModItem::Import(it) => { |
171 | let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it]; | 201 | let Import { visibility, use_tree, ast_id: _ } = &self.tree[it]; |
172 | self.print_visibility(*visibility); | 202 | self.print_visibility(*visibility); |
173 | w!(self, "use {}", path); | 203 | w!(self, "use "); |
174 | if *is_glob { | 204 | self.print_use_tree(use_tree); |
175 | w!(self, "::*"); | 205 | wln!(self, ";"); |
176 | } | ||
177 | if let Some(alias) = alias { | ||
178 | w!(self, " as {}", alias); | ||
179 | } | ||
180 | wln!(self, "; // {}", index); | ||
181 | } | 206 | } |
182 | ModItem::ExternCrate(it) => { | 207 | ModItem::ExternCrate(it) => { |
183 | let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; | 208 | let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; |
@@ -320,7 +345,6 @@ impl<'a> Printer<'a> { | |||
320 | visibility, | 345 | visibility, |
321 | is_auto, | 346 | is_auto, |
322 | is_unsafe, | 347 | is_unsafe, |
323 | bounds, | ||
324 | items, | 348 | items, |
325 | generic_params, | 349 | generic_params, |
326 | ast_id: _, | 350 | ast_id: _, |
@@ -334,10 +358,6 @@ impl<'a> Printer<'a> { | |||
334 | } | 358 | } |
335 | w!(self, "trait {}", name); | 359 | w!(self, "trait {}", name); |
336 | self.print_generic_params(generic_params); | 360 | self.print_generic_params(generic_params); |
337 | if !bounds.is_empty() { | ||
338 | w!(self, ": "); | ||
339 | self.print_type_bounds(bounds); | ||
340 | } | ||
341 | self.print_where_clause_and_opening_brace(generic_params); | 361 | self.print_where_clause_and_opening_brace(generic_params); |
342 | self.indented(|this| { | 362 | self.indented(|this| { |
343 | for item in &**items { | 363 | for item in &**items { |
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index 6407871b5..b362add5c 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs | |||
@@ -26,6 +26,8 @@ use globs::*; | |||
26 | 26 | ||
27 | /// docs on import | 27 | /// docs on import |
28 | use crate::{A, B}; | 28 | use crate::{A, B}; |
29 | |||
30 | use a::{c, d::{e}}; | ||
29 | "#, | 31 | "#, |
30 | expect![[r##" | 32 | expect![[r##" |
31 | #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 } | 33 | #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 } |
@@ -36,19 +38,14 @@ use crate::{A, B}; | |||
36 | 38 | ||
37 | pub(super) extern crate bli; | 39 | pub(super) extern crate bli; |
38 | 40 | ||
39 | pub use crate::path::nested; // 0 | 41 | pub use crate::path::{nested, items as renamed, Trait as _}; |
40 | |||
41 | pub use crate::path::items as renamed; // 1 | ||
42 | 42 | ||
43 | pub use crate::path::Trait as _; // 2 | 43 | pub(self) use globs::*; |
44 | |||
45 | pub(self) use globs::*; // 0 | ||
46 | 44 | ||
47 | #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } | 45 | #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } |
48 | pub(self) use crate::A; // 0 | 46 | pub(self) use crate::{A, B}; |
49 | 47 | ||
50 | #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } | 48 | pub(self) use a::{c, d::{e}}; |
51 | pub(self) use crate::B; // 1 | ||
52 | "##]], | 49 | "##]], |
53 | ); | 50 | ); |
54 | } | 51 | } |
@@ -183,7 +180,7 @@ trait Tr: SuperTrait + 'lifetime { | |||
183 | _: (), | 180 | _: (), |
184 | ) -> (); | 181 | ) -> (); |
185 | 182 | ||
186 | pub(self) trait Tr<Self>: SuperTrait + 'lifetime | 183 | pub(self) trait Tr<Self> |
187 | where | 184 | where |
188 | Self: SuperTrait, | 185 | Self: SuperTrait, |
189 | Self: 'lifetime | 186 | Self: 'lifetime |
@@ -218,7 +215,7 @@ mod outline; | |||
218 | #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } | 215 | #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } |
219 | #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 } | 216 | #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 } |
220 | pub(self) mod inline { | 217 | pub(self) mod inline { |
221 | pub(self) use super::*; // 0 | 218 | pub(self) use super::*; |
222 | 219 | ||
223 | // flags = 0x2 | 220 | // flags = 0x2 |
224 | pub(self) fn fn_in_module() -> (); | 221 | pub(self) fn fn_in_module() -> (); |
@@ -353,7 +350,7 @@ trait Tr<'a, T: 'a>: Super {} | |||
353 | pub(self) union Union<'a, T, const U: u8> { | 350 | pub(self) union Union<'a, T, const U: u8> { |
354 | } | 351 | } |
355 | 352 | ||
356 | pub(self) trait Tr<'a, Self, T>: Super | 353 | pub(self) trait Tr<'a, Self, T> |
357 | where | 354 | where |
358 | Self: Super, | 355 | Self: Super, |
359 | T: 'a | 356 | T: 'a |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 3ea472908..4296c6304 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -17,6 +17,7 @@ use hir_expand::{ | |||
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use la_arena::Idx; | ||
20 | use rustc_hash::{FxHashMap, FxHashSet}; | 21 | use rustc_hash::{FxHashMap, FxHashSet}; |
21 | use syntax::ast; | 22 | use syntax::ast; |
22 | 23 | ||
@@ -143,7 +144,7 @@ impl PartialResolvedImport { | |||
143 | 144 | ||
144 | #[derive(Clone, Debug, Eq, PartialEq)] | 145 | #[derive(Clone, Debug, Eq, PartialEq)] |
145 | enum ImportSource { | 146 | enum ImportSource { |
146 | Import(ItemTreeId<item_tree::Import>), | 147 | Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> }, |
147 | ExternCrate(ItemTreeId<item_tree::ExternCrate>), | 148 | ExternCrate(ItemTreeId<item_tree::ExternCrate>), |
148 | } | 149 | } |
149 | 150 | ||
@@ -165,20 +166,26 @@ impl Import { | |||
165 | krate: CrateId, | 166 | krate: CrateId, |
166 | tree: &ItemTree, | 167 | tree: &ItemTree, |
167 | id: ItemTreeId<item_tree::Import>, | 168 | id: ItemTreeId<item_tree::Import>, |
168 | ) -> Self { | 169 | ) -> Vec<Self> { |
169 | let it = &tree[id.value]; | 170 | let it = &tree[id.value]; |
170 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); | 171 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); |
171 | let visibility = &tree[it.visibility]; | 172 | let visibility = &tree[it.visibility]; |
172 | Self { | 173 | let is_prelude = attrs.by_key("prelude_import").exists(); |
173 | path: it.path.clone(), | 174 | |
174 | alias: it.alias.clone(), | 175 | let mut res = Vec::new(); |
175 | visibility: visibility.clone(), | 176 | it.use_tree.expand(|idx, path, is_glob, alias| { |
176 | is_glob: it.is_glob, | 177 | res.push(Self { |
177 | is_prelude: attrs.by_key("prelude_import").exists(), | 178 | path: Interned::new(path), // FIXME this makes little sense |
178 | is_extern_crate: false, | 179 | alias, |
179 | is_macro_use: false, | 180 | visibility: visibility.clone(), |
180 | source: ImportSource::Import(id), | 181 | is_glob, |
181 | } | 182 | is_prelude, |
183 | is_extern_crate: false, | ||
184 | is_macro_use: false, | ||
185 | source: ImportSource::Import { id, use_tree: idx }, | ||
186 | }); | ||
187 | }); | ||
188 | res | ||
182 | } | 189 | } |
183 | 190 | ||
184 | fn from_extern_crate( | 191 | fn from_extern_crate( |
@@ -1130,11 +1137,8 @@ impl DefCollector<'_> { | |||
1130 | } | 1137 | } |
1131 | 1138 | ||
1132 | for directive in &self.unresolved_imports { | 1139 | for directive in &self.unresolved_imports { |
1133 | if let ImportSource::Import(import) = &directive.import.source { | 1140 | if let ImportSource::Import { id: import, use_tree } = &directive.import.source { |
1134 | let item_tree = import.item_tree(self.db); | 1141 | match (directive.import.path.segments().first(), &directive.import.path.kind) { |
1135 | let import_data = &item_tree[import.value]; | ||
1136 | |||
1137 | match (import_data.path.segments().first(), &import_data.path.kind) { | ||
1138 | (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { | 1142 | (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { |
1139 | if diagnosed_extern_crates.contains(krate) { | 1143 | if diagnosed_extern_crates.contains(krate) { |
1140 | continue; | 1144 | continue; |
@@ -1145,8 +1149,8 @@ impl DefCollector<'_> { | |||
1145 | 1149 | ||
1146 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( | 1150 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( |
1147 | directive.module_id, | 1151 | directive.module_id, |
1148 | InFile::new(import.file_id(), import_data.ast_id), | 1152 | *import, |
1149 | import_data.index, | 1153 | *use_tree, |
1150 | )); | 1154 | )); |
1151 | } | 1155 | } |
1152 | } | 1156 | } |
@@ -1222,16 +1226,20 @@ impl ModCollector<'_, '_> { | |||
1222 | match item { | 1226 | match item { |
1223 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs), | 1227 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs), |
1224 | ModItem::Import(import_id) => { | 1228 | ModItem::Import(import_id) => { |
1225 | self.def_collector.unresolved_imports.push(ImportDirective { | 1229 | let module_id = self.module_id; |
1226 | module_id: self.module_id, | 1230 | let imports = Import::from_use( |
1227 | import: Import::from_use( | 1231 | self.def_collector.db, |
1228 | self.def_collector.db, | 1232 | krate, |
1229 | krate, | 1233 | &self.item_tree, |
1230 | &self.item_tree, | 1234 | ItemTreeId::new(self.file_id, import_id), |
1231 | ItemTreeId::new(self.file_id, import_id), | 1235 | ); |
1232 | ), | 1236 | self.def_collector.unresolved_imports.extend(imports.into_iter().map( |
1233 | status: PartialResolvedImport::Unresolved, | 1237 | |import| ImportDirective { |
1234 | }) | 1238 | module_id, |
1239 | import, | ||
1240 | status: PartialResolvedImport::Unresolved, | ||
1241 | }, | ||
1242 | )); | ||
1235 | } | 1243 | } |
1236 | ModItem::ExternCrate(import_id) => { | 1244 | ModItem::ExternCrate(import_id) => { |
1237 | self.def_collector.unresolved_imports.push(ImportDirective { | 1245 | self.def_collector.unresolved_imports.push(ImportDirective { |
diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs index 8f2f0ff9f..57c36c3c6 100644 --- a/crates/hir_def/src/nameres/diagnostics.rs +++ b/crates/hir_def/src/nameres/diagnostics.rs | |||
@@ -2,9 +2,15 @@ | |||
2 | 2 | ||
3 | use cfg::{CfgExpr, CfgOptions}; | 3 | use cfg::{CfgExpr, CfgOptions}; |
4 | use hir_expand::MacroCallKind; | 4 | use hir_expand::MacroCallKind; |
5 | use la_arena::Idx; | ||
5 | use syntax::ast; | 6 | use syntax::ast; |
6 | 7 | ||
7 | use crate::{nameres::LocalModuleId, path::ModPath, AstId}; | 8 | use crate::{ |
9 | item_tree::{self, ItemTreeId}, | ||
10 | nameres::LocalModuleId, | ||
11 | path::ModPath, | ||
12 | AstId, | ||
13 | }; | ||
8 | 14 | ||
9 | #[derive(Debug, PartialEq, Eq)] | 15 | #[derive(Debug, PartialEq, Eq)] |
10 | pub enum DefDiagnosticKind { | 16 | pub enum DefDiagnosticKind { |
@@ -12,7 +18,7 @@ pub enum DefDiagnosticKind { | |||
12 | 18 | ||
13 | UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, | 19 | UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, |
14 | 20 | ||
15 | UnresolvedImport { ast: AstId<ast::Use>, index: usize }, | 21 | UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> }, |
16 | 22 | ||
17 | UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions }, | 23 | UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions }, |
18 | 24 | ||
@@ -53,10 +59,10 @@ impl DefDiagnostic { | |||
53 | 59 | ||
54 | pub(super) fn unresolved_import( | 60 | pub(super) fn unresolved_import( |
55 | container: LocalModuleId, | 61 | container: LocalModuleId, |
56 | ast: AstId<ast::Use>, | 62 | id: ItemTreeId<item_tree::Import>, |
57 | index: usize, | 63 | index: Idx<ast::UseTree>, |
58 | ) -> Self { | 64 | ) -> Self { |
59 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { ast, index } } | 65 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } |
60 | } | 66 | } |
61 | 67 | ||
62 | pub(super) fn unconfigured_code( | 68 | pub(super) fn unconfigured_code( |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index d9ec03d2d..16440041d 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -14,10 +14,7 @@ use hir_expand::{ | |||
14 | }; | 14 | }; |
15 | use syntax::ast; | 15 | use syntax::ast; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::type_ref::{TypeBound, TypeRef}; |
18 | type_ref::{TypeBound, TypeRef}, | ||
19 | InFile, | ||
20 | }; | ||
21 | 18 | ||
22 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | 19 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
23 | pub struct ModPath { | 20 | pub struct ModPath { |
@@ -56,8 +53,7 @@ impl Display for ImportAlias { | |||
56 | 53 | ||
57 | impl ModPath { | 54 | impl ModPath { |
58 | pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 55 | pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { |
59 | let ctx = LowerCtx::with_hygiene(db, hygiene); | 56 | lower::convert_path(db, None, path, hygiene) |
60 | lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) | ||
61 | } | 57 | } |
62 | 58 | ||
63 | pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { | 59 | pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { |
@@ -70,18 +66,6 @@ impl ModPath { | |||
70 | ModPath { kind, segments: Vec::new() } | 66 | ModPath { kind, segments: Vec::new() } |
71 | } | 67 | } |
72 | 68 | ||
73 | /// Calls `cb` with all paths, represented by this use item. | ||
74 | pub fn expand_use_item( | ||
75 | db: &dyn DefDatabase, | ||
76 | item_src: InFile<ast::Use>, | ||
77 | hygiene: &Hygiene, | ||
78 | mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), | ||
79 | ) { | ||
80 | if let Some(tree) = item_src.value.use_tree() { | ||
81 | lower::lower_use_tree(db, None, tree, hygiene, &mut cb); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub fn segments(&self) -> &[Name] { | 69 | pub fn segments(&self) -> &[Name] { |
86 | &self.segments | 70 | &self.segments |
87 | } | 71 | } |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 54ede7393..f6220aa92 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 15 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub(super) use lower_use::lower_use_tree; | 18 | pub(super) use lower_use::convert_path; |
19 | 19 | ||
20 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 20 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
21 | /// It correctly handles `$crate` based path from macro call. | 21 | /// It correctly handles `$crate` based path from macro call. |
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs index ee80e3df3..0ee406f63 100644 --- a/crates/hir_def/src/path/lower/lower_use.rs +++ b/crates/hir_def/src/path/lower/lower_use.rs | |||
@@ -4,68 +4,15 @@ | |||
4 | use std::iter; | 4 | use std::iter; |
5 | 5 | ||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{hygiene::Hygiene, name::AsName}; | 7 | use hir_expand::hygiene::Hygiene; |
8 | use syntax::ast::{self, NameOwner}; | 8 | use syntax::{ast, AstNode}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | path::{ImportAlias, ModPath, PathKind}, | 12 | path::{ModPath, PathKind}, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(crate) fn lower_use_tree( | 15 | pub(crate) fn convert_path( |
16 | db: &dyn DefDatabase, | ||
17 | prefix: Option<ModPath>, | ||
18 | tree: ast::UseTree, | ||
19 | hygiene: &Hygiene, | ||
20 | cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<ImportAlias>), | ||
21 | ) { | ||
22 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
23 | let prefix = match tree.path() { | ||
24 | // E.g. use something::{{{inner}}}; | ||
25 | None => prefix, | ||
26 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
27 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
28 | Some(path) => match convert_path(db, prefix, path, hygiene) { | ||
29 | Some(it) => Some(it), | ||
30 | None => return, // FIXME: report errors somewhere | ||
31 | }, | ||
32 | }; | ||
33 | for child_tree in use_tree_list.use_trees() { | ||
34 | lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb); | ||
35 | } | ||
36 | } else { | ||
37 | let alias = tree.rename().map(|a| { | ||
38 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
39 | }); | ||
40 | let is_glob = tree.star_token().is_some(); | ||
41 | if let Some(ast_path) = tree.path() { | ||
42 | // Handle self in a path. | ||
43 | // E.g. `use something::{self, <...>}` | ||
44 | if ast_path.qualifier().is_none() { | ||
45 | if let Some(segment) = ast_path.segment() { | ||
46 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
47 | if let Some(prefix) = prefix { | ||
48 | cb(prefix, &tree, false, alias); | ||
49 | return; | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | if let Some(path) = convert_path(db, prefix, ast_path, hygiene) { | ||
55 | cb(path, &tree, is_glob, alias) | ||
56 | } | ||
57 | // FIXME: report errors somewhere | ||
58 | // We get here if we do | ||
59 | } else if is_glob { | ||
60 | cov_mark::hit!(glob_enum_group); | ||
61 | if let Some(prefix) = prefix { | ||
62 | cb(prefix, &tree, is_glob, None) | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | fn convert_path( | ||
69 | db: &dyn DefDatabase, | 16 | db: &dyn DefDatabase, |
70 | prefix: Option<ModPath>, | 17 | prefix: Option<ModPath>, |
71 | path: ast::Path, | 18 | path: ast::Path, |
@@ -78,7 +25,7 @@ fn convert_path( | |||
78 | }; | 25 | }; |
79 | 26 | ||
80 | let segment = path.segment()?; | 27 | let segment = path.segment()?; |
81 | let res = match segment.kind()? { | 28 | let mut mod_path = match segment.kind()? { |
82 | ast::PathSegmentKind::Name(name_ref) => { | 29 | ast::PathSegmentKind::Name(name_ref) => { |
83 | match hygiene.name_ref_to_name(db.upcast(), name_ref) { | 30 | match hygiene.name_ref_to_name(db.upcast(), name_ref) { |
84 | Either::Left(name) => { | 31 | Either::Left(name) => { |
@@ -125,5 +72,18 @@ fn convert_path( | |||
125 | return None; | 72 | return None; |
126 | } | 73 | } |
127 | }; | 74 | }; |
128 | Some(res) | 75 | |
76 | // handle local_inner_macros : | ||
77 | // Basically, even in rustc it is quite hacky: | ||
78 | // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 | ||
79 | // We follow what it did anyway :) | ||
80 | if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain { | ||
81 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | ||
82 | if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) { | ||
83 | mod_path.kind = PathKind::DollarCrate(crate_id); | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | |||
88 | Some(mod_path) | ||
129 | } | 89 | } |
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 6c357c915..a9c1e13e2 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs | |||
@@ -278,9 +278,11 @@ impl TestDB { | |||
278 | let node = ast.to_node(self.upcast()); | 278 | let node = ast.to_node(self.upcast()); |
279 | (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate") | 279 | (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate") |
280 | } | 280 | } |
281 | DefDiagnosticKind::UnresolvedImport { ast, .. } => { | 281 | DefDiagnosticKind::UnresolvedImport { id, .. } => { |
282 | let node = ast.to_node(self.upcast()); | 282 | let item_tree = id.item_tree(self.upcast()); |
283 | (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedImport") | 283 | let import = &item_tree[id.value]; |
284 | let node = InFile::new(id.file_id(), import.ast_id).to_node(self.upcast()); | ||
285 | (InFile::new(id.file_id(), node.syntax().clone()), "UnresolvedImport") | ||
284 | } | 286 | } |
285 | DefDiagnosticKind::UnconfiguredCode { ast, .. } => { | 287 | DefDiagnosticKind::UnconfiguredCode { ast, .. } => { |
286 | let node = ast.to_node(self.upcast()); | 288 | let node = ast.to_node(self.upcast()); |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index dcac7c76d..6cf5810fa 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -311,6 +311,7 @@ mod tests { | |||
311 | /// * a diagnostic is produced | 311 | /// * a diagnostic is produced |
312 | /// * the first diagnostic fix trigger range touches the input cursor position | 312 | /// * the first diagnostic fix trigger range touches the input cursor position |
313 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | 313 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied |
314 | #[track_caller] | ||
314 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | 315 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { |
315 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); | 316 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); |
316 | } | 317 | } |
@@ -325,6 +326,7 @@ mod tests { | |||
325 | } | 326 | } |
326 | } | 327 | } |
327 | 328 | ||
329 | #[track_caller] | ||
328 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { | 330 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { |
329 | let after = trim_indent(ra_fixture_after); | 331 | let after = trim_indent(ra_fixture_after); |
330 | 332 | ||
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 7f7f4d38a..79c2f4a1e 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -42,13 +42,83 @@ pub struct HlRange { | |||
42 | // Feature: Semantic Syntax Highlighting | 42 | // Feature: Semantic Syntax Highlighting |
43 | // | 43 | // |
44 | // rust-analyzer highlights the code semantically. | 44 | // rust-analyzer highlights the code semantically. |
45 | // For example, `bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. | 45 | // For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. |
46 | // rust-analyzer does not specify colors directly, instead it assigns tag (like `struct`) and a set of modifiers (like `declaration`) to each token. | 46 | // rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token. |
47 | // It's up to the client to map those to specific colors. | 47 | // It's up to the client to map those to specific colors. |
48 | // | 48 | // |
49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. | 49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. |
50 | // We also give special modifier for `mut` and `&mut` local variables. | 50 | // We also give special modifier for `mut` and `&mut` local variables. |
51 | // | 51 | // |
52 | // | ||
53 | // .Token Tags | ||
54 | // | ||
55 | // Rust-analyzer currently emits the following token tags: | ||
56 | // | ||
57 | // - For items: | ||
58 | // + | ||
59 | // [horizontal] | ||
60 | // enum:: Emitted for enums. | ||
61 | // function:: Emitted for free-standing functions. | ||
62 | // macro:: Emitted for macros. | ||
63 | // method:: Emitted for associated functions, also knowns as methods. | ||
64 | // namespace:: Emitted for modules. | ||
65 | // struct:: Emitted for structs. | ||
66 | // trait:: Emitted for traits. | ||
67 | // typeAlias:: Emitted for type aliases and `Self` in `impl`s. | ||
68 | // union:: Emitted for unions. | ||
69 | // | ||
70 | // - For literals: | ||
71 | // + | ||
72 | // [horizontal] | ||
73 | // boolean:: Emitted for the boolean literals `true` and `false`. | ||
74 | // character:: Emitted for character literals. | ||
75 | // number:: Emitted for numeric literals. | ||
76 | // string:: Emitted for string literals. | ||
77 | // escapeSequence:: Emitted for escaped sequences inside strings like `\n`. | ||
78 | // formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros. | ||
79 | // | ||
80 | // - For operators: | ||
81 | // + | ||
82 | // [horizontal] | ||
83 | // operator:: Emitted for general operators. | ||
84 | // arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`. | ||
85 | // bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`. | ||
86 | // comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`. | ||
87 | // logical:: Emitted for the logical operators `||`, `&&`, `!`. | ||
88 | // | ||
89 | // - For punctuation: | ||
90 | // + | ||
91 | // [horizontal] | ||
92 | // punctuation:: Emitted for general punctuation. | ||
93 | // angle:: Emitted for `<>` angle brackets. | ||
94 | // brace:: Emitted for `{}` braces. | ||
95 | // bracket:: Emitted for `[]` brackets. | ||
96 | // parenthesis:: Emitted for `()` parentheses. | ||
97 | // colon:: Emitted for the `:` token. | ||
98 | // comma:: Emitted for the `,` token. | ||
99 | // dot:: Emitted for the `.` token. | ||
100 | // Semi:: Emitted for the `;` token. | ||
101 | // | ||
102 | // //- | ||
103 | // | ||
104 | // [horizontal] | ||
105 | // attribute:: Emitted for attributes. | ||
106 | // builtinType:: Emitted for builtin types like `u32`, `str` and `f32`. | ||
107 | // comment:: Emitted for comments. | ||
108 | // constParameter:: Emitted for const parameters. | ||
109 | // enumMember:: Emitted for enum variants. | ||
110 | // generic:: Emitted for generic tokens that have no mapping. | ||
111 | // keyword:: Emitted for keywords. | ||
112 | // label:: Emitted for labels. | ||
113 | // lifetime:: Emitted for lifetimes. | ||
114 | // parameter:: Emitted for non-self function parameters. | ||
115 | // property:: Emitted for struct and union fields. | ||
116 | // selfKeyword:: Emitted for the self function parameter and self path-specifier. | ||
117 | // typeParameter:: Emitted for type parameters. | ||
118 | // unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of. | ||
119 | // variable:: Emitted for locals, constants and statics. | ||
120 | // | ||
121 | // | ||
52 | // .Token Modifiers | 122 | // .Token Modifiers |
53 | // | 123 | // |
54 | // Token modifiers allow to style some elements in the source code more precisely. | 124 | // Token modifiers allow to style some elements in the source code more precisely. |
@@ -56,10 +126,10 @@ pub struct HlRange { | |||
56 | // Rust-analyzer currently emits the following token modifiers: | 126 | // Rust-analyzer currently emits the following token modifiers: |
57 | // | 127 | // |
58 | // [horizontal] | 128 | // [horizontal] |
59 | // associated:: Emitted for associated items. | ||
60 | // async:: Emitted for async functions and the `async` and `await` keywords. | 129 | // async:: Emitted for async functions and the `async` and `await` keywords. |
61 | // attribute:: Emitted for tokens inside attributes. | 130 | // attribute:: Emitted for tokens inside attributes. |
62 | // callable:: Emitted for locals whose types implements one of the `Fn*` traits. | 131 | // callable:: Emitted for locals whose types implements one of the `Fn*` traits. |
132 | // constant:: Emitted for consts. | ||
63 | // consuming:: Emitted for locals that are being consumed when use in a function call. | 133 | // consuming:: Emitted for locals that are being consumed when use in a function call. |
64 | // controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator. | 134 | // controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator. |
65 | // declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`. | 135 | // declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`. |
@@ -68,7 +138,7 @@ pub struct HlRange { | |||
68 | // intraDocLink:: Emitted for intra doc links in doc-strings. | 138 | // intraDocLink:: Emitted for intra doc links in doc-strings. |
69 | // library:: Emitted for items that are defined outside of the current crate. | 139 | // library:: Emitted for items that are defined outside of the current crate. |
70 | // mutable:: Emitted for mutable locals and statics. | 140 | // mutable:: Emitted for mutable locals and statics. |
71 | // static:: Emitted for "static" functions, also known as functions that do not take a `self` param. | 141 | // static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts. |
72 | // trait:: Emitted for associated trait items. | 142 | // trait:: Emitted for associated trait items. |
73 | // unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token. | 143 | // unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token. |
74 | // | 144 | // |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 6129af95f..db216d951 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -46,7 +46,7 @@ define_semantic_token_types![ | |||
46 | (BRACE, "brace"), | 46 | (BRACE, "brace"), |
47 | (BRACKET, "bracket"), | 47 | (BRACKET, "bracket"), |
48 | (BUILTIN_TYPE, "builtinType"), | 48 | (BUILTIN_TYPE, "builtinType"), |
49 | (CHAR_LITERAL, "characterLiteral"), | 49 | (CHAR, "character"), |
50 | (COLON, "colon"), | 50 | (COLON, "colon"), |
51 | (COMMA, "comma"), | 51 | (COMMA, "comma"), |
52 | (COMPARISON, "comparison"), | 52 | (COMPARISON, "comparison"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index ca9513928..6d18d0ffc 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -466,7 +466,7 @@ fn semantic_token_type_and_modifiers( | |||
466 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, | 466 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, |
467 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, | 467 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, |
468 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, | 468 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, |
469 | HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL, | 469 | HlTag::CharLiteral => semantic_tokens::CHAR, |
470 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, | 470 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, |
471 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, | 471 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, |
472 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, | 472 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index fbe2ce1c9..11a3dd04e 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -25,15 +25,21 @@ rust-analyzer supports clangd's extension for opting into UTF-8 as the coordinat | |||
25 | 25 | ||
26 | https://clangd.llvm.org/extensions.html#utf-8-offsets | 26 | https://clangd.llvm.org/extensions.html#utf-8-offsets |
27 | 27 | ||
28 | ## `initializationOptions` | 28 | ## Configuration in `initializationOptions` |
29 | |||
30 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/567 | ||
31 | |||
32 | The `initializationOptions` filed of the `InitializeParams` of the initialization request should contain `"rust-analyzer"` section of the configuration. | ||
33 | |||
34 | `rust-analyzer` normally sends a `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload. | ||
35 | However, the server can't do this during initialization. | ||
36 | At the same time some essential configuration parameters are needed early on, before servicing requests. | ||
37 | For this reason, we ask that `initializationOptions` contains the configuration, as if the server did make a `"workspace/configuration"` request. | ||
29 | 38 | ||
30 | For `initializationOptions`, `rust-analyzer` expects `"rust-analyzer"` section of the configuration. | ||
31 | That is, `rust-analyzer` usually sends `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload. | ||
32 | `initializationOptions` should contain the same data that would be in the first item of the result. | ||
33 | If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following: | 39 | If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following: |
34 | * Not sending `initializationOptions` | 40 | * Not sending `initializationOptions` |
35 | * Send `"initializationOptions": null` | 41 | * Sending `"initializationOptions": null` |
36 | * Send `"initializationOptions": {}` | 42 | * Sending `"initializationOptions": {}` |
37 | 43 | ||
38 | ## Snippet `TextEdit` | 44 | ## Snippet `TextEdit` |
39 | 45 | ||
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index 7ac9ae5b8..3a67294c5 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -67,7 +67,11 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
67 | fn dist_server(release_channel: &str) -> Result<()> { | 67 | fn dist_server(release_channel: &str) -> Result<()> { |
68 | let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel); | 68 | let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel); |
69 | let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin"); | 69 | let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin"); |
70 | let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1"); | 70 | |
71 | // Uncomment to enable debug info for releases. Note that: | ||
72 | // * debug info is split on windows and macs, so it does nothing for those platforms, | ||
73 | // * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable. | ||
74 | // let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1"); | ||
71 | 75 | ||
72 | let target = get_target(); | 76 | let target = get_target(); |
73 | if target.contains("-linux-gnu") || target.contains("-linux-musl") { | 77 | if target.contains("-linux-gnu") || target.contains("-linux-musl") { |