aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config2
-rw-r--r--ARCHITECTURE.md8
-rw-r--r--README.md2
-rw-r--r--crates/ra_hir/src/code_model_api.rs26
-rw-r--r--crates/ra_hir/src/code_model_impl/function.rs4
-rw-r--r--crates/ra_hir/src/code_model_impl/krate.rs13
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs15
-rw-r--r--crates/ra_hir/src/db.rs25
-rw-r--r--crates/ra_hir/src/expr.rs12
-rw-r--r--crates/ra_hir/src/expr/scope.rs (renamed from crates/ra_hir/src/code_model_impl/function/scope.rs)31
-rw-r--r--crates/ra_hir/src/impl_block.rs57
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/module_tree.rs11
-rw-r--r--crates/ra_hir/src/nameres.rs33
-rw-r--r--crates/ra_hir/src/nameres/tests.rs14
-rw-r--r--crates/ra_hir/src/query_definitions.rs42
-rw-r--r--crates/ra_hir/src/source_binder.rs29
-rw-r--r--crates/ra_hir/src/ty.rs24
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs8
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap23
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_array.snap14
-rw-r--r--crates/ra_hir/src/ty/tests.rs4
-rw-r--r--crates/ra_ide_api/src/call_info.rs66
-rw-r--r--crates/ra_ide_api/src/completion.rs19
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs35
-rw-r--r--crates/ra_ide_api/src/impls.rs120
-rw-r--r--crates/ra_ide_api/src/lib.rs11
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs10
-rw-r--r--crates/ra_lsp_server/src/caps.rs4
-rw-r--r--crates/ra_lsp_server/src/conv.rs19
-rw-r--r--crates/ra_lsp_server/src/lib.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs31
-rw-r--r--crates/ra_lsp_server/src/markdown.rs38
-rw-r--r--crates/ra_lsp_server/src/req.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs6
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/src/grammar/expressions/atom.rs18
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt83
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs5
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt47
-rw-r--r--editors/code/package.json28
-rw-r--r--editors/code/src/commands/runnables.ts3
43 files changed, 663 insertions, 285 deletions
diff --git a/.cargo/config b/.cargo/config
index 3fba0f71d..b12f407e6 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -5,6 +5,8 @@ gen-syntax = "run --package tools --bin tools -- gen-syntax"
5gen-tests = "run --package tools --bin tools -- gen-tests" 5gen-tests = "run --package tools --bin tools -- gen-tests"
6# Installs ra_lsp_server 6# Installs ra_lsp_server
7install-lsp = "install --path crates/ra_lsp_server --force" 7install-lsp = "install --path crates/ra_lsp_server --force"
8# Installs ra_lsp_server with the jemalloc feature
9jinstall-lsp = "install --path crates/ra_lsp_server --force --features jemalloc"
8# Installs the visual studio code extension 10# Installs the visual studio code extension
9install-code = "run --package tools --bin tools -- install-code" 11install-code = "run --package tools --bin tools -- install-code"
10# Formats the full repository or installs the git hook to do it automatically. 12# Formats the full repository or installs the git hook to do it automatically.
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index cb8f01f78..8602de56d 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -178,7 +178,7 @@ VS Code plugin
178 178
179To try out VS Code extensions, run `cargo install-code`. This installs both the 179To try out VS Code extensions, run `cargo install-code`. This installs both the
180`ra_lsp_server` binary and the VS Code extension. To install only the binary, use 180`ra_lsp_server` binary and the VS Code extension. To install only the binary, use
181`cargo install --path crates/ra_lsp_server --force` 181`cargo install-lsp` (shorthand for `cargo install --path crates/ra_lsp_server --force`)
182 182
183To see logs from the language server, set `RUST_LOG=info` env variable. To see 183To see logs from the language server, set `RUST_LOG=info` env variable. To see
184all communication between the server and the client, use 184all communication between the server and the client, use
@@ -186,12 +186,12 @@ all communication between the server and the client, use
186 186
187There's `rust-analyzer: status` command which prints common high-level debug 187There's `rust-analyzer: status` command which prints common high-level debug
188info. In particular, it prints info about memory usage of various data 188info. In particular, it prints info about memory usage of various data
189structures, and, if compiled with jemalloc support (`cargo install --features 189structures, and, if compiled with jemalloc support (`cargo jinstall-lsp` or
190jemalloc`), the summary statistic about the heap. 190`cargo install --path crates/ra_lsp_server --force --features jemalloc`), includes
191 statistic about the heap.
191 192
192To run tests, just `cargo test`. 193To run tests, just `cargo test`.
193 194
194To work on the VS Code extension, launch code inside `editors/code` and use `F5` to 195To work on the VS Code extension, launch code inside `editors/code` and use `F5` to
195launch/debug. To automatically apply formatter and linter suggestions, use `npm 196launch/debug. To automatically apply formatter and linter suggestions, use `npm
196run fix`. 197run fix`.
197
diff --git a/README.md b/README.md
index ad600d162..cffc00953 100644
--- a/README.md
+++ b/README.md
@@ -120,7 +120,7 @@ and trait selection) to the existing rustc.
120- [ ] [textDocument/declaration](https://microsoft.github.io/language-server-protocol/specification#textDocument_declaration) 120- [ ] [textDocument/declaration](https://microsoft.github.io/language-server-protocol/specification#textDocument_declaration)
121- [x] [textDocument/definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) 121- [x] [textDocument/definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition)
122- [ ] [textDocument/typeDefinition](https://microsoft.github.io/language-server-protocol/specification#textDocument_typeDefinition) 122- [ ] [textDocument/typeDefinition](https://microsoft.github.io/language-server-protocol/specification#textDocument_typeDefinition)
123- [ ] [textDocument/implementation](https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation) 123- [x] [textDocument/implementation](https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation)
124- [x] [textDocument/references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references) 124- [x] [textDocument/references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references)
125- [x] [textDocument/documentHighlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight) 125- [x] [textDocument/documentHighlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
126- [x] [textDocument/documentSymbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) 126- [x] [textDocument/documentSymbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol)
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index e4008058c..9405aa8ad 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -10,12 +10,13 @@ use crate::{
10 nameres::{ModuleScope, lower::ImportId}, 10 nameres::{ModuleScope, lower::ImportId},
11 db::HirDatabase, 11 db::HirDatabase,
12 expr::BodySyntaxMapping, 12 expr::BodySyntaxMapping,
13 ty::InferenceResult, 13 ty::{InferenceResult},
14 adt::{EnumVariantId, StructFieldId, VariantDef}, 14 adt::{EnumVariantId, StructFieldId, VariantDef},
15 generics::GenericParams, 15 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 16 docs::{Documentation, Docs, docs_from_ast},
17 module_tree::ModuleId, 17 module_tree::ModuleId,
18 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 18 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
19 impl_block::ImplId,
19}; 20};
20 21
21/// hir::Crate describes a single crate. It's the main interface with which 22/// hir::Crate describes a single crate. It's the main interface with which
@@ -51,7 +52,7 @@ pub enum Def {
51 52
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub struct Module { 54pub struct Module {
54 pub(crate) krate: CrateId, 55 pub(crate) krate: Crate,
55 pub(crate) module_id: ModuleId, 56 pub(crate) module_id: ModuleId,
56} 57}
57 58
@@ -126,9 +127,14 @@ impl Module {
126 self.import_source_impl(db, import) 127 self.import_source_impl(db, import)
127 } 128 }
128 129
130 /// Returns the syntax of the impl block in this module
131 pub fn impl_source(&self, db: &impl HirDatabase, impl_id: ImplId) -> TreeArc<ast::ImplBlock> {
132 self.impl_source_impl(db, impl_id)
133 }
134
129 /// Returns the crate this module is part of. 135 /// Returns the crate this module is part of.
130 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { 136 pub fn krate(&self, _db: &impl HirDatabase) -> Option<Crate> {
131 self.krate_impl(db) 137 Some(self.krate)
132 } 138 }
133 139
134 /// Topmost parent of this module. Every module has a `crate_root`, but some 140 /// Topmost parent of this module. Every module has a `crate_root`, but some
@@ -272,6 +278,10 @@ impl Struct {
272 pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { 278 pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
273 db.generic_params((*self).into()) 279 db.generic_params((*self).into())
274 } 280 }
281
282 pub fn ty(&self, db: &impl HirDatabase) -> Ty {
283 db.type_for_def((*self).into())
284 }
275} 285}
276 286
277impl Docs for Struct { 287impl Docs for Struct {
@@ -317,6 +327,10 @@ impl Enum {
317 pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { 327 pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
318 db.generic_params((*self).into()) 328 db.generic_params((*self).into())
319 } 329 }
330
331 pub fn ty(&self, db: &impl HirDatabase) -> Ty {
332 db.type_for_def((*self).into())
333 }
320} 334}
321 335
322impl Docs for Enum { 336impl Docs for Enum {
@@ -382,7 +396,7 @@ pub struct Function {
382 pub(crate) id: FunctionId, 396 pub(crate) id: FunctionId,
383} 397}
384 398
385pub use crate::code_model_impl::function::ScopeEntryWithSyntax; 399pub use crate::expr::ScopeEntryWithSyntax;
386 400
387/// The declared signature of a function. 401/// The declared signature of a function.
388#[derive(Debug, Clone, PartialEq, Eq)] 402#[derive(Debug, Clone, PartialEq, Eq)]
@@ -433,7 +447,7 @@ impl Function {
433 } 447 }
434 448
435 pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping { 449 pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping {
436 let scopes = db.fn_scopes(*self); 450 let scopes = db.expr_scopes(*self);
437 let syntax_mapping = db.body_syntax_mapping(*self); 451 let syntax_mapping = db.body_syntax_mapping(*self);
438 ScopesWithSyntaxMapping { 452 ScopesWithSyntaxMapping {
439 scopes, 453 scopes,
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index e0dd4d629..422643996 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -1,5 +1,3 @@
1mod scope;
2
3use std::sync::Arc; 1use std::sync::Arc;
4 2
5use ra_syntax::ast::{self, NameOwner}; 3use ra_syntax::ast::{self, NameOwner};
@@ -11,8 +9,6 @@ use crate::{
11 impl_block::ImplBlock, 9 impl_block::ImplBlock,
12}; 10};
13 11
14pub use self::scope::{FnScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
15
16impl Function { 12impl Function {
17 pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc<Body> { 13 pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc<Body> {
18 db.body_hir(*self) 14 db.body_hir(*self)
diff --git a/crates/ra_hir/src/code_model_impl/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs
index cdd30b402..86f29d959 100644
--- a/crates/ra_hir/src/code_model_impl/krate.rs
+++ b/crates/ra_hir/src/code_model_impl/krate.rs
@@ -1,31 +1,28 @@
1use ra_db::CrateId;
2
3use crate::{ 1use crate::{
4 Crate, CrateDependency, AsName, Module, 2 Crate, CrateDependency, AsName, Module,
5 db::HirDatabase, 3 db::HirDatabase,
6}; 4};
7 5
8impl Crate { 6impl Crate {
9 pub(crate) fn new(crate_id: CrateId) -> Crate {
10 Crate { crate_id }
11 }
12 pub(crate) fn dependencies_impl(&self, db: &impl HirDatabase) -> Vec<CrateDependency> { 7 pub(crate) fn dependencies_impl(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
13 let crate_graph = db.crate_graph(); 8 let crate_graph = db.crate_graph();
14 crate_graph 9 crate_graph
15 .dependencies(self.crate_id) 10 .dependencies(self.crate_id)
16 .map(|dep| { 11 .map(|dep| {
17 let krate = Crate::new(dep.crate_id()); 12 let krate = Crate {
13 crate_id: dep.crate_id(),
14 };
18 let name = dep.as_name(); 15 let name = dep.as_name();
19 CrateDependency { krate, name } 16 CrateDependency { krate, name }
20 }) 17 })
21 .collect() 18 .collect()
22 } 19 }
23 pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Option<Module> { 20 pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Option<Module> {
24 let module_tree = db.module_tree(self.crate_id); 21 let module_tree = db.module_tree(*self);
25 let module_id = module_tree.modules().next()?; 22 let module_id = module_tree.modules().next()?;
26 23
27 let module = Module { 24 let module = Module {
28 krate: self.crate_id, 25 krate: *self,
29 module_id, 26 module_id,
30 }; 27 };
31 Some(module) 28 Some(module)
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 418d59c91..4a3901b8b 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -3,8 +3,9 @@ use ra_syntax::{ast, SyntaxNode, TreeArc};
3 3
4use crate::{ 4use crate::{
5 Module, ModuleSource, Problem, 5 Module, ModuleSource, Problem,
6 Crate, Name, 6 Name,
7 module_tree::ModuleId, 7 module_tree::ModuleId,
8 impl_block::ImplId,
8 nameres::{lower::ImportId}, 9 nameres::{lower::ImportId},
9 db::HirDatabase, 10 db::HirDatabase,
10}; 11};
@@ -51,13 +52,19 @@ impl Module {
51 db: &impl HirDatabase, 52 db: &impl HirDatabase,
52 import: ImportId, 53 import: ImportId,
53 ) -> TreeArc<ast::PathSegment> { 54 ) -> TreeArc<ast::PathSegment> {
54 let source_map = db.lower_module_source_map(self.clone()); 55 let source_map = db.lower_module_source_map(*self);
55 let (_, source) = self.definition_source(db); 56 let (_, source) = self.definition_source(db);
56 source_map.get(&source, import) 57 source_map.get(&source, import)
57 } 58 }
58 59
59 pub(crate) fn krate_impl(&self, _db: &impl HirDatabase) -> Option<Crate> { 60 pub(crate) fn impl_source_impl(
60 Some(Crate::new(self.krate)) 61 &self,
62 db: &impl HirDatabase,
63 impl_id: ImplId,
64 ) -> TreeArc<ast::ImplBlock> {
65 let source_map = db.impls_in_module_source_map(*self);
66 let (_, source) = self.definition_source(db);
67 source_map.get(&source, impl_id)
61 } 68 }
62 69
63 pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Module { 70 pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Module {
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 3f76b769d..189649841 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,20 +1,20 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, CrateId, salsa}; 4use ra_db::{SourceDatabase, salsa};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 MacroCallId, HirFileId,
8 SourceFileItems, SourceItemId, Crate, Module, HirInterner, 8 SourceFileItems, SourceItemId, Crate, Module, HirInterner,
9 query_definitions, 9 query_definitions,
10 Function, FnSignature, FnScopes, 10 Function, FnSignature, ExprScopes,
11 Struct, Enum, StructField, 11 Struct, Enum, StructField,
12 macros::MacroExpansion, 12 macros::MacroExpansion,
13 module_tree::ModuleTree, 13 module_tree::ModuleTree,
14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, 14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef}, 15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
16 adt::{StructData, EnumData}, 16 adt::{StructData, EnumData},
17 impl_block::ModuleImplBlocks, 17 impl_block::{ModuleImplBlocks, ImplSourceMap},
18 generics::{GenericParams, GenericDef}, 18 generics::{GenericParams, GenericDef},
19 ids::SourceFileItemId, 19 ids::SourceFileItemId,
20}; 20};
@@ -27,8 +27,8 @@ pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> {
27 #[salsa::invoke(crate::macros::expand_macro_invocation)] 27 #[salsa::invoke(crate::macros::expand_macro_invocation)]
28 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>; 28 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
29 29
30 #[salsa::invoke(query_definitions::fn_scopes)] 30 #[salsa::invoke(ExprScopes::expr_scopes_query)]
31 fn fn_scopes(&self, func: Function) -> Arc<FnScopes>; 31 fn expr_scopes(&self, func: Function) -> Arc<ExprScopes>;
32 32
33 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 33 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
34 fn struct_data(&self, s: Struct) -> Arc<StructData>; 34 fn struct_data(&self, s: Struct) -> Arc<StructData>;
@@ -67,15 +67,24 @@ pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> {
67 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_source_map_query)] 67 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_source_map_query)]
68 fn lower_module_source_map(&self, module: Module) -> Arc<ImportSourceMap>; 68 fn lower_module_source_map(&self, module: Module) -> Arc<ImportSourceMap>;
69 69
70 #[salsa::invoke(query_definitions::item_map)] 70 #[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
71 fn item_map(&self, crate_id: CrateId) -> Arc<ItemMap>; 71 fn item_map(&self, krate: Crate) -> Arc<ItemMap>;
72 72
73 #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)] 73 #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)]
74 fn module_tree(&self, crate_id: CrateId) -> Arc<ModuleTree>; 74 fn module_tree(&self, krate: Crate) -> Arc<ModuleTree>;
75
76 #[salsa::invoke(crate::impl_block::impls_in_module_with_source_map_query)]
77 fn impls_in_module_with_source_map(
78 &self,
79 module: Module,
80 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>);
75 81
76 #[salsa::invoke(crate::impl_block::impls_in_module)] 82 #[salsa::invoke(crate::impl_block::impls_in_module)]
77 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; 83 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;
78 84
85 #[salsa::invoke(crate::impl_block::impls_in_module_source_map_query)]
86 fn impls_in_module_source_map(&self, module: Module) -> Arc<ImplSourceMap>;
87
79 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] 88 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
80 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; 89 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;
81 90
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 60d997bbe..37aa24677 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -16,6 +16,10 @@ use crate::{
16}; 16};
17use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; 17use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy};
18 18
19pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
20
21mod scope;
22
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct ExprId(RawId); 24pub struct ExprId(RawId);
21impl_arena_id!(ExprId); 25impl_arena_id!(ExprId);
@@ -215,7 +219,7 @@ pub use ra_syntax::ast::BinOp as BinaryOp;
215#[derive(Debug, Clone, Eq, PartialEq)] 219#[derive(Debug, Clone, Eq, PartialEq)]
216pub struct MatchArm { 220pub struct MatchArm {
217 pub pats: Vec<PatId>, 221 pub pats: Vec<PatId>,
218 // guard: Option<ExprId>, // TODO 222 pub guard: Option<ExprId>,
219 pub expr: ExprId, 223 pub expr: ExprId,
220} 224}
221 225
@@ -511,10 +515,12 @@ impl ExprCollector {
511 MatchArm { 515 MatchArm {
512 pats: vec![pat], 516 pats: vec![pat],
513 expr: then_branch, 517 expr: then_branch,
518 guard: None,
514 }, 519 },
515 MatchArm { 520 MatchArm {
516 pats: vec![placeholder_pat], 521 pats: vec![placeholder_pat],
517 expr: else_branch, 522 expr: else_branch,
523 guard: None,
518 }, 524 },
519 ]; 525 ];
520 self.alloc_expr( 526 self.alloc_expr(
@@ -613,6 +619,10 @@ impl ExprCollector {
613 .map(|arm| MatchArm { 619 .map(|arm| MatchArm {
614 pats: arm.pats().map(|p| self.collect_pat(p)).collect(), 620 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
615 expr: self.collect_expr_opt(arm.expr()), 621 expr: self.collect_expr_opt(arm.expr()),
622 guard: arm
623 .guard()
624 .and_then(|guard| guard.expr())
625 .map(|e| self.collect_expr(e)),
616 }) 626 })
617 .collect() 627 .collect()
618 } else { 628 } else {
diff --git a/crates/ra_hir/src/code_model_impl/function/scope.rs b/crates/ra_hir/src/expr/scope.rs
index c5d1de5eb..f8b5ba581 100644
--- a/crates/ra_hir/src/code_model_impl/function/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -9,14 +9,18 @@ use ra_syntax::{
9}; 9};
10use ra_arena::{Arena, RawId, impl_arena_id}; 10use ra_arena::{Arena, RawId, impl_arena_id};
11 11
12use crate::{Name, AsName, expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySyntaxMapping}}; 12use crate::{
13 Name, AsName, Function,
14 expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySyntaxMapping},
15 db::HirDatabase,
16};
13 17
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct ScopeId(RawId); 19pub struct ScopeId(RawId);
16impl_arena_id!(ScopeId); 20impl_arena_id!(ScopeId);
17 21
18#[derive(Debug, PartialEq, Eq)] 22#[derive(Debug, PartialEq, Eq)]
19pub struct FnScopes { 23pub struct ExprScopes {
20 body: Arc<Body>, 24 body: Arc<Body>,
21 scopes: Arena<ScopeId, ScopeData>, 25 scopes: Arena<ScopeId, ScopeData>,
22 scope_for: FxHashMap<ExprId, ScopeId>, 26 scope_for: FxHashMap<ExprId, ScopeId>,
@@ -34,9 +38,16 @@ pub struct ScopeData {
34 entries: Vec<ScopeEntry>, 38 entries: Vec<ScopeEntry>,
35} 39}
36 40
37impl FnScopes { 41impl ExprScopes {
38 pub(crate) fn new(body: Arc<Body>) -> FnScopes { 42 // TODO: This should take something more general than Function
39 let mut scopes = FnScopes { 43 pub(crate) fn expr_scopes_query(db: &impl HirDatabase, function: Function) -> Arc<ExprScopes> {
44 let body = db.body_hir(function);
45 let res = ExprScopes::new(body);
46 Arc::new(res)
47 }
48
49 fn new(body: Arc<Body>) -> ExprScopes {
50 let mut scopes = ExprScopes {
40 body: body.clone(), 51 body: body.clone(),
41 scopes: Arena::default(), 52 scopes: Arena::default(),
42 scope_for: FxHashMap::default(), 53 scope_for: FxHashMap::default(),
@@ -119,7 +130,7 @@ impl FnScopes {
119#[derive(Debug, Clone, PartialEq, Eq)] 130#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct ScopesWithSyntaxMapping { 131pub struct ScopesWithSyntaxMapping {
121 pub syntax_mapping: Arc<BodySyntaxMapping>, 132 pub syntax_mapping: Arc<BodySyntaxMapping>,
122 pub scopes: Arc<FnScopes>, 133 pub scopes: Arc<ExprScopes>,
123} 134}
124 135
125#[derive(Debug, Clone, PartialEq, Eq)] 136#[derive(Debug, Clone, PartialEq, Eq)]
@@ -249,7 +260,7 @@ fn compute_block_scopes(
249 statements: &[Statement], 260 statements: &[Statement],
250 tail: Option<ExprId>, 261 tail: Option<ExprId>,
251 body: &Body, 262 body: &Body,
252 scopes: &mut FnScopes, 263 scopes: &mut ExprScopes,
253 mut scope: ScopeId, 264 mut scope: ScopeId,
254) { 265) {
255 for stmt in statements { 266 for stmt in statements {
@@ -275,7 +286,7 @@ fn compute_block_scopes(
275 } 286 }
276} 287}
277 288
278fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut FnScopes, scope: ScopeId) { 289fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) {
279 scopes.set_scope(expr, scope); 290 scopes.set_scope(expr, scope);
280 match &body[expr] { 291 match &body[expr] {
281 Expr::Block { statements, tail } => { 292 Expr::Block { statements, tail } => {
@@ -344,7 +355,7 @@ mod tests {
344 let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 355 let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
345 let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 356 let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
346 let body_hir = expr::collect_fn_body_syntax(fn_def); 357 let body_hir = expr::collect_fn_body_syntax(fn_def);
347 let scopes = FnScopes::new(Arc::clone(body_hir.body())); 358 let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
348 let scopes = ScopesWithSyntaxMapping { 359 let scopes = ScopesWithSyntaxMapping {
349 scopes: Arc::new(scopes), 360 scopes: Arc::new(scopes),
350 syntax_mapping: Arc::new(body_hir), 361 syntax_mapping: Arc::new(body_hir),
@@ -444,7 +455,7 @@ mod tests {
444 let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 455 let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
445 456
446 let body_hir = expr::collect_fn_body_syntax(fn_def); 457 let body_hir = expr::collect_fn_body_syntax(fn_def);
447 let scopes = FnScopes::new(Arc::clone(body_hir.body())); 458 let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
448 let scopes = ScopesWithSyntaxMapping { 459 let scopes = ScopesWithSyntaxMapping {
449 scopes: Arc::new(scopes), 460 scopes: Arc::new(scopes),
450 syntax_mapping: Arc::new(body_hir), 461 syntax_mapping: Arc::new(body_hir),
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 222e47349..5fc26324a 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -1,8 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use ra_arena::{Arena, RawId, impl_arena_id}; 4use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
5use ra_syntax::ast::{self, AstNode}; 5use ra_syntax::{
6 AstPtr, SourceFile, TreeArc,
7ast::{self, AstNode}};
6 8
7use crate::{ 9use crate::{
8 Const, Type, 10 Const, Type,
@@ -14,6 +16,26 @@ use crate::{
14 16
15use crate::code_model_api::{Module, ModuleSource}; 17use crate::code_model_api::{Module, ModuleSource};
16 18
19#[derive(Debug, Default, PartialEq, Eq)]
20pub struct ImplSourceMap {
21 map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>,
22}
23
24impl ImplSourceMap {
25 fn insert(&mut self, impl_id: ImplId, impl_block: &ast::ImplBlock) {
26 self.map.insert(impl_id, AstPtr::new(impl_block))
27 }
28
29 pub fn get(&self, source: &ModuleSource, impl_id: ImplId) -> TreeArc<ast::ImplBlock> {
30 let file = match source {
31 ModuleSource::SourceFile(file) => &*file,
32 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
33 };
34
35 self.map[impl_id].to_node(file).to_owned()
36 }
37}
38
17#[derive(Debug, Clone, PartialEq, Eq)] 39#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ImplBlock { 40pub struct ImplBlock {
19 module_impl_blocks: Arc<ModuleImplBlocks>, 41 module_impl_blocks: Arc<ModuleImplBlocks>,
@@ -39,6 +61,10 @@ impl ImplBlock {
39 } 61 }
40 } 62 }
41 63
64 pub fn id(&self) -> ImplId {
65 self.impl_id
66 }
67
42 fn impl_data(&self) -> &ImplData { 68 fn impl_data(&self) -> &ImplData {
43 &self.module_impl_blocks.impls[self.impl_id] 69 &self.module_impl_blocks.impls[self.impl_id]
44 } 70 }
@@ -148,7 +174,7 @@ impl ModuleImplBlocks {
148 } 174 }
149 } 175 }
150 176
151 fn collect(&mut self, db: &impl HirDatabase, module: Module) { 177 fn collect(&mut self, db: &impl HirDatabase, module: Module, source_map: &mut ImplSourceMap) {
152 let (file_id, module_source) = module.definition_source(db); 178 let (file_id, module_source) = module.definition_source(db);
153 let file_id: HirFileId = file_id.into(); 179 let file_id: HirFileId = file_id.into();
154 let node = match &module_source { 180 let node = match &module_source {
@@ -165,12 +191,31 @@ impl ModuleImplBlocks {
165 for &impl_item in &self.impls[id].items { 191 for &impl_item in &self.impls[id].items {
166 self.impls_by_def.insert(impl_item, id); 192 self.impls_by_def.insert(impl_item, id);
167 } 193 }
194
195 source_map.insert(id, impl_block_ast);
168 } 196 }
169 } 197 }
170} 198}
171 199
172pub(crate) fn impls_in_module(db: &impl HirDatabase, module: Module) -> Arc<ModuleImplBlocks> { 200pub(crate) fn impls_in_module_with_source_map_query(
201 db: &impl HirDatabase,
202 module: Module,
203) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
204 let mut source_map = ImplSourceMap::default();
205
173 let mut result = ModuleImplBlocks::new(); 206 let mut result = ModuleImplBlocks::new();
174 result.collect(db, module); 207 result.collect(db, module, &mut source_map);
175 Arc::new(result) 208
209 (Arc::new(result), Arc::new(source_map))
210}
211
212pub(crate) fn impls_in_module(db: &impl HirDatabase, module: Module) -> Arc<ModuleImplBlocks> {
213 db.impls_in_module_with_source_map(module).0
214}
215
216pub(crate) fn impls_in_module_source_map_query(
217 db: &impl HirDatabase,
218 module: Module,
219) -> Arc<ImplSourceMap> {
220 db.impls_in_module_with_source_map(module).1
176} 221}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index eaf8565ee..0b9ee63bf 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -57,9 +57,9 @@ pub use self::{
57 nameres::{ItemMap, PerNs, Namespace, Resolution}, 57 nameres::{ItemMap, PerNs, Namespace, Resolution},
58 ty::Ty, 58 ty::Ty,
59 impl_block::{ImplBlock, ImplItem}, 59 impl_block::{ImplBlock, ImplItem},
60 code_model_impl::function::{FnScopes, ScopesWithSyntaxMapping},
61 docs::{Docs, Documentation}, 60 docs::{Docs, Documentation},
62 adt::AdtDef, 61 adt::AdtDef,
62 expr::{ExprScopes, ScopesWithSyntaxMapping},
63}; 63};
64 64
65pub use self::code_model_api::{ 65pub use self::code_model_api::{
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index 893c375b5..1f327eeb2 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -2,7 +2,7 @@ use std::sync::Arc;
2 2
3use arrayvec::ArrayVec; 3use arrayvec::ArrayVec;
4use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
5use ra_db::{FileId, SourceRoot, CrateId}; 5use ra_db::{FileId, SourceRoot};
6use ra_syntax::{ 6use ra_syntax::{
7 SyntaxNode, TreeArc, 7 SyntaxNode, TreeArc,
8 algo::generate, 8 algo::generate,
@@ -13,6 +13,7 @@ use test_utils::tested_by;
13 13
14use crate::{ 14use crate::{
15 Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource, 15 Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource,
16 Crate,
16 ids::SourceFileItemId, 17 ids::SourceFileItemId,
17}; 18};
18 19
@@ -132,10 +133,10 @@ struct LinkData {
132} 133}
133 134
134impl ModuleTree { 135impl ModuleTree {
135 pub(crate) fn module_tree_query(db: &impl HirDatabase, crate_id: CrateId) -> Arc<ModuleTree> { 136 pub(crate) fn module_tree_query(db: &impl HirDatabase, krate: Crate) -> Arc<ModuleTree> {
136 db.check_canceled(); 137 db.check_canceled();
137 let mut res = ModuleTree::default(); 138 let mut res = ModuleTree::default();
138 res.init_crate(db, crate_id); 139 res.init_crate(db, krate);
139 Arc::new(res) 140 Arc::new(res)
140 } 141 }
141 142
@@ -155,9 +156,9 @@ impl ModuleTree {
155 Some(res) 156 Some(res)
156 } 157 }
157 158
158 fn init_crate(&mut self, db: &impl HirDatabase, crate_id: CrateId) { 159 fn init_crate(&mut self, db: &impl HirDatabase, krate: Crate) {
159 let crate_graph = db.crate_graph(); 160 let crate_graph = db.crate_graph();
160 let file_id = crate_graph.crate_root(crate_id); 161 let file_id = crate_graph.crate_root(krate.crate_id);
161 let source_root_id = db.file_source_root(file_id); 162 let source_root_id = db.file_source_root(file_id);
162 163
163 let source_root = db.source_root(source_root_id); 164 let source_root = db.source_root(source_root_id);
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 97ce6c946..4573a72ba 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -16,9 +16,8 @@
16//! structure itself is modified. 16//! structure itself is modified.
17pub(crate) mod lower; 17pub(crate) mod lower;
18 18
19use std::sync::Arc; 19use std::{time, sync::Arc};
20 20
21use ra_db::CrateId;
22use ra_arena::map::ArenaMap; 21use ra_arena::map::ArenaMap;
23use test_utils::tested_by; 22use test_utils::tested_by;
24use rustc_hash::{FxHashMap, FxHashSet}; 23use rustc_hash::{FxHashMap, FxHashSet};
@@ -156,10 +155,10 @@ impl<T> PerNs<T> {
156 } 155 }
157} 156}
158 157
159pub(crate) struct Resolver<'a, DB> { 158struct Resolver<'a, DB> {
160 db: &'a DB, 159 db: &'a DB,
161 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>, 160 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
162 krate: CrateId, 161 krate: Crate,
163 module_tree: Arc<ModuleTree>, 162 module_tree: Arc<ModuleTree>,
164 processed_imports: FxHashSet<(ModuleId, ImportId)>, 163 processed_imports: FxHashSet<(ModuleId, ImportId)>,
165 result: ItemMap, 164 result: ItemMap,
@@ -169,10 +168,10 @@ impl<'a, DB> Resolver<'a, DB>
169where 168where
170 DB: HirDatabase, 169 DB: HirDatabase,
171{ 170{
172 pub(crate) fn new( 171 fn new(
173 db: &'a DB, 172 db: &'a DB,
174 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>, 173 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
175 krate: CrateId, 174 krate: Crate,
176 ) -> Resolver<'a, DB> { 175 ) -> Resolver<'a, DB> {
177 let module_tree = db.module_tree(krate); 176 let module_tree = db.module_tree(krate);
178 Resolver { 177 Resolver {
@@ -219,7 +218,7 @@ where
219 let crate_graph = self.db.crate_graph(); 218 let crate_graph = self.db.crate_graph();
220 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) 219 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
221 { 220 {
222 let krate = Crate::new(crate_id); 221 let krate = Crate { crate_id };
223 for dep in krate.dependencies(self.db) { 222 for dep in krate.dependencies(self.db) {
224 if let Some(module) = dep.krate.root_module(self.db) { 223 if let Some(module) = dep.krate.root_module(self.db) {
225 let def = module.into(); 224 let def = module.into();
@@ -331,6 +330,26 @@ enum ReachedFixedPoint {
331} 330}
332 331
333impl ItemMap { 332impl ItemMap {
333 pub(crate) fn item_map_query(db: &impl HirDatabase, krate: Crate) -> Arc<ItemMap> {
334 let start = time::Instant::now();
335 let module_tree = db.module_tree(krate);
336 let input = module_tree
337 .modules()
338 .map(|module_id| {
339 (
340 module_id,
341 db.lower_module_module(Module { krate, module_id }),
342 )
343 })
344 .collect::<FxHashMap<_, _>>();
345
346 let resolver = Resolver::new(db, &input, krate);
347 let res = resolver.resolve();
348 let elapsed = start.elapsed();
349 log::info!("item_map: {:?}", elapsed);
350 Arc::new(res)
351 }
352
334 pub(crate) fn resolve_path( 353 pub(crate) fn resolve_path(
335 &self, 354 &self,
336 db: &impl HirDatabase, 355 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 3d420467c..9c5ca097e 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -16,7 +16,7 @@ fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
16 let module = crate::source_binder::module_from_position(&db, pos).unwrap(); 16 let module = crate::source_binder::module_from_position(&db, pos).unwrap();
17 let krate = module.krate(&db).unwrap(); 17 let krate = module.krate(&db).unwrap();
18 let module_id = module.module_id; 18 let module_id = module.module_id;
19 (db.item_map(krate.crate_id), module_id) 19 (db.item_map(krate), module_id)
20} 20}
21 21
22/// Sets the crate root to the file of the cursor marker 22/// Sets the crate root to the file of the cursor marker
@@ -30,7 +30,7 @@ fn item_map_custom_crate_root(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
30 let module = crate::source_binder::module_from_position(&db, pos).unwrap(); 30 let module = crate::source_binder::module_from_position(&db, pos).unwrap();
31 let krate = module.krate(&db).unwrap(); 31 let krate = module.krate(&db).unwrap();
32 let module_id = module.module_id; 32 let module_id = module.module_id;
33 (db.item_map(krate.crate_id), module_id) 33 (db.item_map(krate), module_id)
34} 34}
35 35
36fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { 36fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
@@ -297,7 +297,7 @@ fn item_map_across_crates() {
297 297
298 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 298 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
299 let krate = module.krate(&db).unwrap(); 299 let krate = module.krate(&db).unwrap();
300 let item_map = db.item_map(krate.crate_id); 300 let item_map = db.item_map(krate);
301 301
302 check_module_item_map( 302 check_module_item_map(
303 &item_map, 303 &item_map,
@@ -349,7 +349,7 @@ fn import_across_source_roots() {
349 349
350 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 350 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
351 let krate = module.krate(&db).unwrap(); 351 let krate = module.krate(&db).unwrap();
352 let item_map = db.item_map(krate.crate_id); 352 let item_map = db.item_map(krate);
353 353
354 check_module_item_map( 354 check_module_item_map(
355 &item_map, 355 &item_map,
@@ -391,7 +391,7 @@ fn reexport_across_crates() {
391 391
392 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 392 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
393 let krate = module.krate(&db).unwrap(); 393 let krate = module.krate(&db).unwrap();
394 let item_map = db.item_map(krate.crate_id); 394 let item_map = db.item_map(krate);
395 395
396 check_module_item_map( 396 check_module_item_map(
397 &item_map, 397 &item_map,
@@ -409,7 +409,7 @@ fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
409 let krate = module.krate(&db).unwrap(); 409 let krate = module.krate(&db).unwrap();
410 { 410 {
411 let events = db.log_executed(|| { 411 let events = db.log_executed(|| {
412 db.item_map(krate.crate_id); 412 db.item_map(krate);
413 }); 413 });
414 assert!(format!("{:?}", events).contains("item_map")) 414 assert!(format!("{:?}", events).contains("item_map"))
415 } 415 }
@@ -417,7 +417,7 @@ fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
417 417
418 { 418 {
419 let events = db.log_executed(|| { 419 let events = db.log_executed(|| {
420 db.item_map(krate.crate_id); 420 db.item_map(krate);
421 }); 421 });
422 assert!( 422 assert!(
423 !format!("{:?}", events).contains("item_map"), 423 !format!("{:?}", events).contains("item_map"),
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index bf9ac0dfb..734a98282 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -1,25 +1,14 @@
1use std::{ 1use std::sync::Arc;
2 sync::Arc,
3 time::Instant,
4};
5 2
6use rustc_hash::FxHashMap; 3use ra_syntax::{
7use ra_syntax::{SyntaxNode, TreeArc}; 4 SyntaxNode, TreeArc,
8use ra_db::{CrateId}; 5};
9 6
10use crate::{ 7use crate::{
11 SourceFileItems, SourceItemId, HirFileId, 8 SourceFileItems, SourceItemId, HirFileId,
12 Function, FnScopes, Module,
13 db::HirDatabase, 9 db::HirDatabase,
14 nameres::{ItemMap, Resolver},
15}; 10};
16 11
17pub(super) fn fn_scopes(db: &impl HirDatabase, func: Function) -> Arc<FnScopes> {
18 let body = db.body_hir(func);
19 let res = FnScopes::new(body);
20 Arc::new(res)
21}
22
23pub(super) fn file_items(db: &impl HirDatabase, file_id: HirFileId) -> Arc<SourceFileItems> { 12pub(super) fn file_items(db: &impl HirDatabase, file_id: HirFileId) -> Arc<SourceFileItems> {
24 let source_file = db.hir_parse(file_id); 13 let source_file = db.hir_parse(file_id);
25 let res = SourceFileItems::new(file_id, &source_file); 14 let res = SourceFileItems::new(file_id, &source_file);
@@ -35,26 +24,3 @@ pub(super) fn file_item(
35 .to_node(&source_file) 24 .to_node(&source_file)
36 .to_owned() 25 .to_owned()
37} 26}
38
39pub(super) fn item_map(db: &impl HirDatabase, crate_id: CrateId) -> Arc<ItemMap> {
40 let start = Instant::now();
41 let module_tree = db.module_tree(crate_id);
42 let input = module_tree
43 .modules()
44 .map(|module_id| {
45 (
46 module_id,
47 db.lower_module_module(Module {
48 krate: crate_id,
49 module_id,
50 }),
51 )
52 })
53 .collect::<FxHashMap<_, _>>();
54
55 let resolver = Resolver::new(db, &input, crate_id);
56 let res = resolver.resolve();
57 let elapsed = start.elapsed();
58 log::info!("item_map: {:?}", elapsed);
59 Arc::new(res)
60}
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index f523f0647..d1eaccf23 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -13,8 +13,8 @@ use ra_syntax::{
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, ModuleDef, 16 HirDatabase, Function, ModuleDef, Struct, Enum,
17 AsName, Module, HirFileId, 17 AsName, Module, HirFileId, Crate,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::{LocationCtx, SourceFileItemId},
19}; 19};
20 20
@@ -83,7 +83,8 @@ fn module_from_source(
83 let source_root_id = db.file_source_root(file_id.as_original_file()); 83 let source_root_id = db.file_source_root(file_id.as_original_file());
84 db.source_root_crates(source_root_id) 84 db.source_root_crates(source_root_id)
85 .iter() 85 .iter()
86 .find_map(|&krate| { 86 .map(|&crate_id| Crate { crate_id })
87 .find_map(|krate| {
87 let module_tree = db.module_tree(krate); 88 let module_tree = db.module_tree(krate);
88 let module_id = module_tree.find_module_by_source(file_id, decl_id)?; 89 let module_id = module_tree.find_module_by_source(file_id, decl_id)?;
89 Some(Module { krate, module_id }) 90 Some(Module { krate, module_id })
@@ -128,6 +129,28 @@ pub fn function_from_child_node(
128 function_from_source(db, file_id, fn_def) 129 function_from_source(db, file_id, fn_def)
129} 130}
130 131
132pub fn struct_from_module(
133 db: &impl HirDatabase,
134 module: Module,
135 struct_def: &ast::StructDef,
136) -> Struct {
137 let (file_id, _) = module.definition_source(db);
138 let file_id = file_id.into();
139 let ctx = LocationCtx::new(db, module, file_id);
140 Struct {
141 id: ctx.to_def(struct_def),
142 }
143}
144
145pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
146 let (file_id, _) = module.definition_source(db);
147 let file_id = file_id.into();
148 let ctx = LocationCtx::new(db, module, file_id);
149 Enum {
150 id: ctx.to_def(enum_def),
151 }
152}
153
131pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> { 154pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> {
132 let module = match module_from_file_id(db, file_id) { 155 let module = match module_from_file_id(db, file_id) {
133 Some(it) => it, 156 Some(it) => it,
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 7a5485698..60c231e82 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -34,7 +34,7 @@ use test_utils::tested_by;
34 34
35use crate::{ 35use crate::{
36 Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, 36 Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock,
37 FnSignature, FnScopes, ModuleDef, AdtDef, 37 FnSignature, ExprScopes, ModuleDef, AdtDef,
38 db::HirDatabase, 38 db::HirDatabase,
39 type_ref::{TypeRef, Mutability}, 39 type_ref::{TypeRef, Mutability},
40 name::KnownName, 40 name::KnownName,
@@ -814,7 +814,7 @@ impl Index<PatId> for InferenceResult {
814struct InferenceContext<'a, D: HirDatabase> { 814struct InferenceContext<'a, D: HirDatabase> {
815 db: &'a D, 815 db: &'a D,
816 body: Arc<Body>, 816 body: Arc<Body>,
817 scopes: Arc<FnScopes>, 817 scopes: Arc<ExprScopes>,
818 module: Module, 818 module: Module,
819 impl_block: Option<ImplBlock>, 819 impl_block: Option<ImplBlock>,
820 var_unification_table: InPlaceUnificationTable<TypeVarId>, 820 var_unification_table: InPlaceUnificationTable<TypeVarId>,
@@ -908,7 +908,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
908 fn new( 908 fn new(
909 db: &'a D, 909 db: &'a D,
910 body: Arc<Body>, 910 body: Arc<Body>,
911 scopes: Arc<FnScopes>, 911 scopes: Arc<ExprScopes>,
912 module: Module, 912 module: Module,
913 impl_block: Option<ImplBlock>, 913 impl_block: Option<ImplBlock>,
914 ) -> Self { 914 ) -> Self {
@@ -1488,7 +1488,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1488 for &pat in &arm.pats { 1488 for &pat in &arm.pats {
1489 let _pat_ty = self.infer_pat(pat, &input_ty); 1489 let _pat_ty = self.infer_pat(pat, &input_ty);
1490 } 1490 }
1491 // TODO type the guard 1491 if let Some(guard_expr) = arm.guard {
1492 self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool));
1493 }
1492 self.infer_expr(arm.expr, &expected); 1494 self.infer_expr(arm.expr, &expected);
1493 } 1495 }
1494 1496
@@ -1561,9 +1563,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1561 cast_ty 1563 cast_ty
1562 } 1564 }
1563 Expr::Ref { expr, mutability } => { 1565 Expr::Ref { expr, mutability } => {
1564 // TODO pass the expectation down 1566 let expectation = if let Ty::Ref(ref subty, expected_mutability) = expected.ty {
1565 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 1567 if expected_mutability == Mutability::Mut && *mutability == Mutability::Shared {
1568 // TODO: throw type error - expected mut reference but found shared ref,
1569 // which cannot be coerced
1570 }
1571 Expectation::has_type((**subty).clone())
1572 } else {
1573 Expectation::none()
1574 };
1566 // TODO reference coercions etc. 1575 // TODO reference coercions etc.
1576 let inner_ty = self.infer_expr(*expr, &expectation);
1567 Ty::Ref(Arc::new(inner_ty), *mutability) 1577 Ty::Ref(Arc::new(inner_ty), *mutability)
1568 } 1578 }
1569 Expr::UnaryOp { expr, op } => { 1579 Expr::UnaryOp { expr, op } => {
@@ -1720,7 +1730,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1720pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { 1730pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
1721 db.check_canceled(); 1731 db.check_canceled();
1722 let body = func.body(db); 1732 let body = func.body(db);
1723 let scopes = db.fn_scopes(func); 1733 let scopes = db.expr_scopes(func);
1724 let module = func.module(db); 1734 let module = func.module(db);
1725 let impl_block = func.impl_block(db); 1735 let impl_block = func.impl_block(db);
1726 let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block); 1736 let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 9a571c2aa..37bc3f38c 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -44,7 +44,7 @@ impl CrateImplBlocks {
44 &'a self, 44 &'a self,
45 db: &'a impl HirDatabase, 45 db: &'a impl HirDatabase,
46 ty: &Ty, 46 ty: &Ty,
47 ) -> impl Iterator<Item = ImplBlock> + 'a { 47 ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
48 let fingerprint = TyFingerprint::for_impl(ty); 48 let fingerprint = TyFingerprint::for_impl(ty);
49 fingerprint 49 fingerprint
50 .and_then(|f| self.impls.get(&f)) 50 .and_then(|f| self.impls.get(&f))
@@ -52,11 +52,11 @@ impl CrateImplBlocks {
52 .flat_map(|i| i.iter()) 52 .flat_map(|i| i.iter())
53 .map(move |(module_id, impl_id)| { 53 .map(move |(module_id, impl_id)| {
54 let module = Module { 54 let module = Module {
55 krate: self.krate.crate_id, 55 krate: self.krate,
56 module_id: *module_id, 56 module_id: *module_id,
57 }; 57 };
58 let module_impl_blocks = db.impls_in_module(module); 58 let module_impl_blocks = db.impls_in_module(module);
59 ImplBlock::from_id(module_impl_blocks, *impl_id) 59 (module, ImplBlock::from_id(module_impl_blocks, *impl_id))
60 }) 60 })
61 } 61 }
62 62
@@ -152,7 +152,7 @@ impl Ty {
152 }; 152 };
153 let impls = db.impls_in_crate(krate); 153 let impls = db.impls_in_crate(krate);
154 154
155 for impl_block in impls.lookup_impl_blocks(db, &derefed_ty) { 155 for (_, impl_block) in impls.lookup_impl_blocks(db, &derefed_ty) {
156 for item in impl_block.items() { 156 for item in impl_block.items() {
157 match item { 157 match item {
158 ImplItem::Method(f) => { 158 ImplItem::Method(f) => {
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap
index 2719f592e..48c83cbb2 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap
@@ -1,10 +1,10 @@
1--- 1---
2created: "2019-01-22T14:44:59.880187500+00:00" 2created: "2019-01-28T21:58:55.559331849+00:00"
3creator: insta@0.4.0 3creator: insta@0.5.2
4expression: "&result" 4expression: "&result"
5source: "crates\\ra_hir\\src\\ty\\tests.rs" 5source: crates/ra_hir/src/ty/tests.rs
6--- 6---
7[68; 262) '{ ... d; }': () 7[68; 289) '{ ... d; }': ()
8[78; 79) 'e': E 8[78; 79) 'e': E
9[82; 95) 'E::A { x: 3 }': E 9[82; 95) 'E::A { x: 3 }': E
10[92; 93) '3': usize 10[92; 93) '3': usize
@@ -15,15 +15,18 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs"
15[129; 148) 'E::A {..._var }': E 15[129; 148) 'E::A {..._var }': E
16[139; 146) 'new_var': usize 16[139; 146) 'new_var': usize
17[151; 152) 'e': E 17[151; 152) 'e': E
18[159; 218) 'match ... }': usize 18[159; 245) 'match ... }': usize
19[165; 166) 'e': E 19[165; 166) 'e': E
20[177; 187) 'E::A { x }': E 20[177; 187) 'E::A { x }': E
21[184; 185) 'x': usize 21[184; 185) 'x': usize
22[191; 192) 'x': usize 22[191; 192) 'x': usize
23[202; 206) 'E::B': E 23[202; 206) 'E::B': E
24[210; 211) '1': usize 24[210; 213) 'foo': bool
25[229; 248) 'ref d ...{ .. }': &E 25[217; 218) '1': usize
26[237; 248) 'E::A { .. }': E 26[228; 232) 'E::B': E
27[251; 252) 'e': E 27[236; 238) '10': usize
28[258; 259) 'd': &E 28[256; 275) 'ref d ...{ .. }': &E
29[264; 275) 'E::A { .. }': E
30[278; 279) 'e': E
31[285; 286) 'd': &E
29 32
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap
index 3f2faa598..042248c35 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap
@@ -1,12 +1,12 @@
1--- 1---
2created: "2019-01-22T14:44:59.880187500+00:00" 2created: "2019-01-30T20:08:05.185312835+00:00"
3creator: insta@0.4.0 3creator: insta@0.5.2
4expression: "&result" 4expression: "&result"
5source: "crates\\ra_hir\\src\\ty\\tests.rs" 5source: crates/ra_hir/src/ty/tests.rs
6--- 6---
7[9; 10) 'x': &str 7[9; 10) 'x': &str
8[18; 19) 'y': isize 8[18; 19) 'y': isize
9[28; 293) '{ ... []; }': () 9[28; 324) '{ ... 3]; }': ()
10[38; 39) 'a': [&str] 10[38; 39) 'a': [&str]
11[42; 45) '[x]': [&str] 11[42; 45) '[x]': [&str]
12[43; 44) 'x': &str 12[43; 44) 'x': &str
@@ -56,4 +56,10 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs"
56[260; 263) '"b"': &str 56[260; 263) '"b"': &str
57[275; 276) 'x': [u8] 57[275; 276) 'x': [u8]
58[288; 290) '[]': [u8] 58[288; 290) '[]': [u8]
59[300; 301) 'z': &[u8]
60[311; 321) '&[1, 2, 3]': &[u8]
61[312; 321) '[1, 2, 3]': [u8]
62[313; 314) '1': u8
63[316; 317) '2': u8
64[319; 320) '3': u8
59 65
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index b36e6ec47..cb8d6351d 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -371,6 +371,7 @@ fn test(x: &str, y: isize) {
371 371
372 let b = [a, ["b"]]; 372 let b = [a, ["b"]];
373 let x: [u8; 0] = []; 373 let x: [u8; 0] = [];
374 let z: &[u8] = &[1, 2, 3];
374} 375}
375"#, 376"#,
376 ); 377 );
@@ -426,7 +427,8 @@ fn test() {
426 427
427 match e { 428 match e {
428 E::A { x } => x, 429 E::A { x } => x,
429 E::B => 1, 430 E::B if foo => 1,
431 E::B => 10,
430 }; 432 };
431 433
432 let ref d @ E::A { .. } = e; 434 let ref d @ E::A { .. } = e;
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index ee1e13799..2eb388e0e 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -3,9 +3,10 @@ use ra_db::SourceDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SyntaxNode, TextUnit, TextRange, 4 AstNode, SyntaxNode, TextUnit, TextRange,
5 SyntaxKind::FN_DEF, 5 SyntaxKind::FN_DEF,
6 ast::{self, ArgListOwner, DocCommentsOwner}, 6 ast::{self, ArgListOwner},
7 algo::find_node_at_offset, 7 algo::find_node_at_offset,
8}; 8};
9use hir::Docs;
9 10
10use crate::{FilePosition, CallInfo, db::RootDatabase}; 11use crate::{FilePosition, CallInfo, db::RootDatabase};
11 12
@@ -26,7 +27,9 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
26 let fn_file = db.parse(symbol.file_id); 27 let fn_file = db.parse(symbol.file_id);
27 let fn_def = symbol.ptr.to_node(&fn_file); 28 let fn_def = symbol.ptr.to_node(&fn_file);
28 let fn_def = ast::FnDef::cast(fn_def).unwrap(); 29 let fn_def = ast::FnDef::cast(fn_def).unwrap();
29 let mut call_info = CallInfo::new(fn_def)?; 30 let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?;
31
32 let mut call_info = CallInfo::new(db, function, fn_def)?;
30 // If we have a calling expression let's find which argument we are on 33 // If we have a calling expression let's find which argument we are on
31 let num_params = call_info.parameters.len(); 34 let num_params = call_info.parameters.len();
32 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 35 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
@@ -110,46 +113,13 @@ impl<'a> FnCallNode<'a> {
110} 113}
111 114
112impl CallInfo { 115impl CallInfo {
113 fn new(node: &ast::FnDef) -> Option<Self> { 116 fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option<Self> {
114 let label: String = if let Some(body) = node.body() { 117 let label = crate::completion::function_label(node)?;
115 let body_range = body.syntax().range(); 118 let doc = function.docs(db);
116 let label: String = node
117 .syntax()
118 .children()
119 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
120 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out doc comments
121 .map(|node| node.text().to_string())
122 .collect();
123 label
124 } else {
125 node.syntax().text().to_string()
126 };
127
128 let mut doc = None;
129 if let Some(docs) = node.doc_comment_text() {
130 // Massage markdown
131 let mut processed_lines = Vec::new();
132 let mut in_code_block = false;
133 for line in docs.lines() {
134 if line.starts_with("```") {
135 in_code_block = !in_code_block;
136 }
137
138 let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
139 "```rust".into()
140 } else {
141 line.to_string()
142 };
143
144 processed_lines.push(line);
145 }
146
147 doc = Some(processed_lines.join("\n"));
148 }
149 119
150 Some(CallInfo { 120 Some(CallInfo {
151 parameters: param_list(node), 121 parameters: param_list(node),
152 label: label.trim().to_owned(), 122 label,
153 doc, 123 doc,
154 active_parameter: None, 124 active_parameter: None,
155 }) 125 })
@@ -284,7 +254,7 @@ fn bar() {
284 assert_eq!(info.parameters, vec!["j".to_string()]); 254 assert_eq!(info.parameters, vec!["j".to_string()]);
285 assert_eq!(info.active_parameter, Some(0)); 255 assert_eq!(info.active_parameter, Some(0));
286 assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string()); 256 assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string());
287 assert_eq!(info.doc, Some("test".into())); 257 assert_eq!(info.doc.map(|it| it.into()), Some("test".to_string()));
288 } 258 }
289 259
290 #[test] 260 #[test]
@@ -313,18 +283,18 @@ pub fn do() {
313 assert_eq!(info.active_parameter, Some(0)); 283 assert_eq!(info.active_parameter, Some(0));
314 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 284 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
315 assert_eq!( 285 assert_eq!(
316 info.doc, 286 info.doc.map(|it| it.into()),
317 Some( 287 Some(
318 r#"Adds one to the number given. 288 r#"Adds one to the number given.
319 289
320# Examples 290# Examples
321 291
322```rust 292```
323let five = 5; 293let five = 5;
324 294
325assert_eq!(6, my_crate::add_one(5)); 295assert_eq!(6, my_crate::add_one(5));
326```"# 296```"#
327 .into() 297 .to_string()
328 ) 298 )
329 ); 299 );
330 } 300 }
@@ -359,18 +329,18 @@ pub fn do_it() {
359 assert_eq!(info.active_parameter, Some(0)); 329 assert_eq!(info.active_parameter, Some(0));
360 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 330 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
361 assert_eq!( 331 assert_eq!(
362 info.doc, 332 info.doc.map(|it| it.into()),
363 Some( 333 Some(
364 r#"Adds one to the number given. 334 r#"Adds one to the number given.
365 335
366# Examples 336# Examples
367 337
368```rust 338```
369let five = 5; 339let five = 5;
370 340
371assert_eq!(6, my_crate::add_one(5)); 341assert_eq!(6, my_crate::add_one(5));
372```"# 342```"#
373 .into() 343 .to_string()
374 ) 344 )
375 ); 345 );
376 } 346 }
@@ -414,12 +384,12 @@ pub fn foo() {
414 ); 384 );
415 assert_eq!(info.active_parameter, Some(1)); 385 assert_eq!(info.active_parameter, Some(1));
416 assert_eq!( 386 assert_eq!(
417 info.doc, 387 info.doc.map(|it| it.into()),
418 Some( 388 Some(
419 r#"Method is called when writer finishes. 389 r#"Method is called when writer finishes.
420 390
421By default this method stops actor's `Context`."# 391By default this method stops actor's `Context`."#
422 .into() 392 .to_string()
423 ) 393 )
424 ); 394 );
425 } 395 }
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index b1867de42..722d94f3a 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -10,6 +10,7 @@ mod complete_scope;
10mod complete_postfix; 10mod complete_postfix;
11 11
12use ra_db::SourceDatabase; 12use ra_db::SourceDatabase;
13use ra_syntax::ast::{self, AstNode};
13 14
14use crate::{ 15use crate::{
15 db, 16 db,
@@ -61,3 +62,21 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti
61 complete_postfix::complete_postfix(&mut acc, &ctx); 62 complete_postfix::complete_postfix(&mut acc, &ctx);
62 Some(acc) 63 Some(acc)
63} 64}
65
66pub fn function_label(node: &ast::FnDef) -> Option<String> {
67 let label: String = if let Some(body) = node.body() {
68 let body_range = body.syntax().range();
69 let label: String = node
70 .syntax()
71 .children()
72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
74 .map(|node| node.text().to_string())
75 .collect();
76 label
77 } else {
78 node.syntax().text().to_string()
79 };
80
81 Some(label.trim().to_owned())
82}
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index 49bd636a5..d3bc14894 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -1,12 +1,12 @@
1use hir::{Docs, Documentation}; 1use hir::{Docs, Documentation};
2use ra_syntax::{ 2use ra_syntax::TextRange;
3 ast::{self, AstNode},
4 TextRange,
5};
6use ra_text_edit::TextEdit; 3use ra_text_edit::TextEdit;
7use test_utils::tested_by; 4use test_utils::tested_by;
8 5
9use crate::completion::completion_context::CompletionContext; 6use crate::completion::{
7 completion_context::CompletionContext,
8 function_label,
9};
10 10
11/// `CompletionItem` describes a single completion variant in the editor pop-up. 11/// `CompletionItem` describes a single completion variant in the editor pop-up.
12/// It is basically a POD with various properties. To construct a 12/// It is basically a POD with various properties. To construct a
@@ -97,8 +97,8 @@ impl CompletionItem {
97 self.detail.as_ref().map(|it| it.as_str()) 97 self.detail.as_ref().map(|it| it.as_str())
98 } 98 }
99 /// A doc-comment 99 /// A doc-comment
100 pub fn documentation(&self) -> Option<&str> { 100 pub fn documentation(&self) -> Option<Documentation> {
101 self.documentation.as_ref().map(|it| it.contents()) 101 self.documentation.clone()
102 } 102 }
103 /// What string is used for filtering. 103 /// What string is used for filtering.
104 pub fn lookup(&self) -> &str { 104 pub fn lookup(&self) -> &str {
@@ -252,7 +252,7 @@ impl Builder {
252 self.documentation = Some(docs); 252 self.documentation = Some(docs);
253 } 253 }
254 254
255 if let Some(label) = function_label(ctx, function) { 255 if let Some(label) = function_item_label(ctx, function) {
256 self.detail = Some(label); 256 self.detail = Some(label);
257 } 257 }
258 258
@@ -292,24 +292,9 @@ impl Into<Vec<CompletionItem>> for Completions {
292 } 292 }
293} 293}
294 294
295fn function_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> { 295fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
296 let node = function.source(ctx.db).1; 296 let node = function.source(ctx.db).1;
297 297 function_label(&node)
298 let label: String = if let Some(body) = node.body() {
299 let body_range = body.syntax().range();
300 let label: String = node
301 .syntax()
302 .children()
303 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
304 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
305 .map(|node| node.text().to_string())
306 .collect();
307 label
308 } else {
309 node.syntax().text().to_string()
310 };
311
312 Some(label.trim().to_owned())
313} 298}
314 299
315#[cfg(test)] 300#[cfg(test)]
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
new file mode 100644
index 000000000..469d56d63
--- /dev/null
+++ b/crates/ra_ide_api/src/impls.rs
@@ -0,0 +1,120 @@
1use ra_db::{SourceDatabase};
2use ra_syntax::{
3 AstNode, ast,
4 algo::find_node_at_offset,
5};
6use hir::{db::HirDatabase, source_binder};
7
8use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
9
10pub(crate) fn goto_implementation(
11 db: &RootDatabase,
12 position: FilePosition,
13) -> Option<RangeInfo<Vec<NavigationTarget>>> {
14 let file = db.parse(position.file_id);
15 let syntax = file.syntax();
16
17 let module = source_binder::module_from_position(db, position)?;
18 let krate = module.krate(db)?;
19
20 let node = find_node_at_offset::<ast::NominalDef>(syntax, position.offset)?;
21 let ty = match node.kind() {
22 ast::NominalDefKind::StructDef(def) => {
23 source_binder::struct_from_module(db, module, &def).ty(db)
24 }
25 ast::NominalDefKind::EnumDef(def) => {
26 source_binder::enum_from_module(db, module, &def).ty(db)
27 }
28 };
29
30 let impls = db.impls_in_crate(krate);
31
32 let navs = impls
33 .lookup_impl_blocks(db, &ty)
34 .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp));
35
36 Some(RangeInfo::new(node.syntax().range(), navs.collect()))
37}
38
39#[cfg(test)]
40mod tests {
41 use crate::mock_analysis::analysis_and_position;
42
43 fn check_goto(fixuture: &str, expected: &[&str]) {
44 let (analysis, pos) = analysis_and_position(fixuture);
45
46 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
47 assert_eq!(navs.len(), expected.len());
48 navs.into_iter()
49 .enumerate()
50 .for_each(|(i, nav)| nav.assert_match(expected[i]));
51 }
52
53 #[test]
54 fn goto_implementation_works() {
55 check_goto(
56 "
57 //- /lib.rs
58 struct Foo<|>;
59 impl Foo {}
60 ",
61 &["impl IMPL_BLOCK FileId(1) [12; 23)"],
62 );
63 }
64
65 #[test]
66 fn goto_implementation_works_multiple_blocks() {
67 check_goto(
68 "
69 //- /lib.rs
70 struct Foo<|>;
71 impl Foo {}
72 impl Foo {}
73 ",
74 &[
75 "impl IMPL_BLOCK FileId(1) [12; 23)",
76 "impl IMPL_BLOCK FileId(1) [24; 35)",
77 ],
78 );
79 }
80
81 #[test]
82 fn goto_implementation_works_multiple_mods() {
83 check_goto(
84 "
85 //- /lib.rs
86 struct Foo<|>;
87 mod a {
88 impl super::Foo {}
89 }
90 mod b {
91 impl super::Foo {}
92 }
93 ",
94 &[
95 "impl IMPL_BLOCK FileId(1) [24; 42)",
96 "impl IMPL_BLOCK FileId(1) [57; 75)",
97 ],
98 );
99 }
100
101 #[test]
102 fn goto_implementation_works_multiple_files() {
103 check_goto(
104 "
105 //- /lib.rs
106 struct Foo<|>;
107 mod a;
108 mod b;
109 //- /a.rs
110 impl crate::Foo {}
111 //- /b.rs
112 impl crate::Foo {}
113 ",
114 &[
115 "impl IMPL_BLOCK FileId(2) [0; 18)",
116 "impl IMPL_BLOCK FileId(3) [0; 18)",
117 ],
118 );
119 }
120}
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 51947e4cc..5d8acf9df 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -25,6 +25,7 @@ mod call_info;
25mod syntax_highlighting; 25mod syntax_highlighting;
26mod parent_module; 26mod parent_module;
27mod rename; 27mod rename;
28mod impls;
28 29
29#[cfg(test)] 30#[cfg(test)]
30mod marks; 31mod marks;
@@ -58,6 +59,7 @@ pub use ra_ide_api_light::{
58pub use ra_db::{ 59pub use ra_db::{
59 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 60 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId
60}; 61};
62pub use hir::Documentation;
61 63
62// We use jemalloc mainly to get heap usage statistics, actual performance 64// We use jemalloc mainly to get heap usage statistics, actual performance
63// differnece is not measures. 65// differnece is not measures.
@@ -266,7 +268,7 @@ impl<T> RangeInfo<T> {
266#[derive(Debug)] 268#[derive(Debug)]
267pub struct CallInfo { 269pub struct CallInfo {
268 pub label: String, 270 pub label: String,
269 pub doc: Option<String>, 271 pub doc: Option<Documentation>,
270 pub parameters: Vec<String>, 272 pub parameters: Vec<String>,
271 pub active_parameter: Option<usize>, 273 pub active_parameter: Option<usize>,
272} 274}
@@ -415,6 +417,13 @@ impl Analysis {
415 self.with_db(|db| goto_definition::goto_definition(db, position)) 417 self.with_db(|db| goto_definition::goto_definition(db, position))
416 } 418 }
417 419
420 pub fn goto_implementation(
421 &self,
422 position: FilePosition,
423 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
424 self.with_db(|db| impls::goto_implementation(db, position))
425 }
426
418 /// Finds all usages of the reference at point. 427 /// Finds all usages of the reference at point.
419 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 428 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
420 self.with_db(|db| db.find_all_refs(position)) 429 self.with_db(|db| db.find_all_refs(position))
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index d73d4afa7..5ccb5cc2e 100644
--- a/crates/ra_ide_api/src/navigation_target.rs
+++ b/crates/ra_ide_api/src/navigation_target.rs
@@ -147,6 +147,16 @@ impl NavigationTarget {
147 } 147 }
148 } 148 }
149 149
150 pub(crate) fn from_impl_block(
151 db: &RootDatabase,
152 module: hir::Module,
153 impl_block: &hir::ImplBlock,
154 ) -> NavigationTarget {
155 let (file_id, _) = module.definition_source(db);
156 let node = module.impl_source(db, impl_block.id());
157 NavigationTarget::from_syntax(file_id, "impl".into(), None, node.syntax())
158 }
159
150 #[cfg(test)] 160 #[cfg(test)]
151 pub(crate) fn assert_match(&self, expected: &str) { 161 pub(crate) fn assert_match(&self, expected: &str) {
152 let actual = self.debug_render(); 162 let actual = self.debug_render();
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index bca079d65..254624487 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -2,7 +2,7 @@ use lsp_types::{
2 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, 2 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions,
3 ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, 3 ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability,
4 ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 4 ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
5 TextDocumentSyncOptions, 5 TextDocumentSyncOptions, ImplementationProviderCapability,
6}; 6};
7 7
8pub fn server_capabilities() -> ServerCapabilities { 8pub fn server_capabilities() -> ServerCapabilities {
@@ -26,7 +26,7 @@ pub fn server_capabilities() -> ServerCapabilities {
26 }), 26 }),
27 definition_provider: Some(true), 27 definition_provider: Some(true),
28 type_definition_provider: None, 28 type_definition_provider: None,
29 implementation_provider: None, 29 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
30 references_provider: Some(true), 30 references_provider: Some(true),
31 document_highlight_provider: Some(true), 31 document_highlight_provider: Some(true),
32 document_symbol_provider: Some(true), 32 document_symbol_provider: Some(true),
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 8c87f5195..c033ecdea 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -87,13 +87,6 @@ impl ConvWith for CompletionItem {
87 None 87 None
88 }; 88 };
89 89
90 let documentation = self.documentation().map(|value| {
91 Documentation::MarkupContent(MarkupContent {
92 kind: MarkupKind::Markdown,
93 value: value.to_string(),
94 })
95 });
96
97 let mut res = lsp_types::CompletionItem { 90 let mut res = lsp_types::CompletionItem {
98 label: self.label().to_string(), 91 label: self.label().to_string(),
99 detail: self.detail().map(|it| it.to_string()), 92 detail: self.detail().map(|it| it.to_string()),
@@ -101,7 +94,7 @@ impl ConvWith for CompletionItem {
101 kind: self.kind().map(|it| it.conv()), 94 kind: self.kind().map(|it| it.conv()),
102 text_edit: Some(text_edit), 95 text_edit: Some(text_edit),
103 additional_text_edits, 96 additional_text_edits,
104 documentation: documentation, 97 documentation: self.documentation().map(|it| it.conv()),
105 ..Default::default() 98 ..Default::default()
106 }; 99 };
107 res.insert_text_format = Some(match self.insert_text_format() { 100 res.insert_text_format = Some(match self.insert_text_format() {
@@ -160,6 +153,16 @@ impl ConvWith for Range {
160 } 153 }
161} 154}
162 155
156impl Conv for ra_ide_api::Documentation {
157 type Output = lsp_types::Documentation;
158 fn conv(self) -> Documentation {
159 Documentation::MarkupContent(MarkupContent {
160 kind: MarkupKind::Markdown,
161 value: crate::markdown::sanitize_markdown(self).into(),
162 })
163 }
164}
165
163impl ConvWith for TextEdit { 166impl ConvWith for TextEdit {
164 type Ctx = LineIndex; 167 type Ctx = LineIndex;
165 type Output = Vec<lsp_types::TextEdit>; 168 type Output = Vec<lsp_types::TextEdit>;
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs
index f93d4b37d..5b5f3b948 100644
--- a/crates/ra_lsp_server/src/lib.rs
+++ b/crates/ra_lsp_server/src/lib.rs
@@ -2,6 +2,7 @@ mod caps;
2mod cargo_target_spec; 2mod cargo_target_spec;
3mod conv; 3mod conv;
4mod main_loop; 4mod main_loop;
5mod markdown;
5mod project_model; 6mod project_model;
6pub mod req; 7pub mod req;
7mod server_world; 8mod server_world;
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index e430ac6de..df390c19e 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -305,6 +305,7 @@ fn on_request(
305 .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)? 305 .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)?
306 .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? 306 .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)?
307 .on::<req::GotoDefinition>(handlers::handle_goto_definition)? 307 .on::<req::GotoDefinition>(handlers::handle_goto_definition)?
308 .on::<req::GotoImplementation>(handlers::handle_goto_implementation)?
308 .on::<req::ParentModule>(handlers::handle_parent_module)? 309 .on::<req::ParentModule>(handlers::handle_parent_module)?
309 .on::<req::Runnables>(handlers::handle_runnables)? 310 .on::<req::Runnables>(handlers::handle_runnables)?
310 .on::<req::DecorationsRequest>(handlers::handle_decorations)? 311 .on::<req::DecorationsRequest>(handlers::handle_decorations)?
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 9478ebfb8..74554f15c 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,7 +1,7 @@
1use gen_lsp_server::ErrorCode; 1use gen_lsp_server::ErrorCode;
2use lsp_types::{ 2use lsp_types::{
3 CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, 3 CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity,
4 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, 4 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange,
5 FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, 5 FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
6 MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, 6 MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
7 RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, 7 RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
@@ -229,6 +229,26 @@ pub fn handle_goto_definition(
229 Ok(Some(req::GotoDefinitionResponse::Link(res))) 229 Ok(Some(req::GotoDefinitionResponse::Link(res)))
230} 230}
231 231
232pub fn handle_goto_implementation(
233 world: ServerWorld,
234 params: req::TextDocumentPositionParams,
235) -> Result<Option<req::GotoImplementationResponse>> {
236 let position = params.try_conv_with(&world)?;
237 let line_index = world.analysis().file_line_index(position.file_id);
238 let nav_info = match world.analysis().goto_implementation(position)? {
239 None => return Ok(None),
240 Some(it) => it,
241 };
242 let nav_range = nav_info.range;
243 let res = nav_info
244 .info
245 .into_iter()
246 .map(|nav| RangeInfo::new(nav_range, nav))
247 .map(|nav| to_location_link(&nav, &world, &line_index))
248 .collect::<Result<Vec<_>>>()?;
249 Ok(Some(req::GotoDefinitionResponse::Link(res)))
250}
251
232pub fn handle_parent_module( 252pub fn handle_parent_module(
233 world: ServerWorld, 253 world: ServerWorld,
234 params: req::TextDocumentPositionParams, 254 params: req::TextDocumentPositionParams,
@@ -401,12 +421,9 @@ pub fn handle_signature_help(
401 documentation: None, 421 documentation: None,
402 }) 422 })
403 .collect(); 423 .collect();
404 let documentation = call_info.doc.map(|value| { 424
405 Documentation::MarkupContent(MarkupContent { 425 let documentation = call_info.doc.map(|it| it.conv());
406 kind: MarkupKind::Markdown, 426
407 value,
408 })
409 });
410 let sig_info = SignatureInformation { 427 let sig_info = SignatureInformation {
411 label: call_info.label, 428 label: call_info.label,
412 documentation, 429 documentation,
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs
new file mode 100644
index 000000000..f505755e8
--- /dev/null
+++ b/crates/ra_lsp_server/src/markdown.rs
@@ -0,0 +1,38 @@
1use ra_ide_api::Documentation;
2
3pub(crate) fn sanitize_markdown(docs: Documentation) -> Documentation {
4 let docs: String = docs.into();
5
6 // Massage markdown
7 let mut processed_lines = Vec::new();
8 let mut in_code_block = false;
9 for line in docs.lines() {
10 if line.starts_with("```") {
11 in_code_block = !in_code_block;
12 }
13
14 let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
15 "```rust".into()
16 } else {
17 line.to_string()
18 };
19
20 processed_lines.push(line);
21 }
22
23 Documentation::new(&processed_lines.join("\n"))
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29
30 #[test]
31 fn test_codeblock_adds_rust() {
32 let comment = "```\nfn some_rust() {}\n```";
33 assert_eq!(
34 sanitize_markdown(Documentation::new(comment)).contents(),
35 "```rust\nfn some_rust() {}\n```"
36 );
37 }
38}
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index a4d890755..e224ede80 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -8,7 +8,7 @@ pub use lsp_types::{
8 CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 8 CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
9 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, 9 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
10 PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, 10 PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit,
11 TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, 11 TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams
12}; 12};
13 13
14pub enum AnalyzerStatus {} 14pub enum AnalyzerStatus {}
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 3ace6533c..4f5a96014 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1981,7 +1981,11 @@ impl ToOwned for MatchGuard {
1981} 1981}
1982 1982
1983 1983
1984impl MatchGuard {} 1984impl MatchGuard {
1985 pub fn expr(&self) -> Option<&Expr> {
1986 super::child_opt(self)
1987 }
1988}
1985 1989
1986// MethodCallExpr 1990// MethodCallExpr
1987#[derive(Debug, PartialEq, Eq, Hash)] 1991#[derive(Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 85fc79038..e4cad4eb3 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -418,7 +418,7 @@ Grammar(
418 ], 418 ],
419 collections: [ [ "pats", "Pat" ] ] 419 collections: [ [ "pats", "Pat" ] ]
420 ), 420 ),
421 "MatchGuard": (), 421 "MatchGuard": (options: ["Expr"]),
422 "StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]), 422 "StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
423 "NamedFieldList": (collections: [ ["fields", "NamedField"] ]), 423 "NamedFieldList": (collections: [ ["fields", "NamedField"] ]),
424 "NamedField": (options: ["NameRef", "Expr"]), 424 "NamedField": (options: ["NameRef", "Expr"]),
diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs
index 6d6d89f70..600774afd 100644
--- a/crates/ra_syntax/src/grammar/expressions/atom.rs
+++ b/crates/ra_syntax/src/grammar/expressions/atom.rs
@@ -360,8 +360,8 @@ fn match_arm(p: &mut Parser) -> BlockLike {
360 while p.eat(PIPE) { 360 while p.eat(PIPE) {
361 patterns::pattern(p); 361 patterns::pattern(p);
362 } 362 }
363 if p.eat(IF_KW) { 363 if p.at(IF_KW) {
364 expr(p); 364 match_guard(p);
365 } 365 }
366 p.expect(FAT_ARROW); 366 p.expect(FAT_ARROW);
367 let ret = expr_stmt(p); 367 let ret = expr_stmt(p);
@@ -369,6 +369,20 @@ fn match_arm(p: &mut Parser) -> BlockLike {
369 ret 369 ret
370} 370}
371 371
372// test match_guard
373// fn foo() {
374// match () {
375// _ if foo => (),
376// }
377// }
378fn match_guard(p: &mut Parser) -> CompletedMarker {
379 assert!(p.at(IF_KW));
380 let m = p.start();
381 p.bump();
382 expr(p);
383 m.complete(p, MATCH_GUARD)
384}
385
372// test block_expr 386// test block_expr
373// fn foo() { 387// fn foo() {
374// {}; 388// {};
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt
index 98e7535a3..b44e61879 100644
--- a/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt
@@ -37,32 +37,33 @@ SOURCE_FILE@[0; 167)
37 PLACEHOLDER_PAT@[51; 52) 37 PLACEHOLDER_PAT@[51; 52)
38 UNDERSCORE@[51; 52) 38 UNDERSCORE@[51; 52)
39 WHITESPACE@[52; 53) 39 WHITESPACE@[52; 53)
40 IF_KW@[53; 55) 40 MATCH_GUARD@[53; 77)
41 WHITESPACE@[55; 56) 41 IF_KW@[53; 55)
42 BIN_EXPR@[56; 77) 42 WHITESPACE@[55; 56)
43 PATH_EXPR@[56; 60) 43 BIN_EXPR@[56; 77)
44 PATH@[56; 60) 44 PATH_EXPR@[56; 60)
45 PATH_SEGMENT@[56; 60) 45 PATH@[56; 60)
46 NAME_REF@[56; 60) 46 PATH_SEGMENT@[56; 60)
47 IDENT@[56; 60) "Test" 47 NAME_REF@[56; 60)
48 WHITESPACE@[60; 61) 48 IDENT@[56; 60) "Test"
49 R_ANGLE@[61; 62) 49 WHITESPACE@[60; 61)
50 WHITESPACE@[62; 63) 50 R_ANGLE@[61; 62)
51 STRUCT_LIT@[63; 77) 51 WHITESPACE@[62; 63)
52 PATH@[63; 67) 52 STRUCT_LIT@[63; 77)
53 PATH_SEGMENT@[63; 67) 53 PATH@[63; 67)
54 NAME_REF@[63; 67) 54 PATH_SEGMENT@[63; 67)
55 IDENT@[63; 67) "Test" 55 NAME_REF@[63; 67)
56 NAMED_FIELD_LIST@[67; 77) 56 IDENT@[63; 67) "Test"
57 L_CURLY@[67; 68) 57 NAMED_FIELD_LIST@[67; 77)
58 NAMED_FIELD@[68; 76) 58 L_CURLY@[67; 68)
59 NAME_REF@[68; 73) 59 NAMED_FIELD@[68; 76)
60 IDENT@[68; 73) "field" 60 NAME_REF@[68; 73)
61 COLON@[73; 74) 61 IDENT@[68; 73) "field"
62 WHITESPACE@[74; 75) 62 COLON@[73; 74)
63 LITERAL@[75; 76) 63 WHITESPACE@[74; 75)
64 INT_NUMBER@[75; 76) "0" 64 LITERAL@[75; 76)
65 R_CURLY@[76; 77) 65 INT_NUMBER@[75; 76) "0"
66 R_CURLY@[76; 77)
66 WHITESPACE@[77; 78) 67 WHITESPACE@[77; 78)
67 FAT_ARROW@[78; 80) 68 FAT_ARROW@[78; 80)
68 WHITESPACE@[80; 81) 69 WHITESPACE@[80; 81)
@@ -82,13 +83,14 @@ SOURCE_FILE@[0; 167)
82 NAME@[97; 98) 83 NAME@[97; 98)
83 IDENT@[97; 98) "Y" 84 IDENT@[97; 98) "Y"
84 WHITESPACE@[98; 99) 85 WHITESPACE@[98; 99)
85 IF_KW@[99; 101) 86 MATCH_GUARD@[99; 103)
86 WHITESPACE@[101; 102) 87 IF_KW@[99; 101)
87 PATH_EXPR@[102; 103) 88 WHITESPACE@[101; 102)
88 PATH@[102; 103) 89 PATH_EXPR@[102; 103)
89 PATH_SEGMENT@[102; 103) 90 PATH@[102; 103)
90 NAME_REF@[102; 103) 91 PATH_SEGMENT@[102; 103)
91 IDENT@[102; 103) "Z" 92 NAME_REF@[102; 103)
93 IDENT@[102; 103) "Z"
92 WHITESPACE@[103; 104) 94 WHITESPACE@[103; 104)
93 FAT_ARROW@[104; 106) 95 FAT_ARROW@[104; 106)
94 WHITESPACE@[106; 107) 96 WHITESPACE@[106; 107)
@@ -110,13 +112,14 @@ SOURCE_FILE@[0; 167)
110 NAME@[125; 126) 112 NAME@[125; 126)
111 IDENT@[125; 126) "Y" 113 IDENT@[125; 126) "Y"
112 WHITESPACE@[126; 127) 114 WHITESPACE@[126; 127)
113 IF_KW@[127; 129) 115 MATCH_GUARD@[127; 131)
114 WHITESPACE@[129; 130) 116 IF_KW@[127; 129)
115 PATH_EXPR@[130; 131) 117 WHITESPACE@[129; 130)
116 PATH@[130; 131) 118 PATH_EXPR@[130; 131)
117 PATH_SEGMENT@[130; 131) 119 PATH@[130; 131)
118 NAME_REF@[130; 131) 120 PATH_SEGMENT@[130; 131)
119 IDENT@[130; 131) "Z" 121 NAME_REF@[130; 131)
122 IDENT@[130; 131) "Z"
120 WHITESPACE@[131; 132) 123 WHITESPACE@[131; 132)
121 FAT_ARROW@[132; 134) 124 FAT_ARROW@[132; 134)
122 WHITESPACE@[134; 135) 125 WHITESPACE@[134; 135)
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs
new file mode 100644
index 000000000..f1bd72fc4
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs
@@ -0,0 +1,5 @@
1fn foo() {
2 match () {
3 _ if foo => (),
4 }
5}
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt
new file mode 100644
index 000000000..27553882d
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt
@@ -0,0 +1,47 @@
1SOURCE_FILE@[0; 58)
2 FN_DEF@[0; 57)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK@[9; 57)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 MATCH_EXPR@[15; 55)
15 MATCH_KW@[15; 20)
16 WHITESPACE@[20; 21)
17 TUPLE_EXPR@[21; 23)
18 L_PAREN@[21; 22)
19 R_PAREN@[22; 23)
20 WHITESPACE@[23; 24)
21 MATCH_ARM_LIST@[24; 55)
22 L_CURLY@[24; 25)
23 WHITESPACE@[25; 34)
24 MATCH_ARM@[34; 48)
25 PLACEHOLDER_PAT@[34; 35)
26 UNDERSCORE@[34; 35)
27 WHITESPACE@[35; 36)
28 MATCH_GUARD@[36; 42)
29 IF_KW@[36; 38)
30 WHITESPACE@[38; 39)
31 PATH_EXPR@[39; 42)
32 PATH@[39; 42)
33 PATH_SEGMENT@[39; 42)
34 NAME_REF@[39; 42)
35 IDENT@[39; 42) "foo"
36 WHITESPACE@[42; 43)
37 FAT_ARROW@[43; 45)
38 WHITESPACE@[45; 46)
39 TUPLE_EXPR@[46; 48)
40 L_PAREN@[46; 47)
41 R_PAREN@[47; 48)
42 COMMA@[48; 49)
43 WHITESPACE@[49; 54)
44 R_CURLY@[54; 55)
45 WHITESPACE@[55; 56)
46 R_CURLY@[56; 57)
47 WHITESPACE@[57; 58)
diff --git a/editors/code/package.json b/editors/code/package.json
index 05c67d822..1ed834d62 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -44,7 +44,9 @@
44 "vscode": "^1.1.26" 44 "vscode": "^1.1.26"
45 }, 45 },
46 "activationEvents": [ 46 "activationEvents": [
47 "onLanguage:rust" 47 "onLanguage:rust",
48 "onCommand:rust-analyzer.analyzerStatus",
49 "onCommand:rust-analyzer.collectGarbage"
48 ], 50 ],
49 "main": "./out/extension", 51 "main": "./out/extension",
50 "contributes": { 52 "contributes": {
@@ -73,35 +75,43 @@
73 "commands": [ 75 "commands": [
74 { 76 {
75 "command": "rust-analyzer.syntaxTree", 77 "command": "rust-analyzer.syntaxTree",
76 "title": "rust-analyzer: syntax tree" 78 "title": "Show syntax tree for current file",
79 "category": "Rust Analyzer"
77 }, 80 },
78 { 81 {
79 "command": "rust-analyzer.extendSelection", 82 "command": "rust-analyzer.extendSelection",
80 "title": "rust-analyzer: extend selection" 83 "title": "Extend selection",
84 "category": "Rust Analyzer"
81 }, 85 },
82 { 86 {
83 "command": "rust-analyzer.matchingBrace", 87 "command": "rust-analyzer.matchingBrace",
84 "title": "rust-analyzer: matching brace" 88 "title": "Find matching brace",
89 "category": "Rust Analyzer"
85 }, 90 },
86 { 91 {
87 "command": "rust-analyzer.parentModule", 92 "command": "rust-analyzer.parentModule",
88 "title": "rust-analyzer: parent module" 93 "title": "Locate parent module",
94 "category": "Rust Analyzer"
89 }, 95 },
90 { 96 {
91 "command": "rust-analyzer.joinLines", 97 "command": "rust-analyzer.joinLines",
92 "title": "rust-analyzer: join lines" 98 "title": "Join lines",
99 "category": "Rust Analyzer"
93 }, 100 },
94 { 101 {
95 "command": "rust-analyzer.run", 102 "command": "rust-analyzer.run",
96 "title": "rust-analyzer: run" 103 "title": "Run",
104 "category": "Rust Analyzer"
97 }, 105 },
98 { 106 {
99 "command": "rust-analyzer.analyzerStatus", 107 "command": "rust-analyzer.analyzerStatus",
100 "title": "rust-analyzer: status" 108 "title": "Status",
109 "category": "Rust Analyzer"
101 }, 110 },
102 { 111 {
103 "command": "rust-analyzer.collectGarbage", 112 "command": "rust-analyzer.collectGarbage",
104 "title": "rust-analyzer: run gc" 113 "title": "Run garbage collection",
114 "category": "Rust Analyzer"
105 } 115 }
106 ], 116 ],
107 "keybindings": [ 117 "keybindings": [
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index d9ae56420..c0f2ada76 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -118,7 +118,8 @@ export async function handleSingle(runnable: Runnable) {
118 task.group = vscode.TaskGroup.Build; 118 task.group = vscode.TaskGroup.Build;
119 task.presentationOptions = { 119 task.presentationOptions = {
120 reveal: vscode.TaskRevealKind.Always, 120 reveal: vscode.TaskRevealKind.Always,
121 panel: vscode.TaskPanelKind.Dedicated 121 panel: vscode.TaskPanelKind.Dedicated,
122 clear: true
122 }; 123 };
123 124
124 return vscode.tasks.executeTask(task); 125 return vscode.tasks.executeTask(task);