diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_attribute.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_macro_in_item_position.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_pattern.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_qualified_path.rs | 15 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_unqualified_path.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 7 | ||||
-rw-r--r-- | crates/ra_prof/Cargo.toml | 5 | ||||
-rw-r--r-- | crates/ra_prof/src/lib.rs | 9 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 23 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 73 | ||||
-rw-r--r-- | crates/rust-analyzer/src/reload.rs | 56 | ||||
-rw-r--r-- | crates/stdx/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/vfs-notify/src/include.rs | 1 | ||||
-rw-r--r-- | crates/vfs-notify/src/lib.rs | 12 | ||||
-rw-r--r-- | crates/vfs/src/lib.rs | 2 |
18 files changed, 155 insertions, 73 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 0d877e44e..4a16ac566 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -568,6 +568,7 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode { | |||
568 | node.ancestors().last().unwrap() | 568 | node.ancestors().last().unwrap() |
569 | } | 569 | } |
570 | 570 | ||
571 | #[derive(Debug)] | ||
571 | pub struct SemanticsScope<'a> { | 572 | pub struct SemanticsScope<'a> { |
572 | pub db: &'a dyn HirDatabase, | 573 | pub db: &'a dyn HirDatabase, |
573 | resolver: Resolver, | 574 | resolver: Resolver, |
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 9db317509..047299de9 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs | |||
@@ -195,7 +195,7 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, | |||
195 | 195 | ||
196 | fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { | 196 | fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { |
197 | let mut result = FxHashSet::default(); | 197 | let mut result = FxHashSet::default(); |
198 | ctx.scope().process_all_names(&mut |name, scope_def| { | 198 | ctx.scope.process_all_names(&mut |name, scope_def| { |
199 | if let hir::ScopeDef::MacroDef(mac) = scope_def { | 199 | if let hir::ScopeDef::MacroDef(mac) = scope_def { |
200 | if mac.is_derive_macro() { | 200 | if mac.is_derive_macro() { |
201 | result.insert(name.to_string()); | 201 | result.insert(name.to_string()); |
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 3c6c8c81a..532665285 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -29,7 +29,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
29 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | 29 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { |
30 | for receiver in receiver.autoderef(ctx.db) { | 30 | for receiver in receiver.autoderef(ctx.db) { |
31 | for (field, ty) in receiver.fields(ctx.db) { | 31 | for (field, ty) in receiver.fields(ctx.db) { |
32 | if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { | 32 | if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { |
33 | // Skip private field. FIXME: If the definition location of the | 33 | // Skip private field. FIXME: If the definition location of the |
34 | // field is editable, we should show the completion | 34 | // field is editable, we should show the completion |
35 | continue; | 35 | continue; |
@@ -46,10 +46,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty | |||
46 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | 46 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { |
47 | if let Some(krate) = ctx.krate { | 47 | if let Some(krate) = ctx.krate { |
48 | let mut seen_methods = FxHashSet::default(); | 48 | let mut seen_methods = FxHashSet::default(); |
49 | let traits_in_scope = ctx.scope().traits_in_scope(); | 49 | let traits_in_scope = ctx.scope.traits_in_scope(); |
50 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { | 50 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { |
51 | if func.has_self_param(ctx.db) | 51 | if func.has_self_param(ctx.db) |
52 | && ctx.scope().module().map_or(true, |m| func.is_visible_from(ctx.db, m)) | 52 | && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) |
53 | && seen_methods.insert(func.name(ctx.db)) | 53 | && seen_methods.insert(func.name(ctx.db)) |
54 | { | 54 | { |
55 | acc.add_function(ctx, func, None); | 55 | acc.add_function(ctx, func, None); |
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs index d6613ed7b..0447f0511 100644 --- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs +++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs | |||
@@ -5,7 +5,7 @@ use crate::completion::{CompletionContext, Completions}; | |||
5 | pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { | 5 | pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { |
6 | // Show only macros in top level. | 6 | // Show only macros in top level. |
7 | if ctx.is_new_item { | 7 | if ctx.is_new_item { |
8 | ctx.scope().process_all_names(&mut |name, res| { | 8 | ctx.scope.process_all_names(&mut |name, res| { |
9 | if let hir::ScopeDef::MacroDef(mac) = res { | 9 | if let hir::ScopeDef::MacroDef(mac) = res { |
10 | acc.add_macro(ctx, Some(name.to_string()), mac); | 10 | acc.add_macro(ctx, Some(name.to_string()), mac); |
11 | } | 11 | } |
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs index 13fa7548d..aceb77cb5 100644 --- a/crates/ra_ide/src/completion/complete_pattern.rs +++ b/crates/ra_ide/src/completion/complete_pattern.rs | |||
@@ -13,7 +13,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
13 | 13 | ||
14 | // FIXME: ideally, we should look at the type we are matching against and | 14 | // FIXME: ideally, we should look at the type we are matching against and |
15 | // suggest variants + auto-imports | 15 | // suggest variants + auto-imports |
16 | ctx.scope().process_all_names(&mut |name, res| { | 16 | ctx.scope.process_all_names(&mut |name, res| { |
17 | match &res { | 17 | match &res { |
18 | hir::ScopeDef::ModuleDef(def) => match def { | 18 | hir::ScopeDef::ModuleDef(def) => match def { |
19 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | 19 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index e5553e28f..b08f5b9b4 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -17,21 +17,20 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
17 | return; | 17 | return; |
18 | } | 18 | } |
19 | 19 | ||
20 | let scope = ctx.scope(); | 20 | let context_module = ctx.scope.module(); |
21 | let context_module = scope.module(); | ||
22 | 21 | ||
23 | let res = match scope.resolve_hir_path_qualifier(&path) { | 22 | let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) { |
24 | Some(res) => res, | 23 | Some(res) => res, |
25 | None => return, | 24 | None => return, |
26 | }; | 25 | }; |
27 | 26 | ||
28 | // Add associated types on type parameters and `Self`. | 27 | // Add associated types on type parameters and `Self`. |
29 | res.assoc_type_shorthand_candidates(ctx.db, |alias| { | 28 | resolution.assoc_type_shorthand_candidates(ctx.db, |alias| { |
30 | acc.add_type_alias(ctx, alias); | 29 | acc.add_type_alias(ctx, alias); |
31 | None::<()> | 30 | None::<()> |
32 | }); | 31 | }); |
33 | 32 | ||
34 | match res { | 33 | match resolution { |
35 | PathResolution::Def(hir::ModuleDef::Module(module)) => { | 34 | PathResolution::Def(hir::ModuleDef::Module(module)) => { |
36 | let module_scope = module.scope(ctx.db, context_module); | 35 | let module_scope = module.scope(ctx.db, context_module); |
37 | for (name, def) in module_scope { | 36 | for (name, def) in module_scope { |
@@ -68,7 +67,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
68 | 67 | ||
69 | let krate = ctx.krate; | 68 | let krate = ctx.krate; |
70 | if let Some(krate) = krate { | 69 | if let Some(krate) = krate { |
71 | let traits_in_scope = ctx.scope().traits_in_scope(); | 70 | let traits_in_scope = ctx.scope.traits_in_scope(); |
72 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | 71 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { |
73 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 72 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
74 | return None; | 73 | return None; |
@@ -113,13 +112,13 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
113 | } | 112 | } |
114 | PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { | 113 | PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { |
115 | if let Some(krate) = ctx.krate { | 114 | if let Some(krate) = ctx.krate { |
116 | let ty = match res { | 115 | let ty = match resolution { |
117 | PathResolution::TypeParam(param) => param.ty(ctx.db), | 116 | PathResolution::TypeParam(param) => param.ty(ctx.db), |
118 | PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), | 117 | PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), |
119 | _ => return, | 118 | _ => return, |
120 | }; | 119 | }; |
121 | 120 | ||
122 | let traits_in_scope = ctx.scope().traits_in_scope(); | 121 | let traits_in_scope = ctx.scope.traits_in_scope(); |
123 | let mut seen = FxHashSet::default(); | 122 | let mut seen = FxHashSet::default(); |
124 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | 123 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { |
125 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 124 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index 18f4488b7..bd9551f35 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -25,7 +25,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
25 | return; | 25 | return; |
26 | } | 26 | } |
27 | 27 | ||
28 | ctx.scope().process_all_names(&mut |name, res| { | 28 | ctx.scope.process_all_names(&mut |name, res| { |
29 | if ctx.use_item_syntax.is_some() { | 29 | if ctx.use_item_syntax.is_some() { |
30 | if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { | 30 | if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { |
31 | if name_ref.syntax().text() == name.to_string().as_str() { | 31 | if name_ref.syntax().text() == name.to_string().as_str() { |
@@ -42,7 +42,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
42 | if let Some(Adt::Enum(enum_data)) = ty.as_adt() { | 42 | if let Some(Adt::Enum(enum_data)) = ty.as_adt() { |
43 | let variants = enum_data.variants(ctx.db); | 43 | let variants = enum_data.variants(ctx.db); |
44 | 44 | ||
45 | let module = if let Some(module) = ctx.scope().module() { | 45 | let module = if let Some(module) = ctx.scope.module() { |
46 | // Compute path from the completion site if available. | 46 | // Compute path from the completion site if available. |
47 | module | 47 | module |
48 | } else { | 48 | } else { |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 02811a91e..3d93f7067 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -24,6 +24,7 @@ use test_utils::mark; | |||
24 | #[derive(Debug)] | 24 | #[derive(Debug)] |
25 | pub(crate) struct CompletionContext<'a> { | 25 | pub(crate) struct CompletionContext<'a> { |
26 | pub(super) sema: Semantics<'a, RootDatabase>, | 26 | pub(super) sema: Semantics<'a, RootDatabase>, |
27 | pub(super) scope: SemanticsScope<'a>, | ||
27 | pub(super) db: &'a RootDatabase, | 28 | pub(super) db: &'a RootDatabase, |
28 | pub(super) config: &'a CompletionConfig, | 29 | pub(super) config: &'a CompletionConfig, |
29 | pub(super) offset: TextSize, | 30 | pub(super) offset: TextSize, |
@@ -106,8 +107,10 @@ impl<'a> CompletionContext<'a> { | |||
106 | let original_token = | 107 | let original_token = |
107 | original_file.syntax().token_at_offset(position.offset).left_biased()?; | 108 | original_file.syntax().token_at_offset(position.offset).left_biased()?; |
108 | let token = sema.descend_into_macros(original_token.clone()); | 109 | let token = sema.descend_into_macros(original_token.clone()); |
110 | let scope = sema.scope_at_offset(&token.parent(), position.offset); | ||
109 | let mut ctx = CompletionContext { | 111 | let mut ctx = CompletionContext { |
110 | sema, | 112 | sema, |
113 | scope, | ||
111 | db, | 114 | db, |
112 | config, | 115 | config, |
113 | original_token, | 116 | original_token, |
@@ -207,10 +210,6 @@ impl<'a> CompletionContext<'a> { | |||
207 | } | 210 | } |
208 | } | 211 | } |
209 | 212 | ||
210 | pub(crate) fn scope(&self) -> SemanticsScope<'_> { | ||
211 | self.sema.scope_at_offset(&self.token.parent(), self.offset) | ||
212 | } | ||
213 | |||
214 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { | 213 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { |
215 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); | 214 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); |
216 | let syntax_element = NodeOrToken::Token(fake_ident_token.clone()); | 215 | let syntax_element = NodeOrToken::Token(fake_ident_token.clone()); |
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index c33b5121a..eabfcebb0 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml | |||
@@ -20,3 +20,8 @@ jemalloc-ctl = { version = "0.3.3", optional = true } | |||
20 | [features] | 20 | [features] |
21 | jemalloc = [ "jemallocator", "jemalloc-ctl" ] | 21 | jemalloc = [ "jemallocator", "jemalloc-ctl" ] |
22 | cpu_profiler = [] | 22 | cpu_profiler = [] |
23 | |||
24 | # Uncomment to enable for the whole crate graph | ||
25 | # default = [ "backtrace" ] | ||
26 | # default = [ "jemalloc" ] | ||
27 | # default = [ "cpu_profiler" ] | ||
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index 89df7f04b..7163a8424 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs | |||
@@ -43,6 +43,7 @@ pub struct Scope { | |||
43 | } | 43 | } |
44 | 44 | ||
45 | impl Scope { | 45 | impl Scope { |
46 | #[must_use] | ||
46 | pub fn enter() -> Scope { | 47 | pub fn enter() -> Scope { |
47 | let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); | 48 | let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); |
48 | Scope { prev } | 49 | Scope { prev } |
@@ -65,7 +66,8 @@ impl Drop for Scope { | |||
65 | /// 2. Build with `cpu_profiler` feature. | 66 | /// 2. Build with `cpu_profiler` feature. |
66 | /// 3. Tun the code, the *raw* output would be in the `./out.profile` file. | 67 | /// 3. Tun the code, the *raw* output would be in the `./out.profile` file. |
67 | /// 4. Install pprof for visualization (https://github.com/google/pprof). | 68 | /// 4. Install pprof for visualization (https://github.com/google/pprof). |
68 | /// 5. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. | 69 | /// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` |
70 | /// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. | ||
69 | /// | 71 | /// |
70 | /// For example, here's how I run profiling on NixOS: | 72 | /// For example, here's how I run profiling on NixOS: |
71 | /// | 73 | /// |
@@ -73,11 +75,16 @@ impl Drop for Scope { | |||
73 | /// $ nix-shell -p gperftools --run \ | 75 | /// $ nix-shell -p gperftools --run \ |
74 | /// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' | 76 | /// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' |
75 | /// ``` | 77 | /// ``` |
78 | /// | ||
79 | /// See this diff for how to profile completions: | ||
80 | /// | ||
81 | /// https://github.com/rust-analyzer/rust-analyzer/pull/5306 | ||
76 | #[derive(Debug)] | 82 | #[derive(Debug)] |
77 | pub struct CpuProfiler { | 83 | pub struct CpuProfiler { |
78 | _private: (), | 84 | _private: (), |
79 | } | 85 | } |
80 | 86 | ||
87 | #[must_use] | ||
81 | pub fn cpu_profiler() -> CpuProfiler { | 88 | pub fn cpu_profiler() -> CpuProfiler { |
82 | #[cfg(feature = "cpu_profiler")] | 89 | #[cfg(feature = "cpu_profiler")] |
83 | { | 90 | { |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 6d1154056..4182ca156 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -155,7 +155,7 @@ impl CargoWorkspace { | |||
155 | if let Some(target) = cargo_features.target.as_ref() { | 155 | if let Some(target) = cargo_features.target.as_ref() { |
156 | meta.other_options(vec![String::from("--filter-platform"), target.clone()]); | 156 | meta.other_options(vec![String::from("--filter-platform"), target.clone()]); |
157 | } | 157 | } |
158 | let meta = meta.exec().with_context(|| { | 158 | let mut meta = meta.exec().with_context(|| { |
159 | format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) | 159 | format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) |
160 | })?; | 160 | })?; |
161 | 161 | ||
@@ -175,6 +175,7 @@ impl CargoWorkspace { | |||
175 | 175 | ||
176 | let ws_members = &meta.workspace_members; | 176 | let ws_members = &meta.workspace_members; |
177 | 177 | ||
178 | meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); | ||
178 | for meta_pkg in meta.packages { | 179 | for meta_pkg in meta.packages { |
179 | let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = | 180 | let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = |
180 | meta_pkg; | 181 | meta_pkg; |
@@ -210,7 +211,7 @@ impl CargoWorkspace { | |||
210 | } | 211 | } |
211 | } | 212 | } |
212 | let resolve = meta.resolve.expect("metadata executed with deps"); | 213 | let resolve = meta.resolve.expect("metadata executed with deps"); |
213 | for node in resolve.nodes { | 214 | for mut node in resolve.nodes { |
214 | let source = match pkg_by_id.get(&node.id) { | 215 | let source = match pkg_by_id.get(&node.id) { |
215 | Some(&src) => src, | 216 | Some(&src) => src, |
216 | // FIXME: replace this and a similar branch below with `.unwrap`, once | 217 | // FIXME: replace this and a similar branch below with `.unwrap`, once |
@@ -221,6 +222,7 @@ impl CargoWorkspace { | |||
221 | continue; | 222 | continue; |
222 | } | 223 | } |
223 | }; | 224 | }; |
225 | node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg)); | ||
224 | for dep_node in node.deps { | 226 | for dep_node in node.deps { |
225 | let pkg = match pkg_by_id.get(&dep_node.pkg) { | 227 | let pkg = match pkg_by_id.get(&dep_node.pkg) { |
226 | Some(&pkg) => pkg, | 228 | Some(&pkg) => pkg, |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index c8d34e15a..9a9a6547a 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -26,6 +26,7 @@ use crate::{ | |||
26 | to_proto::url_from_abs_path, | 26 | to_proto::url_from_abs_path, |
27 | Result, | 27 | Result, |
28 | }; | 28 | }; |
29 | use ra_prof::profile; | ||
29 | 30 | ||
30 | #[derive(Eq, PartialEq, Copy, Clone)] | 31 | #[derive(Eq, PartialEq, Copy, Clone)] |
31 | pub(crate) enum Status { | 32 | pub(crate) enum Status { |
@@ -122,6 +123,10 @@ impl GlobalState { | |||
122 | } | 123 | } |
123 | 124 | ||
124 | pub(crate) fn process_changes(&mut self) -> bool { | 125 | pub(crate) fn process_changes(&mut self) -> bool { |
126 | let _p = profile("GlobalState::process_changes"); | ||
127 | let mut fs_changes = Vec::new(); | ||
128 | let mut has_fs_changes = false; | ||
129 | |||
125 | let change = { | 130 | let change = { |
126 | let mut change = AnalysisChange::new(); | 131 | let mut change = AnalysisChange::new(); |
127 | let (vfs, line_endings_map) = &mut *self.vfs.write(); | 132 | let (vfs, line_endings_map) = &mut *self.vfs.write(); |
@@ -130,13 +135,14 @@ impl GlobalState { | |||
130 | return false; | 135 | return false; |
131 | } | 136 | } |
132 | 137 | ||
133 | let fs_op = changed_files.iter().any(|it| it.is_created_or_deleted()); | ||
134 | if fs_op { | ||
135 | let roots = self.source_root_config.partition(&vfs); | ||
136 | change.set_roots(roots) | ||
137 | } | ||
138 | |||
139 | for file in changed_files { | 138 | for file in changed_files { |
139 | if file.is_created_or_deleted() { | ||
140 | if let Some(path) = vfs.file_path(file.file_id).as_path() { | ||
141 | fs_changes.push((path.to_path_buf(), file.change_kind)); | ||
142 | has_fs_changes = true; | ||
143 | } | ||
144 | } | ||
145 | |||
140 | let text = if file.exists() { | 146 | let text = if file.exists() { |
141 | let bytes = vfs.file_contents(file.file_id).to_vec(); | 147 | let bytes = vfs.file_contents(file.file_id).to_vec(); |
142 | match String::from_utf8(bytes).ok() { | 148 | match String::from_utf8(bytes).ok() { |
@@ -152,10 +158,15 @@ impl GlobalState { | |||
152 | }; | 158 | }; |
153 | change.change_file(file.file_id, text); | 159 | change.change_file(file.file_id, text); |
154 | } | 160 | } |
161 | if has_fs_changes { | ||
162 | let roots = self.source_root_config.partition(&vfs); | ||
163 | change.set_roots(roots); | ||
164 | } | ||
155 | change | 165 | change |
156 | }; | 166 | }; |
157 | 167 | ||
158 | self.analysis_host.apply_change(change); | 168 | self.analysis_host.apply_change(change); |
169 | self.maybe_refresh(&fs_changes); | ||
159 | true | 170 | true |
160 | } | 171 | } |
161 | 172 | ||
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 96e2399ce..702f25a19 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -22,6 +22,7 @@ use crate::{ | |||
22 | Result, | 22 | Result, |
23 | }; | 23 | }; |
24 | use ra_project_model::ProjectWorkspace; | 24 | use ra_project_model::ProjectWorkspace; |
25 | use vfs::ChangeKind; | ||
25 | 26 | ||
26 | pub fn main_loop(config: Config, connection: Connection) -> Result<()> { | 27 | pub fn main_loop(config: Config, connection: Connection) -> Result<()> { |
27 | log::info!("initial config: {:#?}", config); | 28 | log::info!("initial config: {:#?}", config); |
@@ -197,39 +198,49 @@ impl GlobalState { | |||
197 | } | 198 | } |
198 | self.analysis_host.maybe_collect_garbage(); | 199 | self.analysis_host.maybe_collect_garbage(); |
199 | } | 200 | } |
200 | Event::Vfs(task) => match task { | 201 | Event::Vfs(mut task) => { |
201 | vfs::loader::Message::Loaded { files } => { | 202 | let _p = profile("GlobalState::handle_event/vfs"); |
202 | let vfs = &mut self.vfs.write().0; | 203 | loop { |
203 | for (path, contents) in files { | 204 | match task { |
204 | let path = VfsPath::from(path); | 205 | vfs::loader::Message::Loaded { files } => { |
205 | if !self.mem_docs.contains(&path) { | 206 | let vfs = &mut self.vfs.write().0; |
206 | vfs.set_file_contents(path, contents) | 207 | for (path, contents) in files { |
208 | let path = VfsPath::from(path); | ||
209 | if !self.mem_docs.contains(&path) { | ||
210 | vfs.set_file_contents(path, contents) | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | vfs::loader::Message::Progress { n_total, n_done } => { | ||
215 | if n_total == 0 { | ||
216 | self.transition(Status::Invalid); | ||
217 | } else { | ||
218 | let state = if n_done == 0 { | ||
219 | self.transition(Status::Loading); | ||
220 | Progress::Begin | ||
221 | } else if n_done < n_total { | ||
222 | Progress::Report | ||
223 | } else { | ||
224 | assert_eq!(n_done, n_total); | ||
225 | self.transition(Status::Ready); | ||
226 | Progress::End | ||
227 | }; | ||
228 | self.report_progress( | ||
229 | "roots scanned", | ||
230 | state, | ||
231 | Some(format!("{}/{}", n_done, n_total)), | ||
232 | Some(Progress::percentage(n_done, n_total)), | ||
233 | ) | ||
234 | } | ||
207 | } | 235 | } |
208 | } | 236 | } |
209 | } | 237 | // Coalesce many VFS event into a single loop turn |
210 | vfs::loader::Message::Progress { n_total, n_done } => { | 238 | task = match self.loader.receiver.try_recv() { |
211 | if n_total == 0 { | 239 | Ok(task) => task, |
212 | self.transition(Status::Invalid); | 240 | Err(_) => break, |
213 | } else { | ||
214 | let state = if n_done == 0 { | ||
215 | self.transition(Status::Loading); | ||
216 | Progress::Begin | ||
217 | } else if n_done < n_total { | ||
218 | Progress::Report | ||
219 | } else { | ||
220 | assert_eq!(n_done, n_total); | ||
221 | self.transition(Status::Ready); | ||
222 | Progress::End | ||
223 | }; | ||
224 | self.report_progress( | ||
225 | "roots scanned", | ||
226 | state, | ||
227 | Some(format!("{}/{}", n_done, n_total)), | ||
228 | Some(Progress::percentage(n_done, n_total)), | ||
229 | ) | ||
230 | } | 241 | } |
231 | } | 242 | } |
232 | }, | 243 | } |
233 | Event::Flycheck(task) => match task { | 244 | Event::Flycheck(task) => match task { |
234 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { | 245 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { |
235 | let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( | 246 | let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( |
@@ -428,7 +439,9 @@ impl GlobalState { | |||
428 | if let Some(flycheck) = &this.flycheck { | 439 | if let Some(flycheck) = &this.flycheck { |
429 | flycheck.handle.update(); | 440 | flycheck.handle.update(); |
430 | } | 441 | } |
431 | this.maybe_refresh(params.text_document.uri.as_str()); | 442 | if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) { |
443 | this.maybe_refresh(&[(abs_path, ChangeKind::Modify)]); | ||
444 | } | ||
432 | Ok(()) | 445 | Ok(()) |
433 | })? | 446 | })? |
434 | .on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| { | 447 | .on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| { |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 0a201fceb..ab1b18ea9 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -6,7 +6,7 @@ use flycheck::FlycheckHandle; | |||
6 | use ra_db::{CrateGraph, SourceRoot, VfsPath}; | 6 | use ra_db::{CrateGraph, SourceRoot, VfsPath}; |
7 | use ra_ide::AnalysisChange; | 7 | use ra_ide::AnalysisChange; |
8 | use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace}; | 8 | use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace}; |
9 | use vfs::{file_set::FileSetConfig, AbsPath}; | 9 | use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | config::{Config, FilesWatcher, LinkedProject}, | 12 | config::{Config, FilesWatcher, LinkedProject}, |
@@ -14,9 +14,11 @@ use crate::{ | |||
14 | lsp_ext, | 14 | lsp_ext, |
15 | main_loop::Task, | 15 | main_loop::Task, |
16 | }; | 16 | }; |
17 | use ra_prof::profile; | ||
17 | 18 | ||
18 | impl GlobalState { | 19 | impl GlobalState { |
19 | pub(crate) fn update_configuration(&mut self, config: Config) { | 20 | pub(crate) fn update_configuration(&mut self, config: Config) { |
21 | let _p = profile("GlobalState::update_configuration"); | ||
20 | let old_config = mem::replace(&mut self.config, config); | 22 | let old_config = mem::replace(&mut self.config, config); |
21 | if self.config.lru_capacity != old_config.lru_capacity { | 23 | if self.config.lru_capacity != old_config.lru_capacity { |
22 | self.analysis_host.update_lru_capacity(old_config.lru_capacity); | 24 | self.analysis_host.update_lru_capacity(old_config.lru_capacity); |
@@ -27,8 +29,8 @@ impl GlobalState { | |||
27 | self.reload_flycheck(); | 29 | self.reload_flycheck(); |
28 | } | 30 | } |
29 | } | 31 | } |
30 | pub(crate) fn maybe_refresh(&mut self, saved_doc_url: &str) { | 32 | pub(crate) fn maybe_refresh(&mut self, changes: &[(AbsPathBuf, ChangeKind)]) { |
31 | if !(saved_doc_url.ends_with("Cargo.toml") || saved_doc_url.ends_with("Cargo.lock")) { | 33 | if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { |
32 | return; | 34 | return; |
33 | } | 35 | } |
34 | match self.status { | 36 | match self.status { |
@@ -40,6 +42,41 @@ impl GlobalState { | |||
40 | } else { | 42 | } else { |
41 | self.transition(Status::NeedsReload); | 43 | self.transition(Status::NeedsReload); |
42 | } | 44 | } |
45 | |||
46 | fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool { | ||
47 | const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; | ||
48 | const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"]; | ||
49 | |||
50 | if path.ends_with("Cargo.toml") || path.ends_with("Cargo.lock") { | ||
51 | return true; | ||
52 | } | ||
53 | if change_kind == ChangeKind::Modify { | ||
54 | return false; | ||
55 | } | ||
56 | if path.extension().unwrap_or_default() != "rs" { | ||
57 | return false; | ||
58 | } | ||
59 | if IMPLICIT_TARGET_FILES.iter().any(|it| path.ends_with(it)) { | ||
60 | return true; | ||
61 | } | ||
62 | let parent = match path.parent() { | ||
63 | Some(it) => it, | ||
64 | None => return false, | ||
65 | }; | ||
66 | if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.ends_with(it)) { | ||
67 | return true; | ||
68 | } | ||
69 | if path.ends_with("main.rs") { | ||
70 | let grand_parent = match parent.parent() { | ||
71 | Some(it) => it, | ||
72 | None => return false, | ||
73 | }; | ||
74 | if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.ends_with(it)) { | ||
75 | return true; | ||
76 | } | ||
77 | } | ||
78 | false | ||
79 | } | ||
43 | } | 80 | } |
44 | pub(crate) fn transition(&mut self, new_status: Status) { | 81 | pub(crate) fn transition(&mut self, new_status: Status) { |
45 | self.status = new_status; | 82 | self.status = new_status; |
@@ -79,6 +116,7 @@ impl GlobalState { | |||
79 | }); | 116 | }); |
80 | } | 117 | } |
81 | pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) { | 118 | pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) { |
119 | let _p = profile("GlobalState::switch_workspaces"); | ||
82 | log::info!("reloading projects: {:?}", self.config.linked_projects); | 120 | log::info!("reloading projects: {:?}", self.config.linked_projects); |
83 | 121 | ||
84 | let mut has_errors = false; | 122 | let mut has_errors = false; |
@@ -88,10 +126,12 @@ impl GlobalState { | |||
88 | res.map_err(|err| { | 126 | res.map_err(|err| { |
89 | has_errors = true; | 127 | has_errors = true; |
90 | log::error!("failed to load workspace: {:#}", err); | 128 | log::error!("failed to load workspace: {:#}", err); |
91 | self.show_message( | 129 | if self.workspaces.is_empty() { |
92 | lsp_types::MessageType::Error, | 130 | self.show_message( |
93 | format!("rust-analyzer failed to load workspace: {:#}", err), | 131 | lsp_types::MessageType::Error, |
94 | ); | 132 | format!("rust-analyzer failed to load workspace: {:#}", err), |
133 | ); | ||
134 | } | ||
95 | }) | 135 | }) |
96 | .ok() | 136 | .ok() |
97 | }) | 137 | }) |
@@ -144,6 +184,7 @@ impl GlobalState { | |||
144 | } | 184 | } |
145 | }, | 185 | }, |
146 | }; | 186 | }; |
187 | |||
147 | let watch = match self.config.files.watcher { | 188 | let watch = match self.config.files.watcher { |
148 | FilesWatcher::Client => vec![], | 189 | FilesWatcher::Client => vec![], |
149 | FilesWatcher::Notify => project_folders.watch, | 190 | FilesWatcher::Notify => project_folders.watch, |
@@ -267,6 +308,7 @@ pub(crate) struct SourceRootConfig { | |||
267 | 308 | ||
268 | impl SourceRootConfig { | 309 | impl SourceRootConfig { |
269 | pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> { | 310 | pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> { |
311 | let _p = profile("SourceRootConfig::partition"); | ||
270 | self.fsc | 312 | self.fsc |
271 | .partition(vfs) | 313 | .partition(vfs) |
272 | .into_iter() | 314 | .into_iter() |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 08ac6f70f..3b605c79d 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -87,6 +87,8 @@ where | |||
87 | Ok(()) | 87 | Ok(()) |
88 | } | 88 | } |
89 | } | 89 | } |
90 | |||
91 | #[must_use] | ||
90 | pub fn timeit(label: &'static str) -> impl Drop { | 92 | pub fn timeit(label: &'static str) -> impl Drop { |
91 | struct Guard { | 93 | struct Guard { |
92 | label: &'static str, | 94 | label: &'static str, |
diff --git a/crates/vfs-notify/src/include.rs b/crates/vfs-notify/src/include.rs index 72f928536..59da3d77a 100644 --- a/crates/vfs-notify/src/include.rs +++ b/crates/vfs-notify/src/include.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | //! See `Include`. | 1 | //! See `Include`. |
2 | |||
3 | use std::convert::TryFrom; | 2 | use std::convert::TryFrom; |
4 | 3 | ||
5 | use globset::{Glob, GlobSet, GlobSetBuilder}; | 4 | use globset::{Glob, GlobSet, GlobSetBuilder}; |
diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index ee5035554..6aaa53f63 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs | |||
@@ -82,11 +82,13 @@ impl NotifyActor { | |||
82 | Event::Message(msg) => match msg { | 82 | Event::Message(msg) => match msg { |
83 | Message::Config(config) => { | 83 | Message::Config(config) => { |
84 | self.watcher = None; | 84 | self.watcher = None; |
85 | let (watcher_sender, watcher_receiver) = unbounded(); | 85 | if !config.watch.is_empty() { |
86 | let watcher = log_notify_error(Watcher::new_immediate(move |event| { | 86 | let (watcher_sender, watcher_receiver) = unbounded(); |
87 | watcher_sender.send(event).unwrap() | 87 | let watcher = log_notify_error(Watcher::new_immediate(move |event| { |
88 | })); | 88 | watcher_sender.send(event).unwrap() |
89 | self.watcher = watcher.map(|it| (it, watcher_receiver)); | 89 | })); |
90 | self.watcher = watcher.map(|it| (it, watcher_receiver)); | ||
91 | } | ||
90 | 92 | ||
91 | let n_total = config.load.len(); | 93 | let n_total = config.load.len(); |
92 | self.send(loader::Message::Progress { n_total, n_done: 0 }); | 94 | self.send(loader::Message::Progress { n_total, n_done: 0 }); |
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 024e58018..3bfecd08f 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs | |||
@@ -70,7 +70,7 @@ impl ChangedFile { | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | #[derive(Eq, PartialEq)] | 73 | #[derive(Eq, PartialEq, Copy, Clone, Debug)] |
74 | pub enum ChangeKind { | 74 | pub enum ChangeKind { |
75 | Create, | 75 | Create, |
76 | Modify, | 76 | Modify, |