aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/attr.rs12
-rw-r--r--crates/hir_expand/src/db.rs33
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html2
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs2
-rw-r--r--crates/rust-analyzer/src/benchmarks.rs74
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs184
-rw-r--r--crates/rust-analyzer/src/lib.rs2
7 files changed, 216 insertions, 93 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index d9294d93a..0171d8a92 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -484,10 +484,10 @@ impl AttrsWithOwner {
484 let mut buf = String::new(); 484 let mut buf = String::new();
485 let mut mapping = Vec::new(); 485 let mut mapping = Vec::new();
486 for (doc, idx) in docs { 486 for (doc, idx) in docs {
487 // str::lines doesn't yield anything for the empty string
488 if !doc.is_empty() { 487 if !doc.is_empty() {
489 for line in doc.split('\n') { 488 let mut base_offset = 0;
490 let line = line.trim_end(); 489 for raw_line in doc.split('\n') {
490 let line = raw_line.trim_end();
491 let line_len = line.len(); 491 let line_len = line.len();
492 let (offset, line) = match line.char_indices().nth(indent) { 492 let (offset, line) = match line.char_indices().nth(indent) {
493 Some((offset, _)) => (offset, &line[offset..]), 493 Some((offset, _)) => (offset, &line[offset..]),
@@ -498,9 +498,13 @@ impl AttrsWithOwner {
498 mapping.push(( 498 mapping.push((
499 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?), 499 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
500 idx, 500 idx,
501 TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?), 501 TextRange::at(
502 (base_offset + offset).try_into().ok()?,
503 line_len.try_into().ok()?,
504 ),
502 )); 505 ));
503 buf.push('\n'); 506 buf.push('\n');
507 base_offset += raw_line.len() + 1;
504 } 508 }
505 } else { 509 } else {
506 buf.push('\n'); 510 buf.push('\n');
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 1e4b0cc19..1389e30db 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -3,14 +3,14 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroDef, MacroRules}; 6use mbe::{ExpandError, ExpandResult};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{ 8use syntax::{
9 algo::diff, 9 algo::diff,
10 ast::{MacroStmts, NameOwner}, 10 ast::{self, NameOwner},
11 AstNode, GreenNode, Parse, 11 AstNode, GreenNode, Parse,
12 SyntaxKind::*, 12 SyntaxKind::*,
13 SyntaxNode, 13 SyntaxNode, SyntaxToken,
14}; 14};
15 15
16use crate::{ 16use crate::{
@@ -27,15 +27,20 @@ const TOKEN_LIMIT: usize = 524288;
27 27
28#[derive(Debug, Clone, Eq, PartialEq)] 28#[derive(Debug, Clone, Eq, PartialEq)]
29pub enum TokenExpander { 29pub enum TokenExpander {
30 /// Old-style `macro_rules`.
30 MacroRules(mbe::MacroRules), 31 MacroRules(mbe::MacroRules),
32 /// AKA macros 2.0.
31 MacroDef(mbe::MacroDef), 33 MacroDef(mbe::MacroDef),
34 /// Stuff like `line!` and `file!`.
32 Builtin(BuiltinFnLikeExpander), 35 Builtin(BuiltinFnLikeExpander),
36 /// `derive(Copy)` and such.
33 BuiltinDerive(BuiltinDeriveExpander), 37 BuiltinDerive(BuiltinDeriveExpander),
38 /// The thing we love the most here in rust-analyzer -- procedural macros.
34 ProcMacro(ProcMacroExpander), 39 ProcMacro(ProcMacroExpander),
35} 40}
36 41
37impl TokenExpander { 42impl TokenExpander {
38 pub fn expand( 43 fn expand(
39 &self, 44 &self,
40 db: &dyn AstDatabase, 45 db: &dyn AstDatabase,
41 id: LazyMacroId, 46 id: LazyMacroId,
@@ -56,7 +61,7 @@ impl TokenExpander {
56 } 61 }
57 } 62 }
58 63
59 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { 64 pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
60 match self { 65 match self {
61 TokenExpander::MacroRules(it) => it.map_id_down(id), 66 TokenExpander::MacroRules(it) => it.map_id_down(id),
62 TokenExpander::MacroDef(it) => it.map_id_down(id), 67 TokenExpander::MacroDef(it) => it.map_id_down(id),
@@ -66,7 +71,7 @@ impl TokenExpander {
66 } 71 }
67 } 72 }
68 73
69 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 74 pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
70 match self { 75 match self {
71 TokenExpander::MacroRules(it) => it.map_id_up(id), 76 TokenExpander::MacroRules(it) => it.map_id_up(id),
72 TokenExpander::MacroDef(it) => it.map_id_up(id), 77 TokenExpander::MacroDef(it) => it.map_id_up(id),
@@ -115,9 +120,9 @@ pub trait AstDatabase: SourceDatabase {
115pub fn expand_hypothetical( 120pub fn expand_hypothetical(
116 db: &dyn AstDatabase, 121 db: &dyn AstDatabase,
117 actual_macro_call: MacroCallId, 122 actual_macro_call: MacroCallId,
118 hypothetical_args: &syntax::ast::TokenTree, 123 hypothetical_args: &ast::TokenTree,
119 token_to_map: syntax::SyntaxToken, 124 token_to_map: SyntaxToken,
120) -> Option<(SyntaxNode, syntax::SyntaxToken)> { 125) -> Option<(SyntaxNode, SyntaxToken)> {
121 let macro_file = MacroFile { macro_call_id: actual_macro_call }; 126 let macro_file = MacroFile { macro_call_id: actual_macro_call };
122 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax()); 127 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax());
123 let range = 128 let range =
@@ -141,10 +146,10 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
141fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 146fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
142 match id.kind { 147 match id.kind {
143 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { 148 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) {
144 syntax::ast::Macro::MacroRules(macro_rules) => { 149 ast::Macro::MacroRules(macro_rules) => {
145 let arg = macro_rules.token_tree()?; 150 let arg = macro_rules.token_tree()?;
146 let (tt, tmap) = mbe::ast_to_token_tree(&arg); 151 let (tt, tmap) = mbe::ast_to_token_tree(&arg);
147 let rules = match MacroRules::parse(&tt) { 152 let rules = match mbe::MacroRules::parse(&tt) {
148 Ok(it) => it, 153 Ok(it) => it,
149 Err(err) => { 154 Err(err) => {
150 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); 155 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default();
@@ -154,10 +159,10 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
154 }; 159 };
155 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 160 Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
156 } 161 }
157 syntax::ast::Macro::MacroDef(macro_def) => { 162 ast::Macro::MacroDef(macro_def) => {
158 let arg = macro_def.body()?; 163 let arg = macro_def.body()?;
159 let (tt, tmap) = mbe::ast_to_token_tree(&arg); 164 let (tt, tmap) = mbe::ast_to_token_tree(&arg);
160 let rules = match MacroDef::parse(&tt) { 165 let rules = match mbe::MacroDef::parse(&tt) {
161 Ok(it) => it, 166 Ok(it) => it,
162 Err(err) => { 167 Err(err) => {
163 let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default(); 168 let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default();
@@ -403,7 +408,7 @@ fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool {
403 if diff(from, to).is_empty() { 408 if diff(from, to).is_empty() {
404 return true; 409 return true;
405 } 410 }
406 if let Some(stmts) = MacroStmts::cast(from.clone()) { 411 if let Some(stmts) = ast::MacroStmts::cast(from.clone()) {
407 if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) { 412 if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) {
408 return true; 413 return true;
409 } 414 }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 638f42c2f..8d83ba206 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -142,6 +142,7 @@ It is beyond me why you'd use these when you got ///
142```rust 142```rust
143</span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation"> 143</span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation">
144``` 144```
145</span><span class="function documentation injected intra_doc_link">[`block_comments2`]</span><span class="comment documentation"> tests these with indentation
145 */</span> 146 */</span>
146<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 147<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
147 148
@@ -150,5 +151,6 @@ It is beyond me why you'd use these when you got ///
150 ```rust 151 ```rust
151</span><span class="comment documentation"> </span><span class="none injected"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation"> 152</span><span class="comment documentation"> </span><span class="none injected"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation">
152 ``` 153 ```
154 </span><span class="function documentation injected intra_doc_link">[`block_comments`]</span><span class="comment documentation"> tests these without indentation
153*/</span> 155*/</span>
154<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments2</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file 156<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments2</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 17cc6334b..b6e952b08 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -618,6 +618,7 @@ It is beyond me why you'd use these when you got ///
618```rust 618```rust
619let _ = example(&[1, 2, 3]); 619let _ = example(&[1, 2, 3]);
620``` 620```
621[`block_comments2`] tests these with indentation
621 */ 622 */
622pub fn block_comments() {} 623pub fn block_comments() {}
623 624
@@ -626,6 +627,7 @@ pub fn block_comments() {}
626 ```rust 627 ```rust
627 let _ = example(&[1, 2, 3]); 628 let _ = example(&[1, 2, 3]);
628 ``` 629 ```
630 [`block_comments`] tests these without indentation
629*/ 631*/
630pub fn block_comments2() {} 632pub fn block_comments2() {}
631"# 633"#
diff --git a/crates/rust-analyzer/src/benchmarks.rs b/crates/rust-analyzer/src/benchmarks.rs
deleted file mode 100644
index bdd94b1c4..000000000
--- a/crates/rust-analyzer/src/benchmarks.rs
+++ /dev/null
@@ -1,74 +0,0 @@
1//! Fully integrated benchmarks for rust-analyzer, which load real cargo
2//! projects.
3//!
4//! The benchmark here is used to debug specific performance regressions. If you
5//! notice that, eg, completion is slow in some specific case, you can modify
6//! code here exercise this specific completion, and thus have a fast
7//! edit/compile/test cycle.
8//!
9//! Note that "Rust Analyzer: Run" action does not allow running a single test
10//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
11//! which you can use to paste the command in terminal and add `--release` manually.
12
13use std::sync::Arc;
14
15use ide::Change;
16use test_utils::project_root;
17use vfs::{AbsPathBuf, VfsPath};
18
19use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
20
21#[test]
22fn benchmark_integrated_highlighting() {
23 // Don't run slow benchmark by default
24 if true {
25 return;
26 }
27
28 // Load rust-analyzer itself.
29 let workspace_to_load = project_root();
30 let file = "./crates/ide_db/src/apply_change.rs";
31
32 let cargo_config = Default::default();
33 let load_cargo_config = LoadCargoConfig {
34 load_out_dirs_from_check: true,
35 wrap_rustc: false,
36 with_proc_macro: false,
37 };
38
39 let (mut host, vfs, _proc_macro) = {
40 let _it = stdx::timeit("workspace loading");
41 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
42 };
43
44 let file_id = {
45 let file = workspace_to_load.join(file);
46 let path = VfsPath::from(AbsPathBuf::assert(file));
47 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
48 };
49
50 {
51 let _it = stdx::timeit("initial");
52 let analysis = host.analysis();
53 analysis.highlight_as_html(file_id, false).unwrap();
54 }
55
56 profile::init_from("*>100");
57 // let _s = profile::heartbeat_span();
58
59 {
60 let _it = stdx::timeit("change");
61 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
62 text.push_str("\npub fn _dummy() {}\n");
63 let mut change = Change::new();
64 change.change_file(file_id, Some(Arc::new(text)));
65 host.apply_change(change);
66 }
67
68 {
69 let _it = stdx::timeit("after change");
70 let _span = profile::cpu_span();
71 let analysis = host.analysis();
72 analysis.highlight_as_html(file_id, false).unwrap();
73 }
74}
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
new file mode 100644
index 000000000..3dcbe397a
--- /dev/null
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -0,0 +1,184 @@
1//! Fully integrated benchmarks for rust-analyzer, which load real cargo
2//! projects.
3//!
4//! The benchmark here is used to debug specific performance regressions. If you
5//! notice that, eg, completion is slow in some specific case, you can modify
6//! code here exercise this specific completion, and thus have a fast
7//! edit/compile/test cycle.
8//!
9//! Note that "Rust Analyzer: Run" action does not allow running a single test
10//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
11//! which you can use to paste the command in terminal and add `--release` manually.
12
13use std::{convert::TryFrom, sync::Arc};
14
15use ide::{Change, CompletionConfig, FilePosition, TextSize};
16use ide_db::helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap};
17use test_utils::project_root;
18use vfs::{AbsPathBuf, VfsPath};
19
20use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
21
22#[test]
23fn integrated_highlighting_benchmark() {
24 if std::env::var("RUN_SLOW_BENCHES").is_err() {
25 return;
26 }
27
28 // Load rust-analyzer itself.
29 let workspace_to_load = project_root();
30 let file = "./crates/ide_db/src/apply_change.rs";
31
32 let cargo_config = Default::default();
33 let load_cargo_config = LoadCargoConfig {
34 load_out_dirs_from_check: true,
35 wrap_rustc: false,
36 with_proc_macro: false,
37 };
38
39 let (mut host, vfs, _proc_macro) = {
40 let _it = stdx::timeit("workspace loading");
41 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
42 };
43
44 let file_id = {
45 let file = workspace_to_load.join(file);
46 let path = VfsPath::from(AbsPathBuf::assert(file));
47 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
48 };
49
50 {
51 let _it = stdx::timeit("initial");
52 let analysis = host.analysis();
53 analysis.highlight_as_html(file_id, false).unwrap();
54 }
55
56 profile::init_from("*>100");
57 // let _s = profile::heartbeat_span();
58
59 {
60 let _it = stdx::timeit("change");
61 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
62 text.push_str("\npub fn _dummy() {}\n");
63 let mut change = Change::new();
64 change.change_file(file_id, Some(Arc::new(text)));
65 host.apply_change(change);
66 }
67
68 {
69 let _it = stdx::timeit("after change");
70 let _span = profile::cpu_span();
71 let analysis = host.analysis();
72 analysis.highlight_as_html(file_id, false).unwrap();
73 }
74}
75
76#[test]
77fn integrated_completion_benchmark() {
78 if std::env::var("RUN_SLOW_BENCHES").is_err() {
79 return;
80 }
81
82 // Load rust-analyzer itself.
83 let workspace_to_load = project_root();
84 let file = "./crates/hir/src/lib.rs";
85
86 let cargo_config = Default::default();
87 let load_cargo_config = LoadCargoConfig {
88 load_out_dirs_from_check: true,
89 wrap_rustc: false,
90 with_proc_macro: false,
91 };
92
93 let (mut host, vfs, _proc_macro) = {
94 let _it = stdx::timeit("workspace loading");
95 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
96 };
97
98 let file_id = {
99 let file = workspace_to_load.join(file);
100 let path = VfsPath::from(AbsPathBuf::assert(file));
101 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
102 };
103
104 {
105 let _it = stdx::timeit("initial");
106 let analysis = host.analysis();
107 analysis.highlight_as_html(file_id, false).unwrap();
108 }
109
110 profile::init_from("*>5");
111 // let _s = profile::heartbeat_span();
112
113 let completion_offset = {
114 let _it = stdx::timeit("change");
115 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
116 let completion_offset =
117 patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)")
118 + "sel".len();
119 let mut change = Change::new();
120 change.change_file(file_id, Some(Arc::new(text)));
121 host.apply_change(change);
122 completion_offset
123 };
124
125 {
126 let _it = stdx::timeit("unqualified path completion");
127 let _span = profile::cpu_span();
128 let analysis = host.analysis();
129 let config = CompletionConfig {
130 enable_postfix_completions: true,
131 enable_imports_on_the_fly: true,
132 add_call_parenthesis: true,
133 add_call_argument_snippets: true,
134 snippet_cap: SnippetCap::new(true),
135 insert_use: InsertUseConfig {
136 merge: Some(MergeBehavior::Full),
137 prefix_kind: hir::PrefixKind::ByCrate,
138 group: true,
139 },
140 };
141 let position =
142 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
143 analysis.completions(&config, position).unwrap();
144 }
145
146 let completion_offset = {
147 let _it = stdx::timeit("change");
148 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
149 let completion_offset =
150 patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)")
151 + "self.".len();
152 let mut change = Change::new();
153 change.change_file(file_id, Some(Arc::new(text)));
154 host.apply_change(change);
155 completion_offset
156 };
157
158 {
159 let _it = stdx::timeit("dot completion");
160 let _span = profile::cpu_span();
161 let analysis = host.analysis();
162 let config = CompletionConfig {
163 enable_postfix_completions: true,
164 enable_imports_on_the_fly: true,
165 add_call_parenthesis: true,
166 add_call_argument_snippets: true,
167 snippet_cap: SnippetCap::new(true),
168 insert_use: InsertUseConfig {
169 merge: Some(MergeBehavior::Full),
170 prefix_kind: hir::PrefixKind::ByCrate,
171 group: true,
172 },
173 };
174 let position =
175 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
176 analysis.completions(&config, position).unwrap();
177 }
178}
179
180fn patch(what: &mut String, from: &str, to: &str) -> usize {
181 let idx = what.find(from).unwrap();
182 *what = what.replacen(from, to, 1);
183 idx
184}
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index d9a5030a0..da7e24bec 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -40,7 +40,7 @@ pub mod lsp_ext;
40pub mod config; 40pub mod config;
41 41
42#[cfg(test)] 42#[cfg(test)]
43mod benchmarks; 43mod integrated_benchmarks;
44 44
45use serde::de::DeserializeOwned; 45use serde::de::DeserializeOwned;
46use std::fmt; 46use std::fmt;