aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/nameres.rs7
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs5
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs23
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/runnables.rs18
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html76
-rw-r--r--crates/ra_ide/src/status.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs9
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs8
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs3
-rw-r--r--crates/ra_ide_db/src/change.rs79
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs90
-rw-r--r--crates/ra_syntax/src/parsing/text_token_source.rs89
-rw-r--r--crates/rust-analyzer/src/global_state.rs57
-rw-r--r--crates/rust-analyzer/src/main_loop.rs68
-rw-r--r--crates/rust-analyzer/src/to_proto.rs1
16 files changed, 214 insertions, 336 deletions
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index b3e5f491a..b8560fdc9 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -119,13 +119,6 @@ impl Default for ModuleOrigin {
119} 119}
120 120
121impl ModuleOrigin { 121impl ModuleOrigin {
122 pub(crate) fn not_sure_file(file: Option<FileId>, declaration: AstId<ast::Module>) -> Self {
123 match file {
124 None => ModuleOrigin::Inline { definition: declaration },
125 Some(definition) => ModuleOrigin::File { declaration, definition },
126 }
127 }
128
129 fn declaration(&self) -> Option<AstId<ast::Module>> { 122 fn declaration(&self) -> Option<AstId<ast::Module>> {
130 match self { 123 match self {
131 ModuleOrigin::File { declaration: module, .. } 124 ModuleOrigin::File { declaration: module, .. }
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 976e5e585..77baa4c69 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -825,7 +825,10 @@ impl ModCollector<'_, '_> {
825 let modules = &mut self.def_collector.def_map.modules; 825 let modules = &mut self.def_collector.def_map.modules;
826 let res = modules.alloc(ModuleData::default()); 826 let res = modules.alloc(ModuleData::default());
827 modules[res].parent = Some(self.module_id); 827 modules[res].parent = Some(self.module_id);
828 modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration); 828 modules[res].origin = match definition {
829 None => ModuleOrigin::Inline { definition: declaration },
830 Some(definition) => ModuleOrigin::File { declaration, definition },
831 };
829 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { 832 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
830 modules[res].scope.define_legacy_macro(name, mac) 833 modules[res].scope.define_legacy_macro(name, mac)
831 } 834 }
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index c7bb1e69f..0b52b01ab 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -135,8 +135,8 @@ impl NavigationTarget {
135 db: &RootDatabase, 135 db: &RootDatabase,
136 node: InFile<&dyn ast::NameOwner>, 136 node: InFile<&dyn ast::NameOwner>,
137 ) -> NavigationTarget { 137 ) -> NavigationTarget {
138 //FIXME: use `_` instead of empty string 138 let name =
139 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); 139 node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
140 let focus_range = 140 let focus_range =
141 node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range); 141 node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range);
142 let frange = original_range(db, node.map(|it| it.syntax())); 142 let frange = original_range(db, node.map(|it| it.syntax()));
@@ -150,6 +150,25 @@ impl NavigationTarget {
150 ) 150 )
151 } 151 }
152 152
153 /// Allows `NavigationTarget` to be created from a `DocCommentsOwner` and a `NameOwner`
154 pub(crate) fn from_doc_commented(
155 db: &RootDatabase,
156 named: InFile<&dyn ast::NameOwner>,
157 node: InFile<&dyn ast::DocCommentsOwner>,
158 ) -> NavigationTarget {
159 let name =
160 named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
161 let frange = original_range(db, node.map(|it| it.syntax()));
162
163 NavigationTarget::from_syntax(
164 frange.file_id,
165 name,
166 None,
167 frange.range,
168 node.value.syntax().kind(),
169 )
170 }
171
153 fn from_syntax( 172 fn from_syntax(
154 file_id: FileId, 173 file_id: FileId,
155 name: SmolStr, 174 name: SmolStr,
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 375da1f45..51dc1f041 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -82,7 +82,7 @@ pub use ra_db::{
82 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, 82 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId,
83}; 83};
84pub use ra_ide_db::{ 84pub use ra_ide_db::{
85 change::{AnalysisChange, LibraryData}, 85 change::AnalysisChange,
86 line_index::{LineCol, LineIndex}, 86 line_index::{LineCol, LineIndex},
87 search::SearchScope, 87 search::SearchScope,
88 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 88 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index fc57dc33d..8105ef373 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -171,7 +171,15 @@ fn runnable_fn(
171 let cfg_exprs = 171 let cfg_exprs =
172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); 172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
173 173
174 let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); 174 let nav = if let RunnableKind::DocTest { .. } = kind {
175 NavigationTarget::from_doc_commented(
176 sema.db,
177 InFile::new(file_id.into(), &fn_def),
178 InFile::new(file_id.into(), &fn_def),
179 )
180 } else {
181 NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def))
182 };
175 Some(Runnable { nav, kind, cfg_exprs }) 183 Some(Runnable { nav, kind, cfg_exprs })
176} 184}
177 185
@@ -419,9 +427,7 @@ mod tests {
419 full_range: 22..64, 427 full_range: 22..64,
420 name: "foo", 428 name: "foo",
421 kind: FN_DEF, 429 kind: FN_DEF,
422 focus_range: Some( 430 focus_range: None,
423 56..59,
424 ),
425 container_name: None, 431 container_name: None,
426 description: None, 432 description: None,
427 docs: None, 433 docs: None,
@@ -486,9 +492,7 @@ mod tests {
486 full_range: 51..105, 492 full_range: 51..105,
487 name: "foo", 493 name: "foo",
488 kind: FN_DEF, 494 kind: FN_DEF,
489 focus_range: Some( 495 focus_range: None,
490 97..100,
491 ),
492 container_name: None, 496 container_name: None,
493 description: None, 497 description: None,
494 docs: None, 498 docs: None,
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html
index f92a0aba5..f61c0daa5 100644
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ b/crates/ra_ide/src/snapshots/highlight_doctest.html
@@ -39,48 +39,48 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
39<span class="keyword">impl</span> <span class="struct">Foo</span> { 39<span class="keyword">impl</span> <span class="struct">Foo</span> {
40 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span>: <span class="builtin_type">bool</span> = <span class="bool_literal">true</span>; 40 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span>: <span class="builtin_type">bool</span> = <span class="bool_literal">true</span>;
41 41
42 <span class="comment">/// Constructs a new `Foo`.</span> 42 <span class="comment documentation">/// Constructs a new `Foo`.</span>
43 <span class="comment">///</span> 43 <span class="comment documentation">///</span>
44 <span class="comment">/// # Examples</span> 44 <span class="comment documentation">/// # Examples</span>
45 <span class="comment">///</span> 45 <span class="comment documentation">///</span>
46 <span class="comment">/// ```</span> 46 <span class="comment documentation">/// ```</span>
47 <span class="comment">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span> 47 <span class="comment documentation">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span>
48 <span class="comment">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="struct">Foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>(); 48 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="struct">Foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>();
49 <span class="comment">/// ```</span> 49 <span class="comment documentation">/// ```</span>
50 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="struct">Foo</span> { 50 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="struct">Foo</span> {
51 <span class="struct">Foo</span> { <span class="field">bar</span>: <span class="bool_literal">true</span> } 51 <span class="struct">Foo</span> { <span class="field">bar</span>: <span class="bool_literal">true</span> }
52 } 52 }
53 53
54 <span class="comment">/// `bar` method on `Foo`.</span> 54 <span class="comment documentation">/// `bar` method on `Foo`.</span>
55 <span class="comment">///</span> 55 <span class="comment documentation">///</span>
56 <span class="comment">/// # Examples</span> 56 <span class="comment documentation">/// # Examples</span>
57 <span class="comment">///</span> 57 <span class="comment documentation">///</span>
58 <span class="comment">/// ```</span> 58 <span class="comment documentation">/// ```</span>
59 <span class="comment">/// </span><span class="keyword">use</span> <span class="module">x</span>::<span class="module">y</span>; 59 <span class="comment documentation">/// </span><span class="keyword">use</span> <span class="module">x</span>::<span class="module">y</span>;
60 <span class="comment">///</span> 60 <span class="comment documentation">///</span>
61 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>(); 61 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>();
62 <span class="comment">///</span> 62 <span class="comment documentation">///</span>
63 <span class="comment">/// </span><span class="comment">// calls bar on foo</span> 63 <span class="comment documentation">/// </span><span class="comment">// calls bar on foo</span>
64 <span class="comment">/// </span><span class="macro">assert!</span>(foo.bar()); 64 <span class="comment documentation">/// </span><span class="macro">assert!</span>(foo.bar());
65 <span class="comment">///</span> 65 <span class="comment documentation">///</span>
66 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">bar</span> = <span class="variable">foo</span>.<span class="field">bar</span> || <span class="struct">Foo</span>::<span class="constant">bar</span>; 66 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">bar</span> = <span class="variable">foo</span>.<span class="field">bar</span> || <span class="struct">Foo</span>::<span class="constant">bar</span>;
67 <span class="comment">///</span> 67 <span class="comment documentation">///</span>
68 <span class="comment">/// </span><span class="comment">/* multi-line 68 <span class="comment documentation">/// </span><span class="comment">/* multi-line
69 </span><span class="comment">/// </span><span class="comment"> comment */</span> 69 </span><span class="comment documentation">/// </span><span class="comment"> comment */</span>
70 <span class="comment">///</span> 70 <span class="comment documentation">///</span>
71 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">multi_line_string</span> = <span class="string_literal">"Foo 71 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">multi_line_string</span> = <span class="string_literal">"Foo
72 </span><span class="comment">/// </span><span class="string_literal"> bar 72 </span><span class="comment documentation">/// </span><span class="string_literal"> bar
73 </span><span class="comment">/// </span><span class="string_literal"> "</span>; 73 </span><span class="comment documentation">/// </span><span class="string_literal"> "</span>;
74 <span class="comment">///</span> 74 <span class="comment documentation">///</span>
75 <span class="comment">/// ```</span> 75 <span class="comment documentation">/// ```</span>
76 <span class="comment">///</span> 76 <span class="comment documentation">///</span>
77 <span class="comment">/// ```rust,no_run</span> 77 <span class="comment documentation">/// ```rust,no_run</span>
78 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>(); 78 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>();
79 <span class="comment">/// ```</span> 79 <span class="comment documentation">/// ```</span>
80 <span class="comment">///</span> 80 <span class="comment documentation">///</span>
81 <span class="comment">/// ```sh</span> 81 <span class="comment documentation">/// ```sh</span>
82 <span class="comment">/// echo 1</span> 82 <span class="comment documentation">/// echo 1</span>
83 <span class="comment">/// ```</span> 83 <span class="comment documentation">/// ```</span>
84 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> { 84 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> {
85 <span class="bool_literal">true</span> 85 <span class="bool_literal">true</span>
86 } 86 }
diff --git a/crates/ra_ide/src/status.rs b/crates/ra_ide/src/status.rs
index 5b7992920..45411b357 100644
--- a/crates/ra_ide/src/status.rs
+++ b/crates/ra_ide/src/status.rs
@@ -16,6 +16,7 @@ use ra_prof::{memory_usage, Bytes};
16use ra_syntax::{ast, Parse, SyntaxNode}; 16use ra_syntax::{ast, Parse, SyntaxNode};
17 17
18use crate::FileId; 18use crate::FileId;
19use rustc_hash::FxHashMap;
19 20
20fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 21fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
21 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>() 22 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>()
@@ -123,20 +124,24 @@ struct LibrarySymbolsStats {
123 124
124impl fmt::Display for LibrarySymbolsStats { 125impl fmt::Display for LibrarySymbolsStats {
125 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 126 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
126 write!(fmt, "{} ({}) symbols", self.total, self.size,) 127 write!(fmt, "{} ({}) symbols", self.total, self.size)
127 } 128 }
128} 129}
129 130
130impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats { 131impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
132 for LibrarySymbolsStats
133{
131 fn from_iter<T>(iter: T) -> LibrarySymbolsStats 134 fn from_iter<T>(iter: T) -> LibrarySymbolsStats
132 where 135 where
133 T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>, 136 T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
134 { 137 {
135 let mut res = LibrarySymbolsStats::default(); 138 let mut res = LibrarySymbolsStats::default();
136 for entry in iter { 139 for entry in iter {
137 let value = entry.value.unwrap(); 140 let value = entry.value.unwrap();
138 res.total += value.len(); 141 for symbols in value.values() {
139 res.size += value.memory_size(); 142 res.total += symbols.len();
143 res.size += symbols.memory_size();
144 }
140 } 145 }
141 res 146 res
142 } 147 }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 854b6cc6d..f8f790e59 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -489,7 +489,14 @@ fn highlight_element(
489 } 489 }
490 490
491 // Simple token-based highlighting 491 // Simple token-based highlighting
492 COMMENT => HighlightTag::Comment.into(), 492 COMMENT => {
493 let comment = element.into_token().and_then(ast::Comment::cast)?;
494 let h = HighlightTag::Comment;
495 match comment.kind().doc {
496 Some(_) => h | HighlightModifier::Documentation,
497 None => h.into(),
498 }
499 }
493 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::StringLiteral.into(), 500 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::StringLiteral.into(),
494 ATTR => HighlightTag::Attribute.into(), 501 ATTR => HighlightTag::Attribute.into(),
495 INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(), 502 INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(),
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index 929a5cc5c..415f24a6d 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -7,7 +7,10 @@ use hir::Semantics;
7use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; 7use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
8use stdx::SepBy; 8use stdx::SepBy;
9 9
10use crate::{call_info::ActiveParameter, Analysis, HighlightTag, HighlightedRange, RootDatabase}; 10use crate::{
11 call_info::ActiveParameter, Analysis, HighlightModifier, HighlightTag, HighlightedRange,
12 RootDatabase,
13};
11 14
12use super::HighlightedRangeStack; 15use super::HighlightedRangeStack;
13 16
@@ -118,7 +121,7 @@ pub(super) fn extract_doc_comments(
118 range.start(), 121 range.start(),
119 range.start() + TextSize::try_from(pos).unwrap(), 122 range.start() + TextSize::try_from(pos).unwrap(),
120 ), 123 ),
121 highlight: HighlightTag::Comment.into(), 124 highlight: HighlightTag::Comment | HighlightModifier::Documentation,
122 binding_hash: None, 125 binding_hash: None,
123 }); 126 });
124 line_start += range.len() - TextSize::try_from(pos).unwrap(); 127 line_start += range.len() - TextSize::try_from(pos).unwrap();
@@ -164,6 +167,7 @@ pub(super) fn highlight_doc_comment(
164 h.range.start() + start_offset, 167 h.range.start() + start_offset,
165 h.range.end() + end_offset.unwrap_or(start_offset), 168 h.range.end() + end_offset.unwrap_or(start_offset),
166 ); 169 );
170
167 stack.add(h); 171 stack.add(h);
168 } 172 }
169 } 173 }
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index 400d22fb6..93bbb4b4d 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -56,6 +56,7 @@ pub enum HighlightModifier {
56 /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is 56 /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is
57 /// not. 57 /// not.
58 Definition, 58 Definition,
59 Documentation,
59 Mutable, 60 Mutable,
60 Unsafe, 61 Unsafe,
61} 62}
@@ -108,6 +109,7 @@ impl HighlightModifier {
108 HighlightModifier::Attribute, 109 HighlightModifier::Attribute,
109 HighlightModifier::ControlFlow, 110 HighlightModifier::ControlFlow,
110 HighlightModifier::Definition, 111 HighlightModifier::Definition,
112 HighlightModifier::Documentation,
111 HighlightModifier::Mutable, 113 HighlightModifier::Mutable,
112 HighlightModifier::Unsafe, 114 HighlightModifier::Unsafe,
113 ]; 115 ];
@@ -117,6 +119,7 @@ impl HighlightModifier {
117 HighlightModifier::Attribute => "attribute", 119 HighlightModifier::Attribute => "attribute",
118 HighlightModifier::ControlFlow => "control", 120 HighlightModifier::ControlFlow => "control",
119 HighlightModifier::Definition => "declaration", 121 HighlightModifier::Definition => "declaration",
122 HighlightModifier::Documentation => "documentation",
120 HighlightModifier::Mutable => "mutable", 123 HighlightModifier::Mutable => "mutable",
121 HighlightModifier::Unsafe => "unsafe", 124 HighlightModifier::Unsafe => "unsafe",
122 } 125 }
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 2fc796a85..78ee6a515 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -9,22 +9,15 @@ use ra_db::{
9 SourceRootId, 9 SourceRootId,
10}; 10};
11use ra_prof::{memory_usage, profile, Bytes}; 11use ra_prof::{memory_usage, profile, Bytes};
12use ra_syntax::SourceFile;
13#[cfg(not(feature = "wasm"))]
14use rayon::prelude::*;
15use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
16 13
17use crate::{ 14use crate::{symbol_index::SymbolsDatabase, RootDatabase};
18 symbol_index::{SymbolIndex, SymbolsDatabase},
19 RootDatabase,
20};
21 15
22#[derive(Default)] 16#[derive(Default)]
23pub struct AnalysisChange { 17pub struct AnalysisChange {
24 new_roots: Vec<(SourceRootId, bool)>, 18 new_roots: Vec<(SourceRootId, bool)>,
25 roots_changed: FxHashMap<SourceRootId, RootChange>, 19 roots_changed: FxHashMap<SourceRootId, RootChange>,
26 files_changed: Vec<(FileId, Arc<String>)>, 20 files_changed: Vec<(FileId, Arc<String>)>,
27 libraries_added: Vec<LibraryData>,
28 crate_graph: Option<CrateGraph>, 21 crate_graph: Option<CrateGraph>,
29} 22}
30 23
@@ -40,9 +33,6 @@ impl fmt::Debug for AnalysisChange {
40 if !self.files_changed.is_empty() { 33 if !self.files_changed.is_empty() {
41 d.field("files_changed", &self.files_changed.len()); 34 d.field("files_changed", &self.files_changed.len());
42 } 35 }
43 if !self.libraries_added.is_empty() {
44 d.field("libraries_added", &self.libraries_added.len());
45 }
46 if self.crate_graph.is_some() { 36 if self.crate_graph.is_some() {
47 d.field("crate_graph", &self.crate_graph); 37 d.field("crate_graph", &self.crate_graph);
48 } 38 }
@@ -79,10 +69,6 @@ impl AnalysisChange {
79 self.roots_changed.entry(root_id).or_default().removed.push(file); 69 self.roots_changed.entry(root_id).or_default().removed.push(file);
80 } 70 }
81 71
82 pub fn add_library(&mut self, data: LibraryData) {
83 self.libraries_added.push(data)
84 }
85
86 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 72 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
87 self.crate_graph = Some(graph); 73 self.crate_graph = Some(graph);
88 } 74 }
@@ -116,47 +102,6 @@ impl fmt::Debug for RootChange {
116 } 102 }
117} 103}
118 104
119pub struct LibraryData {
120 root_id: SourceRootId,
121 root_change: RootChange,
122 symbol_index: SymbolIndex,
123}
124
125impl fmt::Debug for LibraryData {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 f.debug_struct("LibraryData")
128 .field("root_id", &self.root_id)
129 .field("root_change", &self.root_change)
130 .field("n_symbols", &self.symbol_index.len())
131 .finish()
132 }
133}
134
135impl LibraryData {
136 pub fn prepare(
137 root_id: SourceRootId,
138 files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
139 ) -> LibraryData {
140 let _p = profile("LibraryData::prepare");
141
142 #[cfg(not(feature = "wasm"))]
143 let iter = files.par_iter();
144 #[cfg(feature = "wasm")]
145 let iter = files.iter();
146
147 let symbol_index = SymbolIndex::for_files(iter.map(|(file_id, _, text)| {
148 let parse = SourceFile::parse(text);
149 (*file_id, parse)
150 }));
151 let mut root_change = RootChange::default();
152 root_change.added = files
153 .into_iter()
154 .map(|(file_id, path, text)| AddFile { file_id, path, text })
155 .collect();
156 LibraryData { root_id, root_change, symbol_index }
157 }
158}
159
160const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100); 105const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
161 106
162impl RootDatabase { 107impl RootDatabase {
@@ -171,6 +116,7 @@ impl RootDatabase {
171 log::info!("apply_change {:?}", change); 116 log::info!("apply_change {:?}", change);
172 if !change.new_roots.is_empty() { 117 if !change.new_roots.is_empty() {
173 let mut local_roots = Vec::clone(&self.local_roots()); 118 let mut local_roots = Vec::clone(&self.local_roots());
119 let mut libraries = Vec::clone(&self.library_roots());
174 for (root_id, is_local) in change.new_roots { 120 for (root_id, is_local) in change.new_roots {
175 let root = 121 let root =
176 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() }; 122 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() };
@@ -178,9 +124,12 @@ impl RootDatabase {
178 self.set_source_root_with_durability(root_id, Arc::new(root), durability); 124 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
179 if is_local { 125 if is_local {
180 local_roots.push(root_id); 126 local_roots.push(root_id);
127 } else {
128 libraries.push(root_id)
181 } 129 }
182 } 130 }
183 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); 131 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
132 self.set_library_roots_with_durability(Arc::new(libraries), Durability::HIGH);
184 } 133 }
185 134
186 for (root_id, root_change) in change.roots_changed { 135 for (root_id, root_change) in change.roots_changed {
@@ -192,24 +141,6 @@ impl RootDatabase {
192 let durability = durability(&source_root); 141 let durability = durability(&source_root);
193 self.set_file_text_with_durability(file_id, text, durability) 142 self.set_file_text_with_durability(file_id, text, durability)
194 } 143 }
195 if !change.libraries_added.is_empty() {
196 let mut libraries = Vec::clone(&self.library_roots());
197 for library in change.libraries_added {
198 libraries.push(library.root_id);
199 self.set_source_root_with_durability(
200 library.root_id,
201 Arc::new(SourceRoot::new_library()),
202 Durability::HIGH,
203 );
204 self.set_library_symbols_with_durability(
205 library.root_id,
206 Arc::new(library.symbol_index),
207 Durability::HIGH,
208 );
209 self.apply_root_change(library.root_id, library.root_change);
210 }
211 self.set_library_roots_with_durability(Arc::new(libraries), Durability::HIGH);
212 }
213 if let Some(crate_graph) = change.crate_graph { 144 if let Some(crate_graph) = change.crate_graph {
214 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) 145 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
215 } 146 }
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index aab918973..25c99813f 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -34,14 +34,15 @@ use ra_db::{
34 salsa::{self, ParallelDatabase}, 34 salsa::{self, ParallelDatabase},
35 CrateId, FileId, SourceDatabaseExt, SourceRootId, 35 CrateId, FileId, SourceDatabaseExt, SourceRootId,
36}; 36};
37use ra_prof::profile;
37use ra_syntax::{ 38use ra_syntax::{
38 ast::{self, NameOwner}, 39 ast::{self, NameOwner},
39 match_ast, AstNode, Parse, SmolStr, SourceFile, 40 match_ast, AstNode, Parse, SmolStr, SourceFile,
40 SyntaxKind::{self, *}, 41 SyntaxKind::{self, *},
41 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, 42 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
42}; 43};
43#[cfg(not(feature = "wasm"))]
44use rayon::prelude::*; 44use rayon::prelude::*;
45use rustc_hash::FxHashMap;
45 46
46use crate::RootDatabase; 47use crate::RootDatabase;
47 48
@@ -86,10 +87,9 @@ impl Query {
86} 87}
87 88
88#[salsa::query_group(SymbolsDatabaseStorage)] 89#[salsa::query_group(SymbolsDatabaseStorage)]
89pub trait SymbolsDatabase: hir::db::HirDatabase { 90pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt + ParallelDatabase {
90 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>; 91 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
91 #[salsa::input] 92 fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>;
92 fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>;
93 /// The set of "local" (that is, from the current workspace) roots. 93 /// The set of "local" (that is, from the current workspace) roots.
94 /// Files in local roots are assumed to change frequently. 94 /// Files in local roots are assumed to change frequently.
95 #[salsa::input] 95 #[salsa::input]
@@ -100,6 +100,29 @@ pub trait SymbolsDatabase: hir::db::HirDatabase {
100 fn library_roots(&self) -> Arc<Vec<SourceRootId>>; 100 fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
101} 101}
102 102
103fn library_symbols(
104 db: &(impl SymbolsDatabase + ParallelDatabase),
105) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
106 let _p = profile("library_symbols");
107
108 let roots = db.library_roots();
109 let res = roots
110 .iter()
111 .map(|&root_id| {
112 let root = db.source_root(root_id);
113 let files = root
114 .walk()
115 .map(|it| (it, SourceDatabaseExt::file_text(db, it)))
116 .collect::<Vec<_>>();
117 let symbol_index = SymbolIndex::for_files(
118 files.into_par_iter().map(|(file, text)| (file, SourceFile::parse(&text))),
119 );
120 (root_id, symbol_index)
121 })
122 .collect();
123 Arc::new(res)
124}
125
103fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 126fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
104 db.check_canceled(); 127 db.check_canceled();
105 let parse = db.parse(file_id); 128 let parse = db.parse(file_id);
@@ -112,9 +135,9 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
112} 135}
113 136
114/// Need to wrap Snapshot to provide `Clone` impl for `map_with` 137/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
115struct Snap(salsa::Snapshot<RootDatabase>); 138struct Snap<DB>(DB);
116impl Clone for Snap { 139impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
117 fn clone(&self) -> Snap { 140 fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
118 Snap(self.0.snapshot()) 141 Snap(self.0.snapshot())
119 } 142 }
120} 143}
@@ -143,19 +166,11 @@ impl Clone for Snap {
143pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { 166pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
144 let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); 167 let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone());
145 168
146 let buf: Vec<Arc<SymbolIndex>> = if query.libs { 169 let tmp1;
147 let snap = Snap(db.snapshot()); 170 let tmp2;
148 #[cfg(not(feature = "wasm"))] 171 let buf: Vec<&SymbolIndex> = if query.libs {
149 let buf = db 172 tmp1 = db.library_symbols();
150 .library_roots() 173 tmp1.values().collect()
151 .par_iter()
152 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
153 .collect();
154
155 #[cfg(feature = "wasm")]
156 let buf = db.library_roots().iter().map(|&lib_id| snap.0.library_symbols(lib_id)).collect();
157
158 buf
159 } else { 174 } else {
160 let mut files = Vec::new(); 175 let mut files = Vec::new();
161 for &root in db.local_roots().iter() { 176 for &root in db.local_roots().iter() {
@@ -164,14 +179,11 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
164 } 179 }
165 180
166 let snap = Snap(db.snapshot()); 181 let snap = Snap(db.snapshot());
167 #[cfg(not(feature = "wasm"))] 182 tmp2 = files
168 let buf = 183 .par_iter()
169 files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect(); 184 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
170 185 .collect::<Vec<_>>();
171 #[cfg(feature = "wasm")] 186 tmp2.iter().map(|it| &**it).collect()
172 let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect();
173
174 buf
175 }; 187 };
176 query.search(&buf) 188 query.search(&buf)
177} 189}
@@ -191,14 +203,11 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<Fil
191 203
192 let snap = Snap(db.snapshot()); 204 let snap = Snap(db.snapshot());
193 205
194 #[cfg(not(feature = "wasm"))]
195 let buf = files 206 let buf = files
196 .par_iter() 207 .par_iter()
197 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) 208 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
198 .collect::<Vec<_>>(); 209 .collect::<Vec<_>>();
199 210 let buf = buf.iter().map(|it| &**it).collect::<Vec<_>>();
200 #[cfg(feature = "wasm")]
201 let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect::<Vec<_>>();
202 211
203 query.search(&buf) 212 query.search(&buf)
204} 213}
@@ -245,12 +254,8 @@ impl SymbolIndex {
245 lhs_chars.cmp(rhs_chars) 254 lhs_chars.cmp(rhs_chars)
246 } 255 }
247 256
248 #[cfg(not(feature = "wasm"))]
249 symbols.par_sort_by(cmp); 257 symbols.par_sort_by(cmp);
250 258
251 #[cfg(feature = "wasm")]
252 symbols.sort_by(cmp);
253
254 let mut builder = fst::MapBuilder::memory(); 259 let mut builder = fst::MapBuilder::memory();
255 260
256 let mut last_batch_start = 0; 261 let mut last_batch_start = 0;
@@ -284,7 +289,6 @@ impl SymbolIndex {
284 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>() 289 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
285 } 290 }
286 291
287 #[cfg(not(feature = "wasm"))]
288 pub(crate) fn for_files( 292 pub(crate) fn for_files(
289 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>, 293 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
290 ) -> SymbolIndex { 294 ) -> SymbolIndex {
@@ -294,16 +298,6 @@ impl SymbolIndex {
294 SymbolIndex::new(symbols) 298 SymbolIndex::new(symbols)
295 } 299 }
296 300
297 #[cfg(feature = "wasm")]
298 pub(crate) fn for_files(
299 files: impl Iterator<Item = (FileId, Parse<ast::SourceFile>)>,
300 ) -> SymbolIndex {
301 let symbols = files
302 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
303 .collect::<Vec<_>>();
304 SymbolIndex::new(symbols)
305 }
306
307 fn range_to_map_value(start: usize, end: usize) -> u64 { 301 fn range_to_map_value(start: usize, end: usize) -> u64 {
308 debug_assert![start <= (std::u32::MAX as usize)]; 302 debug_assert![start <= (std::u32::MAX as usize)];
309 debug_assert![end <= (std::u32::MAX as usize)]; 303 debug_assert![end <= (std::u32::MAX as usize)];
@@ -319,7 +313,7 @@ impl SymbolIndex {
319} 313}
320 314
321impl Query { 315impl Query {
322 pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> { 316 pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> {
323 let mut op = fst::map::OpBuilder::new(); 317 let mut op = fst::map::OpBuilder::new();
324 for file_symbols in indices.iter() { 318 for file_symbols in indices.iter() {
325 let automaton = fst::automaton::Subsequence::new(&self.lowercased); 319 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
diff --git a/crates/ra_syntax/src/parsing/text_token_source.rs b/crates/ra_syntax/src/parsing/text_token_source.rs
index 7ddc2c2c3..97aa3e795 100644
--- a/crates/ra_syntax/src/parsing/text_token_source.rs
+++ b/crates/ra_syntax/src/parsing/text_token_source.rs
@@ -1,40 +1,35 @@
1//! FIXME: write short doc here 1//! See `TextTokenSource` docs.
2 2
3use ra_parser::Token as PToken;
4use ra_parser::TokenSource; 3use ra_parser::TokenSource;
5 4
6use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize}; 5use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize};
7 6
7/// Implementation of `ra_parser::TokenSource` that takes tokens from source code text.
8pub(crate) struct TextTokenSource<'t> { 8pub(crate) struct TextTokenSource<'t> {
9 text: &'t str, 9 text: &'t str,
10 /// start position of each token(expect whitespace and comment) 10 /// token and its start position (non-whitespace/comment tokens)
11 /// ```non-rust 11 /// ```non-rust
12 /// struct Foo; 12 /// struct Foo;
13 /// ^------^--- 13 /// ^------^--^-
14 /// | | ^- 14 /// | | \________
15 /// 0 7 10 15 /// | \____ \
16 /// | \ |
17 /// (struct, 0) (Foo, 7) (;, 10)
16 /// ``` 18 /// ```
17 /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]` 19 /// `[(struct, 0), (Foo, 7), (;, 10)]`
18 start_offsets: Vec<TextSize>, 20 token_offset_pairs: Vec<(Token, TextSize)>,
19 /// non-whitespace/comment tokens
20 /// ```non-rust
21 /// struct Foo {}
22 /// ^^^^^^ ^^^ ^^
23 /// ```
24 /// tokens: `[struct, Foo, {, }]`
25 tokens: Vec<Token>,
26 21
27 /// Current token and position 22 /// Current token and position
28 curr: (PToken, usize), 23 curr: (ra_parser::Token, usize),
29} 24}
30 25
31impl<'t> TokenSource for TextTokenSource<'t> { 26impl<'t> TokenSource for TextTokenSource<'t> {
32 fn current(&self) -> PToken { 27 fn current(&self) -> ra_parser::Token {
33 self.curr.0 28 self.curr.0
34 } 29 }
35 30
36 fn lookahead_nth(&self, n: usize) -> PToken { 31 fn lookahead_nth(&self, n: usize) -> ra_parser::Token {
37 mk_token(self.curr.1 + n, &self.start_offsets, &self.tokens) 32 mk_token(self.curr.1 + n, &self.token_offset_pairs)
38 } 33 }
39 34
40 fn bump(&mut self) { 35 fn bump(&mut self) {
@@ -43,45 +38,47 @@ impl<'t> TokenSource for TextTokenSource<'t> {
43 } 38 }
44 39
45 let pos = self.curr.1 + 1; 40 let pos = self.curr.1 + 1;
46 self.curr = (mk_token(pos, &self.start_offsets, &self.tokens), pos); 41 self.curr = (mk_token(pos, &self.token_offset_pairs), pos);
47 } 42 }
48 43
49 fn is_keyword(&self, kw: &str) -> bool { 44 fn is_keyword(&self, kw: &str) -> bool {
50 let pos = self.curr.1; 45 self.token_offset_pairs
51 if pos >= self.tokens.len() { 46 .get(self.curr.1)
52 return false; 47 .map(|(token, offset)| &self.text[TextRange::at(*offset, token.len)] == kw)
53 } 48 .unwrap_or(false)
54 let range = TextRange::at(self.start_offsets[pos], self.tokens[pos].len);
55 self.text[range] == *kw
56 } 49 }
57} 50}
58 51
59fn mk_token(pos: usize, start_offsets: &[TextSize], tokens: &[Token]) -> PToken { 52fn mk_token(pos: usize, token_offset_pairs: &[(Token, TextSize)]) -> ra_parser::Token {
60 let kind = tokens.get(pos).map(|t| t.kind).unwrap_or(EOF); 53 let (kind, is_jointed_to_next) = match token_offset_pairs.get(pos) {
61 let is_jointed_to_next = if pos + 1 < start_offsets.len() { 54 Some((token, offset)) => (
62 start_offsets[pos] + tokens[pos].len == start_offsets[pos + 1] 55 token.kind,
63 } else { 56 token_offset_pairs
64 false 57 .get(pos + 1)
58 .map(|(_, next_offset)| offset + token.len == *next_offset)
59 .unwrap_or(false),
60 ),
61 None => (EOF, false),
65 }; 62 };
66 63 ra_parser::Token { kind, is_jointed_to_next }
67 PToken { kind, is_jointed_to_next }
68} 64}
69 65
70impl<'t> TextTokenSource<'t> { 66impl<'t> TextTokenSource<'t> {
71 /// Generate input from tokens(expect comment and whitespace). 67 /// Generate input from tokens(expect comment and whitespace).
72 pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> TextTokenSource<'t> { 68 pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> TextTokenSource<'t> {
73 let mut tokens = Vec::new(); 69 let token_offset_pairs: Vec<_> = raw_tokens
74 let mut start_offsets = Vec::new(); 70 .iter()
75 let mut len = 0.into(); 71 .filter_map({
76 for &token in raw_tokens.iter() { 72 let mut len = 0.into();
77 if !token.kind.is_trivia() { 73 move |token| {
78 tokens.push(token); 74 let pair = if token.kind.is_trivia() { None } else { Some((*token, len)) };
79 start_offsets.push(len); 75 len += token.len;
80 } 76 pair
81 len += token.len; 77 }
82 } 78 })
79 .collect();
83 80
84 let first = mk_token(0, &start_offsets, &tokens); 81 let first = mk_token(0, &token_offset_pairs);
85 TextTokenSource { text, start_offsets, tokens, curr: (first, 0) } 82 TextTokenSource { text, token_offset_pairs, curr: (first, 0) }
86 } 83 }
87} 84}
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index ef6c7d44d..1527c9947 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -12,16 +12,13 @@ use crossbeam_channel::{unbounded, Receiver};
12use lsp_types::Url; 12use lsp_types::Url;
13use parking_lot::RwLock; 13use parking_lot::RwLock;
14use ra_flycheck::{Flycheck, FlycheckConfig}; 14use ra_flycheck::{Flycheck, FlycheckConfig};
15use ra_ide::{ 15use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, SourceRootId};
16 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId,
17};
18use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 16use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
19use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsTask, Watch}; 17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsTask, Watch};
20use relative_path::RelativePathBuf;
21use stdx::format_to; 18use stdx::format_to;
22 19
23use crate::{ 20use crate::{
24 config::Config, 21 config::{Config, FilesWatcher},
25 diagnostics::{CheckFixes, DiagnosticCollection}, 22 diagnostics::{CheckFixes, DiagnosticCollection},
26 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 23 main_loop::pending_requests::{CompletedRequest, LatestRequests},
27 to_proto::url_from_abs_path, 24 to_proto::url_from_abs_path,
@@ -33,20 +30,16 @@ use rustc_hash::{FxHashMap, FxHashSet};
33 30
34fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> { 31fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> {
35 // FIXME: Figure out the multi-workspace situation 32 // FIXME: Figure out the multi-workspace situation
36 workspaces 33 workspaces.iter().find_map(|w| match w {
37 .iter() 34 ProjectWorkspace::Cargo { cargo, .. } => {
38 .find_map(|w| match w {
39 ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
40 ProjectWorkspace::Json { .. } => None,
41 })
42 .map(|cargo| {
43 let cargo_project_root = cargo.workspace_root().to_path_buf(); 35 let cargo_project_root = cargo.workspace_root().to_path_buf();
44 Some(Flycheck::new(config.clone(), cargo_project_root)) 36 Some(Flycheck::new(config.clone(), cargo_project_root))
45 }) 37 }
46 .unwrap_or_else(|| { 38 ProjectWorkspace::Json { .. } => {
47 log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); 39 log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
48 None 40 None
49 }) 41 }
42 })
50} 43}
51 44
52/// `GlobalState` is the primary mutable state of the language server 45/// `GlobalState` is the primary mutable state of the language server
@@ -83,7 +76,6 @@ impl GlobalState {
83 workspaces: Vec<ProjectWorkspace>, 76 workspaces: Vec<ProjectWorkspace>,
84 lru_capacity: Option<usize>, 77 lru_capacity: Option<usize>,
85 exclude_globs: &[Glob], 78 exclude_globs: &[Glob],
86 watch: Watch,
87 config: Config, 79 config: Config,
88 ) -> GlobalState { 80 ) -> GlobalState {
89 let mut change = AnalysisChange::new(); 81 let mut change = AnalysisChange::new();
@@ -118,6 +110,7 @@ impl GlobalState {
118 110
119 let (task_sender, task_receiver) = unbounded(); 111 let (task_sender, task_receiver) = unbounded();
120 let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); 112 let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
113 let watch = Watch(matches!(config.files.watcher, FilesWatcher::Notify));
121 let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); 114 let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
122 115
123 let mut extern_source_roots = FxHashMap::default(); 116 let mut extern_source_roots = FxHashMap::default();
@@ -195,32 +188,18 @@ impl GlobalState {
195 188
196 /// Returns a vec of libraries 189 /// Returns a vec of libraries
197 /// FIXME: better API here 190 /// FIXME: better API here
198 pub fn process_changes( 191 pub fn process_changes(&mut self, roots_scanned: &mut usize) -> bool {
199 &mut self,
200 roots_scanned: &mut usize,
201 ) -> Option<Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>> {
202 let changes = self.vfs.write().commit_changes(); 192 let changes = self.vfs.write().commit_changes();
203 if changes.is_empty() { 193 if changes.is_empty() {
204 return None; 194 return false;
205 } 195 }
206 let mut libs = Vec::new();
207 let mut change = AnalysisChange::new(); 196 let mut change = AnalysisChange::new();
208 for c in changes { 197 for c in changes {
209 match c { 198 match c {
210 VfsChange::AddRoot { root, files } => { 199 VfsChange::AddRoot { root, files } => {
211 let root_path = self.vfs.read().root2path(root); 200 *roots_scanned += 1;
212 let is_local = self.local_roots.iter().any(|r| root_path.starts_with(r)); 201 for (file, path, text) in files {
213 if is_local { 202 change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
214 *roots_scanned += 1;
215 for (file, path, text) in files {
216 change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
217 }
218 } else {
219 let files = files
220 .into_iter()
221 .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
222 .collect();
223 libs.push((SourceRootId(root.0), files));
224 } 203 }
225 } 204 }
226 VfsChange::AddFile { root, file, path, text } => { 205 VfsChange::AddFile { root, file, path, text } => {
@@ -235,13 +214,7 @@ impl GlobalState {
235 } 214 }
236 } 215 }
237 self.analysis_host.apply_change(change); 216 self.analysis_host.apply_change(change);
238 Some(libs) 217 true
239 }
240
241 pub fn add_lib(&mut self, data: LibraryData) {
242 let mut change = AnalysisChange::new();
243 change.add_library(data);
244 self.analysis_host.apply_change(change);
245 } 218 }
246 219
247 pub fn snapshot(&self) -> GlobalStateSnapshot { 220 pub fn snapshot(&self) -> GlobalStateSnapshot {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 80cfd3c28..f0aaaa21e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -24,11 +24,10 @@ use lsp_types::{
24 WorkDoneProgressReport, 24 WorkDoneProgressReport,
25}; 25};
26use ra_flycheck::{CheckTask, Status}; 26use ra_flycheck::{CheckTask, Status};
27use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; 27use ra_ide::{Canceled, FileId, LineIndex};
28use ra_prof::profile; 28use ra_prof::profile;
29use ra_project_model::{PackageRoot, ProjectWorkspace}; 29use ra_project_model::{PackageRoot, ProjectWorkspace};
30use ra_vfs::{VfsTask, Watch}; 30use ra_vfs::VfsTask;
31use relative_path::RelativePathBuf;
32use rustc_hash::FxHashSet; 31use rustc_hash::FxHashSet;
33use serde::{de::DeserializeOwned, Serialize}; 32use serde::{de::DeserializeOwned, Serialize};
34use threadpool::ThreadPool; 33use threadpool::ThreadPool;
@@ -161,25 +160,17 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
161 connection.sender.send(request.into()).unwrap(); 160 connection.sender.send(request.into()).unwrap();
162 } 161 }
163 162
164 GlobalState::new( 163 GlobalState::new(workspaces, config.lru_capacity, &globs, config)
165 workspaces,
166 config.lru_capacity,
167 &globs,
168 Watch(matches!(config.files.watcher, FilesWatcher::Notify)),
169 config,
170 )
171 }; 164 };
172 165
173 loop_state.roots_total = global_state.vfs.read().n_roots(); 166 loop_state.roots_total = global_state.vfs.read().n_roots();
174 167
175 let pool = ThreadPool::default(); 168 let pool = ThreadPool::default();
176 let (task_sender, task_receiver) = unbounded::<Task>(); 169 let (task_sender, task_receiver) = unbounded::<Task>();
177 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
178 170
179 log::info!("server initialized, serving requests"); 171 log::info!("server initialized, serving requests");
180 { 172 {
181 let task_sender = task_sender; 173 let task_sender = task_sender;
182 let libdata_sender = libdata_sender;
183 loop { 174 loop {
184 log::trace!("selecting"); 175 log::trace!("selecting");
185 let event = select! { 176 let event = select! {
@@ -192,7 +183,6 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
192 Ok(task) => Event::Vfs(task), 183 Ok(task) => Event::Vfs(task),
193 Err(RecvError) => return Err("vfs died".into()), 184 Err(RecvError) => return Err("vfs died".into()),
194 }, 185 },
195 recv(libdata_receiver) -> data => Event::Lib(data.unwrap()),
196 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { 186 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
197 Ok(task) => Event::CheckWatcher(task), 187 Ok(task) => Event::CheckWatcher(task),
198 Err(RecvError) => return Err("check watcher died".into()), 188 Err(RecvError) => return Err("check watcher died".into()),
@@ -203,15 +193,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
203 break; 193 break;
204 }; 194 };
205 } 195 }
206 loop_turn( 196 loop_turn(&pool, &task_sender, &connection, &mut global_state, &mut loop_state, event)?;
207 &pool,
208 &task_sender,
209 &libdata_sender,
210 &connection,
211 &mut global_state,
212 &mut loop_state,
213 event,
214 )?;
215 } 197 }
216 } 198 }
217 global_state.analysis_host.request_cancellation(); 199 global_state.analysis_host.request_cancellation();
@@ -219,7 +201,6 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
219 task_receiver.into_iter().for_each(|task| { 201 task_receiver.into_iter().for_each(|task| {
220 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state) 202 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state)
221 }); 203 });
222 libdata_receiver.into_iter().for_each(drop);
223 log::info!("...tasks have finished"); 204 log::info!("...tasks have finished");
224 log::info!("joining threadpool..."); 205 log::info!("joining threadpool...");
225 pool.join(); 206 pool.join();
@@ -243,7 +224,6 @@ enum Event {
243 Msg(Message), 224 Msg(Message),
244 Task(Task), 225 Task(Task),
245 Vfs(VfsTask), 226 Vfs(VfsTask),
246 Lib(LibraryData),
247 CheckWatcher(CheckTask), 227 CheckWatcher(CheckTask),
248} 228}
249 229
@@ -279,7 +259,6 @@ impl fmt::Debug for Event {
279 Event::Msg(it) => fmt::Debug::fmt(it, f), 259 Event::Msg(it) => fmt::Debug::fmt(it, f),
280 Event::Task(it) => fmt::Debug::fmt(it, f), 260 Event::Task(it) => fmt::Debug::fmt(it, f),
281 Event::Vfs(it) => fmt::Debug::fmt(it, f), 261 Event::Vfs(it) => fmt::Debug::fmt(it, f),
282 Event::Lib(it) => fmt::Debug::fmt(it, f),
283 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f), 262 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f),
284 } 263 }
285 } 264 }
@@ -291,10 +270,6 @@ struct LoopState {
291 pending_responses: FxHashSet<RequestId>, 270 pending_responses: FxHashSet<RequestId>,
292 pending_requests: PendingRequests, 271 pending_requests: PendingRequests,
293 subscriptions: Subscriptions, 272 subscriptions: Subscriptions,
294 // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same
295 // time to always have a thread ready to react to input.
296 in_flight_libraries: usize,
297 pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
298 workspace_loaded: bool, 273 workspace_loaded: bool,
299 roots_progress_reported: Option<usize>, 274 roots_progress_reported: Option<usize>,
300 roots_scanned: usize, 275 roots_scanned: usize,
@@ -315,7 +290,6 @@ impl LoopState {
315fn loop_turn( 290fn loop_turn(
316 pool: &ThreadPool, 291 pool: &ThreadPool,
317 task_sender: &Sender<Task>, 292 task_sender: &Sender<Task>,
318 libdata_sender: &Sender<LibraryData>,
319 connection: &Connection, 293 connection: &Connection,
320 global_state: &mut GlobalState, 294 global_state: &mut GlobalState,
321 loop_state: &mut LoopState, 295 loop_state: &mut LoopState,
@@ -339,12 +313,6 @@ fn loop_turn(
339 Event::Vfs(task) => { 313 Event::Vfs(task) => {
340 global_state.vfs.write().handle_task(task); 314 global_state.vfs.write().handle_task(task);
341 } 315 }
342 Event::Lib(lib) => {
343 global_state.add_lib(lib);
344 global_state.maybe_collect_garbage();
345 loop_state.in_flight_libraries -= 1;
346 loop_state.roots_scanned += 1;
347 }
348 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?, 316 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
349 Event::Msg(msg) => match msg { 317 Event::Msg(msg) => match msg {
350 Message::Request(req) => on_request( 318 Message::Request(req) => on_request(
@@ -390,36 +358,12 @@ fn loop_turn(
390 }, 358 },
391 }; 359 };
392 360
393 let mut state_changed = false; 361 let mut state_changed = global_state.process_changes(&mut loop_state.roots_scanned);
394 if let Some(changes) = global_state.process_changes(&mut loop_state.roots_scanned) {
395 state_changed = true;
396 loop_state.pending_libraries.extend(changes);
397 }
398
399 let max_in_flight_libs = pool.max_count().saturating_sub(2).max(1);
400 while loop_state.in_flight_libraries < max_in_flight_libs {
401 let (root, files) = match loop_state.pending_libraries.pop() {
402 Some(it) => it,
403 None => break,
404 };
405
406 loop_state.in_flight_libraries += 1;
407 let sender = libdata_sender.clone();
408 pool.execute(move || {
409 log::info!("indexing {:?} ... ", root);
410 let data = LibraryData::prepare(root, files);
411 sender.send(data).unwrap();
412 });
413 }
414 362
415 let show_progress = 363 let show_progress =
416 !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress; 364 !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress;
417 365
418 if !loop_state.workspace_loaded 366 if !loop_state.workspace_loaded && loop_state.roots_scanned == loop_state.roots_total {
419 && loop_state.roots_scanned == loop_state.roots_total
420 && loop_state.pending_libraries.is_empty()
421 && loop_state.in_flight_libraries == 0
422 {
423 state_changed = true; 367 state_changed = true;
424 loop_state.workspace_loaded = true; 368 loop_state.workspace_loaded = true;
425 if let Some(flycheck) = &global_state.flycheck { 369 if let Some(flycheck) = &global_state.flycheck {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 055c97455..ec153097e 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -331,6 +331,7 @@ fn semantic_token_type_and_modifiers(
331 let modifier = match modifier { 331 let modifier = match modifier {
332 HighlightModifier::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER, 332 HighlightModifier::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER,
333 HighlightModifier::Definition => lsp_types::SemanticTokenModifier::DECLARATION, 333 HighlightModifier::Definition => lsp_types::SemanticTokenModifier::DECLARATION,
334 HighlightModifier::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION,
334 HighlightModifier::ControlFlow => semantic_tokens::CONTROL_FLOW, 335 HighlightModifier::ControlFlow => semantic_tokens::CONTROL_FLOW,
335 HighlightModifier::Mutable => semantic_tokens::MUTABLE, 336 HighlightModifier::Mutable => semantic_tokens::MUTABLE,
336 HighlightModifier::Unsafe => semantic_tokens::UNSAFE, 337 HighlightModifier::Unsafe => semantic_tokens::UNSAFE,