aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock75
-rw-r--r--crates/ra_assists/src/handlers/extract_variable.rs103
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs90
-rw-r--r--crates/ra_hir_def/src/item_scope.rs29
-rw-r--r--crates/ra_hir_def/src/nameres.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs72
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs130
-rw-r--r--crates/ra_hir_def/src/visibility.rs41
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs22
-rw-r--r--crates/ra_prof/Cargo.toml10
-rw-r--r--crates/ra_prof/src/lib.rs10
-rw-r--r--crates/ra_prof/src/memory_usage.rs21
-rw-r--r--crates/rust-analyzer/Cargo.toml5
-rw-r--r--crates/rust-analyzer/src/bin/args.rs4
-rw-r--r--crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--docs/dev/README.md8
-rw-r--r--xtask/src/dist.rs2
-rw-r--r--xtask/src/install.rs2
-rw-r--r--xtask/src/main.rs12
19 files changed, 428 insertions, 214 deletions
diff --git a/Cargo.lock b/Cargo.lock
index cf4de8bbe..280d97432 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -216,12 +216,12 @@ dependencies = [
216 216
217[[package]] 217[[package]]
218name = "crossbeam-channel" 218name = "crossbeam-channel"
219version = "0.4.2" 219version = "0.4.3"
220source = "registry+https://github.com/rust-lang/crates.io-index" 220source = "registry+https://github.com/rust-lang/crates.io-index"
221checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" 221checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
222dependencies = [ 222dependencies = [
223 "cfg-if",
223 "crossbeam-utils", 224 "crossbeam-utils",
224 "maybe-uninit",
225] 225]
226 226
227[[package]] 227[[package]]
@@ -360,12 +360,6 @@ dependencies = [
360] 360]
361 361
362[[package]] 362[[package]]
363name = "fs_extra"
364version = "1.1.0"
365source = "registry+https://github.com/rust-lang/crates.io-index"
366checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
367
368[[package]]
369name = "fsevent" 363name = "fsevent"
370version = "2.0.2" 364version = "2.0.2"
371source = "registry+https://github.com/rust-lang/crates.io-index" 365source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -542,38 +536,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
542checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 536checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
543 537
544[[package]] 538[[package]]
545name = "jemalloc-ctl"
546version = "0.3.3"
547source = "registry+https://github.com/rust-lang/crates.io-index"
548checksum = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7"
549dependencies = [
550 "jemalloc-sys",
551 "libc",
552 "paste",
553]
554
555[[package]]
556name = "jemalloc-sys"
557version = "0.3.2"
558source = "registry+https://github.com/rust-lang/crates.io-index"
559checksum = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
560dependencies = [
561 "cc",
562 "fs_extra",
563 "libc",
564]
565
566[[package]]
567name = "jemallocator"
568version = "0.3.2"
569source = "registry+https://github.com/rust-lang/crates.io-index"
570checksum = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
571dependencies = [
572 "jemalloc-sys",
573 "libc",
574]
575
576[[package]]
577name = "jod-thread" 539name = "jod-thread"
578version = "0.1.2" 540version = "0.1.2"
579source = "registry+https://github.com/rust-lang/crates.io-index" 541source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -875,25 +837,6 @@ dependencies = [
875] 837]
876 838
877[[package]] 839[[package]]
878name = "paste"
879version = "0.1.18"
880source = "registry+https://github.com/rust-lang/crates.io-index"
881checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
882dependencies = [
883 "paste-impl",
884 "proc-macro-hack",
885]
886
887[[package]]
888name = "paste-impl"
889version = "0.1.18"
890source = "registry+https://github.com/rust-lang/crates.io-index"
891checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
892dependencies = [
893 "proc-macro-hack",
894]
895
896[[package]]
897name = "paths" 840name = "paths"
898version = "0.1.0" 841version = "0.1.0"
899 842
@@ -932,12 +875,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
932checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" 875checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
933 876
934[[package]] 877[[package]]
935name = "proc-macro-hack"
936version = "0.5.16"
937source = "registry+https://github.com/rust-lang/crates.io-index"
938checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
939
940[[package]]
941name = "proc-macro2" 878name = "proc-macro2"
942version = "1.0.19" 879version = "1.0.19"
943source = "registry+https://github.com/rust-lang/crates.io-index" 880source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1198,9 +1135,8 @@ name = "ra_prof"
1198version = "0.1.0" 1135version = "0.1.0"
1199dependencies = [ 1136dependencies = [
1200 "backtrace", 1137 "backtrace",
1201 "jemalloc-ctl", 1138 "cfg-if",
1202 "jemallocator", 1139 "libc",
1203 "mimalloc",
1204 "once_cell", 1140 "once_cell",
1205 "ra_arena", 1141 "ra_arena",
1206] 1142]
@@ -1425,6 +1361,7 @@ dependencies = [
1425 "log", 1361 "log",
1426 "lsp-server", 1362 "lsp-server",
1427 "lsp-types", 1363 "lsp-types",
1364 "mimalloc",
1428 "parking_lot", 1365 "parking_lot",
1429 "pico-args", 1366 "pico-args",
1430 "ra_cfg", 1367 "ra_cfg",
diff --git a/crates/ra_assists/src/handlers/extract_variable.rs b/crates/ra_assists/src/handlers/extract_variable.rs
index 481baf1a4..098adf078 100644
--- a/crates/ra_assists/src/handlers/extract_variable.rs
+++ b/crates/ra_assists/src/handlers/extract_variable.rs
@@ -2,7 +2,6 @@ use ra_syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 SyntaxKind::{ 3 SyntaxKind::{
4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, 4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
5 WHITESPACE,
6 }, 5 },
7 SyntaxNode, 6 SyntaxNode,
8}; 7};
@@ -36,22 +35,20 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
36 mark::hit!(extract_var_in_comment_is_not_applicable); 35 mark::hit!(extract_var_in_comment_is_not_applicable);
37 return None; 36 return None;
38 } 37 }
39 let expr = node.ancestors().find_map(valid_target_expr)?; 38 let to_extract = node.ancestors().find_map(valid_target_expr)?;
40 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr.clone())?; 39 let anchor = Anchor::from(&to_extract)?;
41 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?.clone(); 40 let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone();
42 if indent.kind() != WHITESPACE { 41 let target = to_extract.syntax().text_range();
43 return None;
44 }
45 let target = expr.syntax().text_range();
46 acc.add( 42 acc.add(
47 AssistId("extract_variable", AssistKind::RefactorExtract), 43 AssistId("extract_variable", AssistKind::RefactorExtract),
48 "Extract into variable", 44 "Extract into variable",
49 target, 45 target,
50 move |edit| { 46 move |edit| {
51 let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) { 47 let field_shorthand =
52 Some(field) => field.name_ref(), 48 match to_extract.syntax().parent().and_then(ast::RecordField::cast) {
53 None => None, 49 Some(field) => field.name_ref(),
54 }; 50 None => None,
51 };
55 52
56 let mut buf = String::new(); 53 let mut buf = String::new();
57 54
@@ -60,26 +57,20 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
60 None => "var_name".to_string(), 57 None => "var_name".to_string(),
61 }; 58 };
62 let expr_range = match &field_shorthand { 59 let expr_range = match &field_shorthand {
63 Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()), 60 Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()),
64 None => expr.syntax().text_range(), 61 None => to_extract.syntax().text_range(),
65 }; 62 };
66 63
67 if wrap_in_block { 64 if let Anchor::WrapInBlock(_) = anchor {
68 format_to!(buf, "{{ let {} = ", var_name); 65 format_to!(buf, "{{ let {} = ", var_name);
69 } else { 66 } else {
70 format_to!(buf, "let {} = ", var_name); 67 format_to!(buf, "let {} = ", var_name);
71 }; 68 };
72 format_to!(buf, "{}", expr.syntax()); 69 format_to!(buf, "{}", to_extract.syntax());
73 70
74 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); 71 if let Anchor::Replace(stmt) = anchor {
75 let is_full_stmt = if let Some(expr_stmt) = &full_stmt {
76 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone())
77 } else {
78 false
79 };
80 if is_full_stmt {
81 mark::hit!(test_extract_var_expr_stmt); 72 mark::hit!(test_extract_var_expr_stmt);
82 if full_stmt.unwrap().semicolon_token().is_none() { 73 if stmt.semicolon_token().is_none() {
83 buf.push_str(";"); 74 buf.push_str(";");
84 } 75 }
85 match ctx.config.snippet_cap { 76 match ctx.config.snippet_cap {
@@ -107,7 +98,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
107 } 98 }
108 99
109 edit.replace(expr_range, var_name.clone()); 100 edit.replace(expr_range, var_name.clone());
110 let offset = anchor_stmt.text_range().start(); 101 let offset = anchor.syntax().text_range().start();
111 match ctx.config.snippet_cap { 102 match ctx.config.snippet_cap {
112 Some(cap) => { 103 Some(cap) => {
113 let snip = 104 let snip =
@@ -117,8 +108,8 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
117 None => edit.insert(offset, buf), 108 None => edit.insert(offset, buf),
118 } 109 }
119 110
120 if wrap_in_block { 111 if let Anchor::WrapInBlock(_) = anchor {
121 edit.insert(anchor_stmt.text_range().end(), " }"); 112 edit.insert(anchor.syntax().text_range().end(), " }");
122 } 113 }
123 }, 114 },
124 ) 115 )
@@ -138,32 +129,48 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
138 } 129 }
139} 130}
140 131
141/// Returns the syntax node which will follow the freshly extractd var 132enum Anchor {
142/// and a boolean indicating whether we have to wrap it within a { } block 133 Before(SyntaxNode),
143/// to produce correct code. 134 Replace(ast::ExprStmt),
144/// It can be a statement, the last in a block expression or a wanna be block 135 WrapInBlock(SyntaxNode),
145/// expression like a lambda or match arm. 136}
146fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { 137
147 expr.syntax().ancestors().find_map(|node| { 138impl Anchor {
148 if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { 139 fn from(to_extract: &ast::Expr) -> Option<Anchor> {
149 if expr.syntax() == &node { 140 to_extract.syntax().ancestors().find_map(|node| {
150 mark::hit!(test_extract_var_last_expr); 141 if let Some(expr) =
151 return Some((node, false)); 142 node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr())
143 {
144 if expr.syntax() == &node {
145 mark::hit!(test_extract_var_last_expr);
146 return Some(Anchor::Before(node));
147 }
152 } 148 }
153 }
154 149
155 if let Some(parent) = node.parent() { 150 if let Some(parent) = node.parent() {
156 if parent.kind() == MATCH_ARM || parent.kind() == LAMBDA_EXPR { 151 if parent.kind() == MATCH_ARM || parent.kind() == LAMBDA_EXPR {
157 return Some((node, true)); 152 return Some(Anchor::WrapInBlock(node));
153 }
158 } 154 }
159 }
160 155
161 if ast::Stmt::cast(node.clone()).is_some() { 156 if let Some(stmt) = ast::Stmt::cast(node.clone()) {
162 return Some((node, false)); 157 if let ast::Stmt::ExprStmt(stmt) = stmt {
163 } 158 if stmt.expr().as_ref() == Some(to_extract) {
159 return Some(Anchor::Replace(stmt));
160 }
161 }
162 return Some(Anchor::Before(node));
163 }
164 None
165 })
166 }
164 167
165 None 168 fn syntax(&self) -> &SyntaxNode {
166 }) 169 match self {
170 Anchor::Before(it) | Anchor::WrapInBlock(it) => it,
171 Anchor::Replace(stmt) => stmt.syntax(),
172 }
173 }
167} 174}
168 175
169#[cfg(test)] 176#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index e212557c8..1d3ed3c6a 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -3,6 +3,7 @@ use ra_db::FileId;
3use ra_syntax::{ast, AstNode, TextRange, TextSize}; 3use ra_syntax::{ast, AstNode, TextRange, TextSize};
4 4
5use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; 5use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
6use ast::VisibilityOwner;
6 7
7// FIXME: this really should be a fix for diagnostic, rather than an assist. 8// FIXME: this really should be a fix for diagnostic, rather than an assist.
8 9
@@ -48,7 +49,8 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
48 return None; 49 return None;
49 }; 50 };
50 51
51 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db(), def)?; 52 let (offset, current_visibility, target, target_file, target_name) =
53 target_data_for_def(ctx.db(), def)?;
52 54
53 let missing_visibility = 55 let missing_visibility =
54 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 56 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
@@ -61,8 +63,20 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
61 acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { 63 acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
62 builder.edit_file(target_file); 64 builder.edit_file(target_file);
63 match ctx.config.snippet_cap { 65 match ctx.config.snippet_cap {
64 Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), 66 Some(cap) => match current_visibility {
65 None => builder.insert(offset, format!("{} ", missing_visibility)), 67 Some(current_visibility) => builder.replace_snippet(
68 cap,
69 current_visibility.syntax().text_range(),
70 format!("$0{}", missing_visibility),
71 ),
72 None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
73 },
74 None => match current_visibility {
75 Some(current_visibility) => {
76 builder.replace(current_visibility.syntax().text_range(), missing_visibility)
77 }
78 None => builder.insert(offset, format!("{} ", missing_visibility)),
79 },
66 } 80 }
67 }) 81 })
68} 82}
@@ -82,14 +96,14 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
82 let target_module = parent.module(ctx.db()); 96 let target_module = parent.module(ctx.db());
83 97
84 let in_file_source = record_field_def.source(ctx.db()); 98 let in_file_source = record_field_def.source(ctx.db());
85 let (offset, target) = match in_file_source.value { 99 let (offset, current_visibility, target) = match in_file_source.value {
86 hir::FieldSource::Named(it) => { 100 hir::FieldSource::Named(it) => {
87 let s = it.syntax(); 101 let s = it.syntax();
88 (vis_offset(s), s.text_range()) 102 (vis_offset(s), it.visibility(), s.text_range())
89 } 103 }
90 hir::FieldSource::Pos(it) => { 104 hir::FieldSource::Pos(it) => {
91 let s = it.syntax(); 105 let s = it.syntax();
92 (vis_offset(s), s.text_range()) 106 (vis_offset(s), it.visibility(), s.text_range())
93 } 107 }
94 }; 108 };
95 109
@@ -104,8 +118,20 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
104 acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { 118 acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
105 builder.edit_file(target_file); 119 builder.edit_file(target_file);
106 match ctx.config.snippet_cap { 120 match ctx.config.snippet_cap {
107 Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), 121 Some(cap) => match current_visibility {
108 None => builder.insert(offset, format!("{} ", missing_visibility)), 122 Some(current_visibility) => builder.replace_snippet(
123 cap,
124 dbg!(current_visibility.syntax()).text_range(),
125 format!("$0{}", missing_visibility),
126 ),
127 None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
128 },
129 None => match current_visibility {
130 Some(current_visibility) => {
131 builder.replace(current_visibility.syntax().text_range(), missing_visibility)
132 }
133 None => builder.insert(offset, format!("{} ", missing_visibility)),
134 },
109 } 135 }
110 }) 136 })
111} 137}
@@ -113,24 +139,30 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
113fn target_data_for_def( 139fn target_data_for_def(
114 db: &dyn HirDatabase, 140 db: &dyn HirDatabase,
115 def: hir::ModuleDef, 141 def: hir::ModuleDef,
116) -> Option<(TextSize, TextRange, FileId, Option<hir::Name>)> { 142) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId, Option<hir::Name>)> {
117 fn offset_target_and_file_id<S, Ast>( 143 fn offset_target_and_file_id<S, Ast>(
118 db: &dyn HirDatabase, 144 db: &dyn HirDatabase,
119 x: S, 145 x: S,
120 ) -> (TextSize, TextRange, FileId) 146 ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId)
121 where 147 where
122 S: HasSource<Ast = Ast>, 148 S: HasSource<Ast = Ast>,
123 Ast: AstNode, 149 Ast: AstNode + ast::VisibilityOwner,
124 { 150 {
125 let source = x.source(db); 151 let source = x.source(db);
126 let in_file_syntax = source.syntax(); 152 let in_file_syntax = source.syntax();
127 let file_id = in_file_syntax.file_id; 153 let file_id = in_file_syntax.file_id;
128 let syntax = in_file_syntax.value; 154 let syntax = in_file_syntax.value;
129 (vis_offset(syntax), syntax.text_range(), file_id.original_file(db.upcast())) 155 let current_visibility = source.value.visibility();
156 (
157 vis_offset(syntax),
158 current_visibility,
159 syntax.text_range(),
160 file_id.original_file(db.upcast()),
161 )
130 } 162 }
131 163
132 let target_name; 164 let target_name;
133 let (offset, target, target_file) = match def { 165 let (offset, current_visibility, target, target_file) = match def {
134 hir::ModuleDef::Function(f) => { 166 hir::ModuleDef::Function(f) => {
135 target_name = Some(f.name(db)); 167 target_name = Some(f.name(db));
136 offset_target_and_file_id(db, f) 168 offset_target_and_file_id(db, f)
@@ -164,13 +196,13 @@ fn target_data_for_def(
164 let in_file_source = m.declaration_source(db)?; 196 let in_file_source = m.declaration_source(db)?;
165 let file_id = in_file_source.file_id.original_file(db.upcast()); 197 let file_id = in_file_source.file_id.original_file(db.upcast());
166 let syntax = in_file_source.value.syntax(); 198 let syntax = in_file_source.value.syntax();
167 (vis_offset(syntax), syntax.text_range(), file_id) 199 (vis_offset(syntax), in_file_source.value.visibility(), syntax.text_range(), file_id)
168 } 200 }
169 // Enum variants can't be private, we can't modify builtin types 201 // Enum variants can't be private, we can't modify builtin types
170 hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None, 202 hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None,
171 }; 203 };
172 204
173 Some((offset, target, target_file, target_name)) 205 Some((offset, current_visibility, target, target_file, target_name))
174} 206}
175 207
176#[cfg(test)] 208#[cfg(test)]
@@ -523,6 +555,34 @@ struct Bar;
523 } 555 }
524 556
525 #[test] 557 #[test]
558 fn replaces_pub_crate_with_pub() {
559 check_assist(
560 fix_visibility,
561 r"
562//- /main.rs crate:a deps:foo
563foo::Bar<|>
564//- /lib.rs crate:foo
565pub(crate) struct Bar;
566",
567 r"$0pub struct Bar;
568",
569 );
570 check_assist(
571 fix_visibility,
572 r"
573//- /main.rs crate:a deps:foo
574fn main() {
575 foo::Foo { <|>bar: () };
576}
577//- /lib.rs crate:foo
578pub struct Foo { pub(crate) bar: () }
579",
580 r"pub struct Foo { $0pub bar: () }
581",
582 );
583 }
584
585 #[test]
526 #[ignore] 586 #[ignore]
527 // FIXME handle reexports properly 587 // FIXME handle reexports properly
528 fn fix_visibility_of_reexport() { 588 fn fix_visibility_of_reexport() {
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index beeb98559..8fee4b15e 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -36,6 +36,8 @@ pub struct ItemScope {
36 36
37 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
38 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
39 /// Traits imported via `use Trait as _;`.
40 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
39 /// Macros visible in current module in legacy textual scope 41 /// Macros visible in current module in legacy textual scope
40 /// 42 ///
41 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. 43 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -126,10 +128,13 @@ impl ItemScope {
126 } 128 }
127 129
128 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 130 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
129 self.types.values().filter_map(|(def, _)| match def { 131 self.types
130 ModuleDefId::TraitId(t) => Some(*t), 132 .values()
131 _ => None, 133 .filter_map(|(def, _)| match def {
132 }) 134 ModuleDefId::TraitId(t) => Some(*t),
135 _ => None,
136 })
137 .chain(self.unnamed_trait_imports.keys().copied())
133 } 138 }
134 139
135 pub(crate) fn define_def(&mut self, def: ModuleDefId) { 140 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
@@ -148,6 +153,14 @@ impl ItemScope {
148 self.legacy_macros.insert(name, mac); 153 self.legacy_macros.insert(name, mac);
149 } 154 }
150 155
156 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
157 self.unnamed_trait_imports.get(&tr).copied()
158 }
159
160 pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
161 self.unnamed_trait_imports.insert(tr, vis);
162 }
163
151 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 164 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
152 let mut changed = false; 165 let mut changed = false;
153 166
@@ -241,8 +254,12 @@ impl ItemScope {
241 changed 254 changed
242 } 255 }
243 256
244 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 257 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
245 self.entries().map(|(name, res)| (name.clone(), res)) 258 self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
259 self.unnamed_trait_imports
260 .iter()
261 .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
262 )
246 } 263 }
247 264
248 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 265 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 5a9de3d3e..3d9b55a73 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -239,7 +239,7 @@ impl CrateDefMap {
239 entries.sort_by_key(|(name, _)| name.clone()); 239 entries.sort_by_key(|(name, _)| name.clone());
240 240
241 for (name, def) in entries { 241 for (name, def) in entries {
242 format_to!(buf, "{}:", name); 242 format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string()));
243 243
244 if def.types.is_some() { 244 if def.types.is_some() {
245 buf.push_str(" t"); 245 buf.push_str(" t");
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index d85a86c0a..a030cab47 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -310,7 +310,7 @@ impl DefCollector<'_> {
310 if export { 310 if export {
311 self.update( 311 self.update(
312 self.def_map.root, 312 self.def_map.root,
313 &[(name, PerNs::macros(macro_, Visibility::Public))], 313 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
314 Visibility::Public, 314 Visibility::Public,
315 ImportType::Named, 315 ImportType::Named,
316 ); 316 );
@@ -336,7 +336,7 @@ impl DefCollector<'_> {
336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { 336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
337 self.update( 337 self.update(
338 self.def_map.root, 338 self.def_map.root,
339 &[(name, PerNs::macros(macro_, Visibility::Public))], 339 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
340 Visibility::Public, 340 Visibility::Public,
341 ImportType::Named, 341 ImportType::Named,
342 ); 342 );
@@ -534,7 +534,7 @@ impl DefCollector<'_> {
534 let name = variant_data.name.clone(); 534 let name = variant_data.name.clone();
535 let variant = EnumVariantId { parent: e, local_id }; 535 let variant = EnumVariantId { parent: e, local_id };
536 let res = PerNs::both(variant.into(), variant.into(), vis); 536 let res = PerNs::both(variant.into(), variant.into(), vis);
537 (name, res) 537 (Some(name), res)
538 }) 538 })
539 .collect::<Vec<_>>(); 539 .collect::<Vec<_>>();
540 self.update(module_id, &resolutions, vis, ImportType::Glob); 540 self.update(module_id, &resolutions, vis, ImportType::Glob);
@@ -550,15 +550,15 @@ impl DefCollector<'_> {
550 match import.path.segments.last() { 550 match import.path.segments.last() {
551 Some(last_segment) => { 551 Some(last_segment) => {
552 let name = match &import.alias { 552 let name = match &import.alias {
553 Some(ImportAlias::Alias(name)) => name.clone(), 553 Some(ImportAlias::Alias(name)) => Some(name.clone()),
554 Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 554 Some(ImportAlias::Underscore) => None,
555 None => last_segment.clone(), 555 None => Some(last_segment.clone()),
556 }; 556 };
557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
558 558
559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
560 if import.is_extern_crate && module_id == self.def_map.root { 560 if import.is_extern_crate && module_id == self.def_map.root {
561 if let Some(def) = def.take_types() { 561 if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
562 self.def_map.extern_prelude.insert(name.clone(), def); 562 self.def_map.extern_prelude.insert(name.clone(), def);
563 } 563 }
564 } 564 }
@@ -573,7 +573,7 @@ impl DefCollector<'_> {
573 fn update( 573 fn update(
574 &mut self, 574 &mut self,
575 module_id: LocalModuleId, 575 module_id: LocalModuleId,
576 resolutions: &[(Name, PerNs)], 576 resolutions: &[(Option<Name>, PerNs)],
577 vis: Visibility, 577 vis: Visibility,
578 import_type: ImportType, 578 import_type: ImportType,
579 ) { 579 ) {
@@ -584,7 +584,7 @@ impl DefCollector<'_> {
584 fn update_recursive( 584 fn update_recursive(
585 &mut self, 585 &mut self,
586 module_id: LocalModuleId, 586 module_id: LocalModuleId,
587 resolutions: &[(Name, PerNs)], 587 resolutions: &[(Option<Name>, PerNs)],
588 // All resolutions are imported with this visibility; the visibilies in 588 // All resolutions are imported with this visibility; the visibilies in
589 // the `PerNs` values are ignored and overwritten 589 // the `PerNs` values are ignored and overwritten
590 vis: Visibility, 590 vis: Visibility,
@@ -595,15 +595,51 @@ impl DefCollector<'_> {
595 // prevent stack overflows (but this shouldn't be possible) 595 // prevent stack overflows (but this shouldn't be possible)
596 panic!("infinite recursion in glob imports!"); 596 panic!("infinite recursion in glob imports!");
597 } 597 }
598 let scope = &mut self.def_map.modules[module_id].scope;
599 let mut changed = false; 598 let mut changed = false;
599
600 for (name, res) in resolutions { 600 for (name, res) in resolutions {
601 changed |= scope.push_res_with_import( 601 match name {
602 &mut self.from_glob_import, 602 Some(name) => {
603 (module_id, name.clone()), 603 let scope = &mut self.def_map.modules[module_id].scope;
604 res.with_visibility(vis), 604 changed |= scope.push_res_with_import(
605 import_type, 605 &mut self.from_glob_import,
606 ); 606 (module_id, name.clone()),
607 res.with_visibility(vis),
608 import_type,
609 );
610 }
611 None => {
612 let tr = match res.take_types() {
613 Some(ModuleDefId::TraitId(tr)) => tr,
614 Some(other) => {
615 log::debug!("non-trait `_` import of {:?}", other);
616 continue;
617 }
618 None => continue,
619 };
620 let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
621 let should_update = match old_vis {
622 None => true,
623 Some(old_vis) => {
624 let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
625 panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
626 });
627
628 if max_vis == old_vis {
629 false
630 } else {
631 mark::hit!(upgrade_underscore_visibility);
632 true
633 }
634 }
635 };
636
637 if should_update {
638 changed = true;
639 self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
640 }
641 }
642 }
607 } 643 }
608 644
609 if !changed { 645 if !changed {
@@ -950,7 +986,7 @@ impl ModCollector<'_, '_> {
950 .unwrap_or(Visibility::Public); 986 .unwrap_or(Visibility::Public);
951 self.def_collector.update( 987 self.def_collector.update(
952 self.module_id, 988 self.module_id,
953 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], 989 &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
954 vis, 990 vis,
955 ImportType::Named, 991 ImportType::Named,
956 ) 992 )
@@ -1057,7 +1093,7 @@ impl ModCollector<'_, '_> {
1057 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1093 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1058 self.def_collector.update( 1094 self.def_collector.update(
1059 self.module_id, 1095 self.module_id,
1060 &[(name, PerNs::from_def(def, vis, false))], 1096 &[(Some(name), PerNs::from_def(def, vis, false))],
1061 vis, 1097 vis,
1062 ImportType::Named, 1098 ImportType::Named,
1063 ); 1099 );
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 205d3528b..839b1de57 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -558,3 +558,133 @@ mod b {
558 "#]], 558 "#]],
559 ); 559 );
560} 560}
561
562#[test]
563fn underscore_import() {
564 check(
565 r#"
566//- /main.rs
567use tr::Tr as _;
568use tr::Tr2 as _;
569
570mod tr {
571 pub trait Tr {}
572 pub trait Tr2 {}
573}
574 "#,
575 expect![[r#"
576 crate
577 _: t
578 _: t
579 tr: t
580
581 crate::tr
582 Tr: t
583 Tr2: t
584 "#]],
585 );
586}
587
588#[test]
589fn underscore_reexport() {
590 check(
591 r#"
592//- /main.rs
593mod tr {
594 pub trait PubTr {}
595 pub trait PrivTr {}
596}
597mod reex {
598 use crate::tr::PrivTr as _;
599 pub use crate::tr::PubTr as _;
600}
601use crate::reex::*;
602 "#,
603 expect![[r#"
604 crate
605 _: t
606 reex: t
607 tr: t
608
609 crate::tr
610 PrivTr: t
611 PubTr: t
612
613 crate::reex
614 _: t
615 _: t
616 "#]],
617 );
618}
619
620#[test]
621fn underscore_pub_crate_reexport() {
622 mark::check!(upgrade_underscore_visibility);
623 check(
624 r#"
625//- /main.rs crate:main deps:lib
626use lib::*;
627
628//- /lib.rs crate:lib
629use tr::Tr as _;
630pub use tr::Tr as _;
631
632mod tr {
633 pub trait Tr {}
634}
635 "#,
636 expect![[r#"
637 crate
638 _: t
639 "#]],
640 );
641}
642
643#[test]
644fn underscore_nontrait() {
645 check(
646 r#"
647//- /main.rs
648mod m {
649 pub struct Struct;
650 pub enum Enum {}
651 pub const CONST: () = ();
652}
653use crate::m::{Struct as _, Enum as _, CONST as _};
654 "#,
655 expect![[r#"
656 crate
657 m: t
658
659 crate::m
660 CONST: v
661 Enum: t
662 Struct: t v
663 "#]],
664 );
665}
666
667#[test]
668fn underscore_name_conflict() {
669 check(
670 r#"
671//- /main.rs
672struct Tr;
673
674use tr::Tr as _;
675
676mod tr {
677 pub trait Tr {}
678}
679 "#,
680 expect![[r#"
681 crate
682 _: t
683 Tr: t v
684 tr: t
685
686 crate::tr
687 Tr: t
688 "#]],
689 );
690}
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs
index 8136cb50c..1abffb4c3 100644
--- a/crates/ra_hir_def/src/visibility.rs
+++ b/crates/ra_hir_def/src/visibility.rs
@@ -5,6 +5,7 @@ use ra_syntax::ast;
5 5
6use crate::{ 6use crate::{
7 db::DefDatabase, 7 db::DefDatabase,
8 nameres::CrateDefMap,
8 path::{ModPath, PathKind}, 9 path::{ModPath, PathKind},
9 ModuleId, 10 ModuleId,
10}; 11};
@@ -115,7 +116,7 @@ impl Visibility {
115 116
116 pub(crate) fn is_visible_from_def_map( 117 pub(crate) fn is_visible_from_def_map(
117 self, 118 self,
118 def_map: &crate::nameres::CrateDefMap, 119 def_map: &CrateDefMap,
119 from_module: crate::LocalModuleId, 120 from_module: crate::LocalModuleId,
120 ) -> bool { 121 ) -> bool {
121 let to_module = match self { 122 let to_module = match self {
@@ -129,4 +130,42 @@ impl Visibility {
129 }); 130 });
130 ancestors.any(|m| m == to_module.local_id) 131 ancestors.any(|m| m == to_module.local_id)
131 } 132 }
133
134 /// Returns the most permissive visibility of `self` and `other`.
135 ///
136 /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
137 /// visible in unrelated modules).
138 pub(crate) fn max(self, other: Visibility, def_map: &CrateDefMap) -> Option<Visibility> {
139 match (self, other) {
140 (Visibility::Module(_), Visibility::Public)
141 | (Visibility::Public, Visibility::Module(_))
142 | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
143 (Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
144 if mod_a.krate != mod_b.krate {
145 return None;
146 }
147
148 let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| {
149 let parent_id = def_map[*m].parent?;
150 Some(parent_id)
151 });
152 let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| {
153 let parent_id = def_map[*m].parent?;
154 Some(parent_id)
155 });
156
157 if a_ancestors.any(|m| m == mod_b.local_id) {
158 // B is above A
159 return Some(Visibility::Module(mod_b));
160 }
161
162 if b_ancestors.any(|m| m == mod_a.local_id) {
163 // A is above B
164 return Some(Visibility::Module(mod_a));
165 }
166
167 None
168 }
169 }
170 }
132} 171}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index d3c4d3f2a..526e61caf 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -3089,3 +3089,25 @@ fn test() {
3089 "#, 3089 "#,
3090 ); 3090 );
3091} 3091}
3092
3093#[test]
3094fn underscore_import() {
3095 check_types(
3096 r#"
3097mod tr {
3098 pub trait Tr {
3099 fn method(&self) -> u8 { 0 }
3100 }
3101}
3102
3103struct Tr;
3104impl crate::tr::Tr for Tr {}
3105
3106use crate::tr::Tr as _;
3107fn test() {
3108 Tr.method();
3109 //^^^^^^^^^^^ u8
3110}
3111 "#,
3112 );
3113}
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml
index b3d52985a..6c214501e 100644
--- a/crates/ra_prof/Cargo.toml
+++ b/crates/ra_prof/Cargo.toml
@@ -13,18 +13,12 @@ doctest = false
13ra_arena = { path = "../ra_arena" } 13ra_arena = { path = "../ra_arena" }
14once_cell = "1.3.1" 14once_cell = "1.3.1"
15backtrace = { version = "0.3.44", optional = true } 15backtrace = { version = "0.3.44", optional = true }
16mimalloc = { version = "0.1.19", default-features = false, optional = true } 16cfg-if = "0.1.10"
17 17libc = "0.2.73"
18[target.'cfg(not(target_env = "msvc"))'.dependencies]
19jemallocator = { version = "0.3.2", optional = true }
20jemalloc-ctl = { version = "0.3.3", optional = true }
21 18
22[features] 19[features]
23jemalloc = [ "jemallocator", "jemalloc-ctl" ]
24cpu_profiler = [] 20cpu_profiler = []
25 21
26# Uncomment to enable for the whole crate graph 22# Uncomment to enable for the whole crate graph
27# default = [ "backtrace" ] 23# default = [ "backtrace" ]
28# default = [ "jemalloc" ]
29# default = [ "mimalloc" ]
30# default = [ "cpu_profiler" ] 24# default = [ "cpu_profiler" ]
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index b54531b4e..ba5609703 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -13,16 +13,6 @@ pub use crate::{
13 memory_usage::{Bytes, MemoryUsage}, 13 memory_usage::{Bytes, MemoryUsage},
14}; 14};
15 15
16// We use jemalloc mainly to get heap usage statistics, actual performance
17// difference is not measures.
18#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
19#[global_allocator]
20static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
21
22#[cfg(all(feature = "mimalloc"))]
23#[global_allocator]
24static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
25
26/// Prints backtrace to stderr, useful for debugging. 16/// Prints backtrace to stderr, useful for debugging.
27#[cfg(feature = "backtrace")] 17#[cfg(feature = "backtrace")]
28pub fn print_backtrace() { 18pub fn print_backtrace() {
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs
index 9768f656c..ee79ec3ee 100644
--- a/crates/ra_prof/src/memory_usage.rs
+++ b/crates/ra_prof/src/memory_usage.rs
@@ -1,26 +1,25 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2
3use std::fmt; 2use std::fmt;
4 3
4use cfg_if::cfg_if;
5
5pub struct MemoryUsage { 6pub struct MemoryUsage {
6 pub allocated: Bytes, 7 pub allocated: Bytes,
7 pub resident: Bytes, 8 pub resident: Bytes,
8} 9}
9 10
10impl MemoryUsage { 11impl MemoryUsage {
11 #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
12 pub fn current() -> MemoryUsage { 12 pub fn current() -> MemoryUsage {
13 jemalloc_ctl::epoch::advance().unwrap(); 13 cfg_if! {
14 MemoryUsage { 14 if #[cfg(target_os = "linux")] {
15 allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap()), 15 // Note: This is incredibly slow.
16 resident: Bytes(jemalloc_ctl::stats::resident::read().unwrap()), 16 let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as usize;
17 MemoryUsage { allocated: Bytes(alloc), resident: Bytes(0) }
18 } else {
19 MemoryUsage { allocated: Bytes(0), resident: Bytes(0) }
20 }
17 } 21 }
18 } 22 }
19
20 #[cfg(any(not(feature = "jemalloc"), target_env = "msvc"))]
21 pub fn current() -> MemoryUsage {
22 MemoryUsage { allocated: Bytes(0), resident: Bytes(0) }
23 }
24} 23}
25 24
26impl fmt::Display for MemoryUsage { 25impl fmt::Display for MemoryUsage {
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 5eb2d0bb7..023c104d1 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -29,6 +29,7 @@ serde = { version = "1.0.106", features = ["derive"] }
29serde_json = "1.0.48" 29serde_json = "1.0.48"
30threadpool = "1.7.1" 30threadpool = "1.7.1"
31rayon = "1.3.1" 31rayon = "1.3.1"
32mimalloc = { version = "0.1.19", default-features = false, optional = true }
32 33
33stdx = { path = "../stdx" } 34stdx = { path = "../stdx" }
34 35
@@ -62,7 +63,3 @@ expect = { path = "../expect" }
62test_utils = { path = "../test_utils" } 63test_utils = { path = "../test_utils" }
63mbe = { path = "../ra_mbe", package = "ra_mbe" } 64mbe = { path = "../ra_mbe", package = "ra_mbe" }
64tt = { path = "../ra_tt", package = "ra_tt" } 65tt = { path = "../ra_tt", package = "ra_tt" }
65
66[features]
67jemalloc = [ "ra_prof/jemalloc" ]
68mimalloc = [ "ra_prof/mimalloc" ]
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 3210416ee..741a2a951 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -166,7 +166,7 @@ USAGE:
166FLAGS: 166FLAGS:
167 -o, --only Only analyze items matching this path 167 -o, --only Only analyze items matching this path
168 -h, --help Prints help information 168 -h, --help Prints help information
169 --memory-usage Collect memory usage statistics (requires `--features jemalloc`) 169 --memory-usage Collect memory usage statistics
170 --randomize Randomize order in which crates, modules, and items are processed 170 --randomize Randomize order in which crates, modules, and items are processed
171 --parallel Run type inference in parallel 171 --parallel Run type inference in parallel
172 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 172 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
@@ -221,7 +221,7 @@ USAGE:
221 221
222FLAGS: 222FLAGS:
223 -h, --help Prints help information 223 -h, --help Prints help information
224 --memory-usage Collect memory usage statistics (requires `--features jemalloc`) 224 --memory-usage Collect memory usage statistics
225 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 225 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
226 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding 226 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
227 -v, --verbose 227 -v, --verbose
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 408892eab..a473c9165 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -16,6 +16,10 @@ use vfs::AbsPathBuf;
16 16
17use crate::args::HelpPrinted; 17use crate::args::HelpPrinted;
18 18
19#[cfg(all(feature = "mimalloc"))]
20#[global_allocator]
21static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
22
19fn main() -> Result<()> { 23fn main() -> Result<()> {
20 setup_logging()?; 24 setup_logging()?;
21 let args = match args::Args::parse()? { 25 let args = match args::Args::parse()? {
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 3af01cd6b..2bb2f75bd 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -397,13 +397,7 @@ To log all communication between the server and the client, there are two choice
397 397
398There are also two VS Code commands which might be of interest: 398There are also two VS Code commands which might be of interest:
399 399
400* `Rust Analyzer: Status` shows some memory-usage statistics. To take full 400* `Rust Analyzer: Status` shows some memory-usage statistics.
401 advantage of it, you need to compile rust-analyzer with jemalloc support:
402 ```
403 $ cargo install --path crates/rust-analyzer --force --features jemalloc
404 ```
405
406 There's an alias for this: `cargo xtask install --server --jemalloc`.
407 401
408* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. 402* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection.
409 403
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index b8f68027c..c198c0907 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -57,8 +57,6 @@ fn dist_server() -> Result<()> {
57 env::set_var("CC", "clang"); 57 env::set_var("CC", "clang");
58 run!( 58 run!(
59 "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" 59 "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release"
60 // We'd want to add, but that requires setting the right linker somehow
61 // --features=jemalloc
62 )?; 60 )?;
63 } else { 61 } else {
64 run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; 62 run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?;
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index a0dc0c9c2..b25a6e301 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -24,7 +24,6 @@ pub struct ServerOpt {
24 24
25pub enum Malloc { 25pub enum Malloc {
26 System, 26 System,
27 Jemalloc,
28 Mimalloc, 27 Mimalloc,
29} 28}
30 29
@@ -138,7 +137,6 @@ fn install_server(opts: ServerOpt) -> Result<()> {
138 137
139 let malloc_feature = match opts.malloc { 138 let malloc_feature = match opts.malloc {
140 Malloc::System => "", 139 Malloc::System => "",
141 Malloc::Jemalloc => "--features jemalloc",
142 Malloc::Mimalloc => "--features mimalloc", 140 Malloc::Mimalloc => "--features mimalloc",
143 }; 141 };
144 let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", malloc_feature); 142 let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", malloc_feature);
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 399ff7204..53d3ce3e7 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -45,7 +45,6 @@ USAGE:
45FLAGS: 45FLAGS:
46 --client-code Install only VS Code plugin 46 --client-code Install only VS Code plugin
47 --server Install only the language server 47 --server Install only the language server
48 --jemalloc Use jemalloc for server
49 --mimalloc Use mimalloc for server 48 --mimalloc Use mimalloc for server
50 -h, --help Prints help information 49 -h, --help Prints help information
51 " 50 "
@@ -62,15 +61,8 @@ FLAGS:
62 return Ok(()); 61 return Ok(());
63 } 62 }
64 63
65 let malloc = match (args.contains("--jemalloc"), args.contains("--mimalloc")) { 64 let malloc =
66 (false, false) => Malloc::System, 65 if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };
67 (true, false) => Malloc::Jemalloc,
68 (false, true) => Malloc::Mimalloc,
69 (true, true) => {
70 eprintln!("error: Cannot use both `--jemalloc` and `--mimalloc`");
71 return Ok(());
72 }
73 };
74 66
75 args.finish()?; 67 args.finish()?;
76 68