aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/fill_match_arms.rs28
-rw-r--r--crates/completion/src/item.rs4
-rw-r--r--crates/hir_def/src/body.rs2
-rw-r--r--crates/hir_def/src/body/lower.rs2
-rw-r--r--crates/hir_expand/src/ast_id_map.rs4
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/ide/src/inlay_hints.rs20
-rw-r--r--crates/ide/src/references/rename.rs6
-rw-r--r--crates/ide_db/src/source_change.rs7
-rw-r--r--crates/profile/Cargo.toml2
-rw-r--r--crates/project_model/src/build_data.rs5
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/bin/args.rs49
-rw-r--r--crates/rust-analyzer/src/bin/logger.rs39
-rw-r--r--crates/rust-analyzer/src/bin/main.rs26
-rw-r--r--crates/stdx/Cargo.toml1
-rw-r--r--crates/stdx/src/lib.rs2
-rw-r--r--crates/stdx/src/macros.rs51
-rw-r--r--crates/syntax/Cargo.toml2
19 files changed, 158 insertions, 100 deletions
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs
index 7663d211d..4964ddc7d 100644
--- a/crates/assists/src/handlers/fill_match_arms.rs
+++ b/crates/assists/src/handlers/fill_match_arms.rs
@@ -272,6 +272,34 @@ mod tests {
272 } 272 }
273 273
274 #[test] 274 #[test]
275 fn partial_fill_option() {
276 check_assist(
277 fill_match_arms,
278 r#"
279enum Option<T> { Some(T), None }
280use Option::*;
281
282fn main() {
283 match None$0 {
284 None => {}
285 }
286}
287 "#,
288 r#"
289enum Option<T> { Some(T), None }
290use Option::*;
291
292fn main() {
293 match None {
294 None => {}
295 Some(${0:_}) => {}
296 }
297}
298 "#,
299 );
300 }
301
302 #[test]
275 fn partial_fill_or_pat() { 303 fn partial_fill_or_pat() {
276 check_assist( 304 check_assist(
277 fill_match_arms, 305 fill_match_arms,
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index eeb952ec3..8ec4ac65e 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -10,7 +10,7 @@ use ide_db::{
10 }, 10 },
11 SymbolKind, 11 SymbolKind,
12}; 12};
13use stdx::{assert_never, impl_from}; 13use stdx::{impl_from, never};
14use syntax::{algo, TextRange}; 14use syntax::{algo, TextRange};
15use text_edit::TextEdit; 15use text_edit::TextEdit;
16 16
@@ -404,7 +404,7 @@ impl Builder {
404 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { 404 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
405 self.detail = detail.map(Into::into); 405 self.detail = detail.map(Into::into);
406 if let Some(detail) = &self.detail { 406 if let Some(detail) = &self.detail {
407 if assert_never!(detail.contains('\n'), "multiline detail:\n{}", detail) { 407 if never!(detail.contains('\n'), "multiline detail:\n{}", detail) {
408 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string()); 408 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
409 } 409 }
410 } 410 }
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index d0c84ab0b..b9ecf22fa 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -17,6 +17,7 @@ use hir_expand::{
17 HirFileId, InFile, MacroDefId, 17 HirFileId, InFile, MacroDefId,
18}; 18};
19use la_arena::{Arena, ArenaMap}; 19use la_arena::{Arena, ArenaMap};
20use profile::Count;
20use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
21use syntax::{ast, AstNode, AstPtr}; 22use syntax::{ast, AstNode, AstPtr};
22use test_utils::mark; 23use test_utils::mark;
@@ -237,6 +238,7 @@ pub struct Body {
237 /// The `ExprId` of the actual body expression. 238 /// The `ExprId` of the actual body expression.
238 pub body_expr: ExprId, 239 pub body_expr: ExprId,
239 pub item_scope: ItemScope, 240 pub item_scope: ItemScope,
241 _c: Count<Self>,
240} 242}
241 243
242pub type ExprPtr = AstPtr<ast::Expr>; 244pub type ExprPtr = AstPtr<ast::Expr>;
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 4ce5e5b72..209965fca 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -10,6 +10,7 @@ use hir_expand::{
10 ExpandError, HirFileId, MacroDefId, MacroDefKind, 10 ExpandError, HirFileId, MacroDefId, MacroDefKind,
11}; 11};
12use la_arena::Arena; 12use la_arena::Arena;
13use profile::Count;
13use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
14use syntax::{ 15use syntax::{
15 ast::{ 16 ast::{
@@ -77,6 +78,7 @@ pub(super) fn lower(
77 params: Vec::new(), 78 params: Vec::new(),
78 body_expr: dummy_expr_id(), 79 body_expr: dummy_expr_id(),
79 item_scope: Default::default(), 80 item_scope: Default::default(),
81 _c: Count::new(),
80 }, 82 },
81 item_trees: { 83 item_trees: {
82 let mut map = FxHashMap::default(); 84 let mut map = FxHashMap::default();
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs
index 0991fffd8..16cf29907 100644
--- a/crates/hir_expand/src/ast_id_map.rs
+++ b/crates/hir_expand/src/ast_id_map.rs
@@ -13,6 +13,7 @@ use std::{
13}; 13};
14 14
15use la_arena::{Arena, Idx}; 15use la_arena::{Arena, Idx};
16use profile::Count;
16use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; 17use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
17 18
18/// `AstId` points to an AST node in a specific file. 19/// `AstId` points to an AST node in a specific file.
@@ -62,12 +63,13 @@ type ErasedFileAstId = Idx<SyntaxNodePtr>;
62#[derive(Debug, PartialEq, Eq, Default)] 63#[derive(Debug, PartialEq, Eq, Default)]
63pub struct AstIdMap { 64pub struct AstIdMap {
64 arena: Arena<SyntaxNodePtr>, 65 arena: Arena<SyntaxNodePtr>,
66 _c: Count<Self>,
65} 67}
66 68
67impl AstIdMap { 69impl AstIdMap {
68 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { 70 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
69 assert!(node.parent().is_none()); 71 assert!(node.parent().is_none());
70 let mut res = AstIdMap { arena: Arena::default() }; 72 let mut res = AstIdMap::default();
71 // By walking the tree in breadth-first order we make sure that parents 73 // By walking the tree in breadth-first order we make sure that parents
72 // get lower ids then children. That is, adding a new child does not 74 // get lower ids then children. That is, adding a new child does not
73 // change parent's id. This means that, say, adding a new function to a 75 // change parent's id. This means that, say, adding a new function to a
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index db42a00dc..c7502bf57 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.50", default-features = false } 20chalk-solve = { version = "0.51", default-features = false }
21chalk-ir = "0.50" 21chalk-ir = "0.51"
22chalk-recursive = "0.50" 22chalk-recursive = "0.51"
23la-arena = { version = "0.2.0", path = "../../lib/arena" } 23la-arena = { version = "0.2.0", path = "../../lib/arena" }
24 24
25stdx = { path = "../stdx", version = "0.0.0" } 25stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 54485fd30..2f37c8040 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -416,8 +416,11 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
416 name_ref => Some(name_ref.to_owned()), 416 name_ref => Some(name_ref.to_owned()),
417 } 417 }
418 } 418 }
419 ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
420 ast::Expr::PathExpr(path_expr) => Some(path_expr.to_string()),
421 ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
419 ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?), 422 ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
420 _ => Some(expr.to_string()), 423 _ => None,
421 } 424 }
422} 425}
423 426
@@ -1438,4 +1441,19 @@ fn main() {
1438"#, 1441"#,
1439 ) 1442 )
1440 } 1443 }
1444
1445 #[test]
1446 fn param_name_hints_show_for_literals() {
1447 check(
1448 r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
1449fn main() {
1450 test(
1451 0x0fab272b,
1452 //^^^^^^^^^^ a
1453 0x0fab272b
1454 //^^^^^^^^^^ b
1455 );
1456}"#,
1457 )
1458 }
1441} 1459}
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index c25bcce50..99a558532 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -9,7 +9,7 @@ use ide_db::{
9 search::FileReference, 9 search::FileReference,
10 RootDatabase, 10 RootDatabase,
11}; 11};
12use stdx::assert_never; 12use stdx::never;
13use syntax::{ 13use syntax::{
14 ast::{self, NameOwner}, 14 ast::{self, NameOwner},
15 lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, 15 lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T,
@@ -285,7 +285,7 @@ fn rename_mod(
285} 285}
286 286
287fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { 287fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> {
288 if assert_never!(local.is_self(sema.db)) { 288 if never!(local.is_self(sema.db)) {
289 bail!("rename_to_self invoked on self"); 289 bail!("rename_to_self invoked on self");
290 } 290 }
291 291
@@ -388,7 +388,7 @@ fn rename_self_to_param(
388 let (file_id, self_param) = match local.source(sema.db) { 388 let (file_id, self_param) = match local.source(sema.db) {
389 InFile { file_id, value: Either::Right(self_param) } => (file_id, self_param), 389 InFile { file_id, value: Either::Right(self_param) } => (file_id, self_param),
390 _ => { 390 _ => {
391 assert_never!(true, "rename_self_to_param invoked on a non-self local"); 391 never!(true, "rename_self_to_param invoked on a non-self local");
392 bail!("rename_self_to_param invoked on a non-self local"); 392 bail!("rename_self_to_param invoked on a non-self local");
393 } 393 }
394 }; 394 };
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs
index b1f87731b..f76bac151 100644
--- a/crates/ide_db/src/source_change.rs
+++ b/crates/ide_db/src/source_change.rs
@@ -10,7 +10,7 @@ use std::{
10 10
11use base_db::{AnchoredPathBuf, FileId}; 11use base_db::{AnchoredPathBuf, FileId};
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use stdx::assert_never; 13use stdx::never;
14use text_edit::TextEdit; 14use text_edit::TextEdit;
15 15
16#[derive(Default, Debug, Clone)] 16#[derive(Default, Debug, Clone)]
@@ -40,10 +40,7 @@ impl SourceChange {
40 pub fn insert_source_edit(&mut self, file_id: FileId, edit: TextEdit) { 40 pub fn insert_source_edit(&mut self, file_id: FileId, edit: TextEdit) {
41 match self.source_file_edits.entry(file_id) { 41 match self.source_file_edits.entry(file_id) {
42 Entry::Occupied(mut entry) => { 42 Entry::Occupied(mut entry) => {
43 assert_never!( 43 never!(entry.get_mut().union(edit).is_err(), "overlapping edits for same file");
44 entry.get_mut().union(edit).is_err(),
45 "overlapping edits for same file"
46 );
47 } 44 }
48 Entry::Vacant(entry) => { 45 Entry::Vacant(entry) => {
49 entry.insert(edit); 46 entry.insert(edit);
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml
index 4dd9acc98..486f9c164 100644
--- a/crates/profile/Cargo.toml
+++ b/crates/profile/Cargo.toml
@@ -14,7 +14,7 @@ once_cell = "1.3.1"
14cfg-if = "1" 14cfg-if = "1"
15libc = "0.2.73" 15libc = "0.2.73"
16la-arena = { version = "0.2.0", path = "../../lib/arena" } 16la-arena = { version = "0.2.0", path = "../../lib/arena" }
17countme = { version = "2.0.0", features = ["enable"] } 17countme = { version = "2.0.1", features = ["enable"] }
18jemalloc-ctl = { version = "0.3.3", optional = true } 18jemalloc-ctl = { version = "0.3.3", optional = true }
19 19
20[target.'cfg(target_os = "linux")'.dependencies] 20[target.'cfg(target_os = "linux")'.dependencies]
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index cf32995e0..3ff347e2c 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -175,7 +175,7 @@ fn is_dylib(path: &Path) -> bool {
175/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> 175/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
176fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) { 176fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) {
177 // FIXME: Missing variables: 177 // FIXME: Missing variables:
178 // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name> 178 // CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
179 179
180 let mut manifest_dir = package.manifest_path.clone(); 180 let mut manifest_dir = package.manifest_path.clone();
181 manifest_dir.pop(); 181 manifest_dir.pop();
@@ -183,6 +183,9 @@ fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, St
183 env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into())); 183 env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into()));
184 } 184 }
185 185
186 // Not always right, but works for common cases.
187 env.push(("CARGO".into(), "cargo".into()));
188
186 env.push(("CARGO_PKG_VERSION".into(), package.version.to_string())); 189 env.push(("CARGO_PKG_VERSION".into(), package.version.to_string()));
187 env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string())); 190 env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string()));
188 env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string())); 191 env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string()));
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 268c00942..82ea76666 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -37,6 +37,7 @@ lsp-server = "0.5.0"
37tracing = "0.1" 37tracing = "0.1"
38tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 38tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
39tracing-tree = { version = "0.1.4" } 39tracing-tree = { version = "0.1.4" }
40always-assert = "0.1"
40 41
41stdx = { path = "../stdx", version = "0.0.0" } 42stdx = { path = "../stdx", version = "0.0.0" }
42flycheck = { path = "../flycheck", version = "0.0.0" } 43flycheck = { path = "../flycheck", version = "0.0.0" }
@@ -72,3 +73,4 @@ tt = { path = "../tt" }
72 73
73[features] 74[features]
74jemalloc = ["jemallocator", "profile/jemalloc"] 75jemalloc = ["jemallocator", "profile/jemalloc"]
76force-always-assert = ["always-assert/force"]
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 7d917946e..2a532361d 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -14,7 +14,10 @@ use vfs::AbsPathBuf;
14pub(crate) struct Args { 14pub(crate) struct Args {
15 pub(crate) verbosity: Verbosity, 15 pub(crate) verbosity: Verbosity,
16 pub(crate) log_file: Option<PathBuf>, 16 pub(crate) log_file: Option<PathBuf>,
17 pub(crate) no_buffering: bool,
17 pub(crate) command: Command, 18 pub(crate) command: Command,
19 #[allow(unused)]
20 pub(crate) wait_dbg: bool,
18} 21}
19 22
20pub(crate) enum Command { 23pub(crate) enum Command {
@@ -47,11 +50,17 @@ FLAGS:
47 -vv, --spammy 50 -vv, --spammy
48 -q, --quiet Set verbosity 51 -q, --quiet Set verbosity
49 52
50 --log-file <PATH> Log to the specified filed instead of stderr 53 --log-file <PATH> Log to the specified file instead of stderr
54 --no-log-buffering
55 Flush log records to the file immediately
56
57 --wait-dbg Wait until a debugger is attached to.
58 The flag is valid for debug builds only
51 59
52ENVIRONMENTAL VARIABLES: 60ENVIRONMENTAL VARIABLES:
53 RA_LOG Set log filter in env_logger format 61 RA_LOG Set log filter in env_logger format
54 RA_PROFILE Enable hierarchical profiler 62 RA_PROFILE Enable hierarchical profiler
63 RA_WAIT_DBG If set acts like a --wait-dbg flag
55 64
56COMMANDS: 65COMMANDS:
57 66
@@ -114,6 +123,8 @@ impl Args {
114 verbosity: Verbosity::Normal, 123 verbosity: Verbosity::Normal,
115 log_file: None, 124 log_file: None,
116 command: Command::Version, 125 command: Command::Version,
126 no_buffering: false,
127 wait_dbg: false,
117 }); 128 });
118 } 129 }
119 130
@@ -130,21 +141,41 @@ impl Args {
130 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), 141 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
131 }; 142 };
132 let log_file = matches.opt_value_from_str("--log-file")?; 143 let log_file = matches.opt_value_from_str("--log-file")?;
144 let no_buffering = matches.contains("--no-log-buffering");
145 let wait_dbg = matches.contains("--wait-dbg");
133 146
134 if matches.contains(["-h", "--help"]) { 147 if matches.contains(["-h", "--help"]) {
135 eprintln!("{}", HELP); 148 eprintln!("{}", HELP);
136 return Ok(Args { verbosity, log_file: None, command: Command::Help }); 149 return Ok(Args {
150 verbosity,
151 log_file: None,
152 command: Command::Help,
153 no_buffering,
154 wait_dbg,
155 });
137 } 156 }
138 157
139 if matches.contains("--print-config-schema") { 158 if matches.contains("--print-config-schema") {
140 return Ok(Args { verbosity, log_file, command: Command::PrintConfigSchema }); 159 return Ok(Args {
160 verbosity,
161 log_file,
162 command: Command::PrintConfigSchema,
163 no_buffering,
164 wait_dbg,
165 });
141 } 166 }
142 167
143 let subcommand = match matches.subcommand()? { 168 let subcommand = match matches.subcommand()? {
144 Some(it) => it, 169 Some(it) => it,
145 None => { 170 None => {
146 finish_args(matches)?; 171 finish_args(matches)?;
147 return Ok(Args { verbosity, log_file, command: Command::RunServer }); 172 return Ok(Args {
173 verbosity,
174 log_file,
175 command: Command::RunServer,
176 no_buffering,
177 wait_dbg,
178 });
148 } 179 }
149 }; 180 };
150 let command = match subcommand.as_str() { 181 let command = match subcommand.as_str() {
@@ -219,11 +250,17 @@ impl Args {
219 }, 250 },
220 _ => { 251 _ => {
221 eprintln!("{}", HELP); 252 eprintln!("{}", HELP);
222 return Ok(Args { verbosity, log_file: None, command: Command::Help }); 253 return Ok(Args {
254 verbosity,
255 log_file: None,
256 command: Command::Help,
257 no_buffering,
258 wait_dbg,
259 });
223 } 260 }
224 }; 261 };
225 finish_args(matches)?; 262 finish_args(matches)?;
226 Ok(Args { verbosity, log_file, command }) 263 Ok(Args { verbosity, log_file, command, no_buffering, wait_dbg })
227 } 264 }
228} 265}
229 266
diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs
index 3bcb1ae37..14887c5cc 100644
--- a/crates/rust-analyzer/src/bin/logger.rs
+++ b/crates/rust-analyzer/src/bin/logger.rs
@@ -4,7 +4,7 @@
4 4
5use std::{ 5use std::{
6 fs::File, 6 fs::File,
7 io::{BufWriter, Write}, 7 io::{self, BufWriter, Write},
8}; 8};
9 9
10use env_logger::filter::{Builder, Filter}; 10use env_logger::filter::{Builder, Filter};
@@ -14,10 +14,11 @@ use parking_lot::Mutex;
14pub(crate) struct Logger { 14pub(crate) struct Logger {
15 filter: Filter, 15 filter: Filter,
16 file: Option<Mutex<BufWriter<File>>>, 16 file: Option<Mutex<BufWriter<File>>>,
17 no_buffering: bool,
17} 18}
18 19
19impl Logger { 20impl Logger {
20 pub(crate) fn new(log_file: Option<File>, filter: Option<&str>) -> Logger { 21 pub(crate) fn new(log_file: Option<File>, no_buffering: bool, filter: Option<&str>) -> Logger {
21 let filter = { 22 let filter = {
22 let mut builder = Builder::new(); 23 let mut builder = Builder::new();
23 if let Some(filter) = filter { 24 if let Some(filter) = filter {
@@ -28,7 +29,7 @@ impl Logger {
28 29
29 let file = log_file.map(|it| Mutex::new(BufWriter::new(it))); 30 let file = log_file.map(|it| Mutex::new(BufWriter::new(it)));
30 31
31 Logger { filter, file } 32 Logger { filter, file, no_buffering }
32 } 33 }
33 34
34 pub(crate) fn install(self) { 35 pub(crate) fn install(self) {
@@ -46,7 +47,8 @@ impl Log for Logger {
46 if !self.filter.matches(record) { 47 if !self.filter.matches(record) {
47 return; 48 return;
48 } 49 }
49 match &self.file { 50
51 let should_flush = match &self.file {
50 Some(w) => { 52 Some(w) => {
51 let _ = writeln!( 53 let _ = writeln!(
52 w.lock(), 54 w.lock(),
@@ -55,19 +57,32 @@ impl Log for Logger {
55 record.module_path().unwrap_or_default(), 57 record.module_path().unwrap_or_default(),
56 record.args(), 58 record.args(),
57 ); 59 );
60 self.no_buffering
61 }
62 None => {
63 eprintln!(
64 "[{} {}] {}",
65 record.level(),
66 record.module_path().unwrap_or_default(),
67 record.args(),
68 );
69 true // flush stderr unconditionally
58 } 70 }
59 None => eprintln!( 71 };
60 "[{} {}] {}", 72
61 record.level(), 73 if should_flush {
62 record.module_path().unwrap_or_default(), 74 self.flush();
63 record.args(),
64 ),
65 } 75 }
66 } 76 }
67 77
68 fn flush(&self) { 78 fn flush(&self) {
69 if let Some(w) = &self.file { 79 match &self.file {
70 let _ = w.lock().flush(); 80 Some(w) => {
81 let _ = w.lock().flush();
82 }
83 None => {
84 let _ = io::stderr().flush();
85 }
71 } 86 }
72 } 87 }
73} 88}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 1d6e5478b..088b17b03 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -21,6 +21,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
21 21
22fn main() { 22fn main() {
23 if let Err(err) = try_main() { 23 if let Err(err) = try_main() {
24 log::error!("Unexpected error: {}", err);
24 eprintln!("{}", err); 25 eprintln!("{}", err);
25 process::exit(101); 26 process::exit(101);
26 } 27 }
@@ -28,7 +29,17 @@ fn main() {
28 29
29fn try_main() -> Result<()> { 30fn try_main() -> Result<()> {
30 let args = args::Args::parse()?; 31 let args = args::Args::parse()?;
31 setup_logging(args.log_file)?; 32
33 #[cfg(debug_assertions)]
34 if args.wait_dbg || env::var("RA_WAIT_DBG").is_ok() {
35 #[allow(unused_mut)]
36 let mut d = 4;
37 while d == 4 {
38 d = 4;
39 }
40 }
41
42 setup_logging(args.log_file, args.no_buffering)?;
32 match args.command { 43 match args.command {
33 args::Command::RunServer => run_server()?, 44 args::Command::RunServer => run_server()?,
34 args::Command::PrintConfigSchema => { 45 args::Command::PrintConfigSchema => {
@@ -56,7 +67,7 @@ fn try_main() -> Result<()> {
56 Ok(()) 67 Ok(())
57} 68}
58 69
59fn setup_logging(log_file: Option<PathBuf>) -> Result<()> { 70fn setup_logging(log_file: Option<PathBuf>, no_buffering: bool) -> Result<()> {
60 env::set_var("RUST_BACKTRACE", "short"); 71 env::set_var("RUST_BACKTRACE", "short");
61 72
62 let log_file = match log_file { 73 let log_file = match log_file {
@@ -69,21 +80,12 @@ fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
69 None => None, 80 None => None,
70 }; 81 };
71 let filter = env::var("RA_LOG").ok(); 82 let filter = env::var("RA_LOG").ok();
72 logger::Logger::new(log_file, filter.as_deref()).install(); 83 logger::Logger::new(log_file, no_buffering, filter.as_deref()).install();
73 84
74 tracing_setup::setup_tracing()?; 85 tracing_setup::setup_tracing()?;
75 86
76 profile::init(); 87 profile::init();
77 88
78 if !cfg!(debug_assertions) {
79 stdx::set_assert_hook(|loc, args| {
80 if env::var("RA_PROFILE").is_ok() {
81 panic!("assertion failed at {}: {}", loc, args)
82 }
83 log::error!("assertion failed at {}: {}", loc, args)
84 });
85 }
86
87 Ok(()) 89 Ok(())
88} 90}
89 91
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index c47e8d0a8..5866c0a28 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
11 11
12[dependencies] 12[dependencies]
13backtrace = { version = "0.3.44", optional = true } 13backtrace = { version = "0.3.44", optional = true }
14always-assert = { version = "0.1.1", features = ["log"] }
14# Think twice before adding anything here 15# Think twice before adding anything here
15 16
16[features] 17[features]
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index d42817078..d26be4853 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -4,7 +4,7 @@ use std::{cmp::Ordering, ops, process, time::Instant};
4mod macros; 4mod macros;
5pub mod panic_context; 5pub mod panic_context;
6 6
7pub use crate::macros::{on_assert_failure, set_assert_hook}; 7pub use always_assert::{always, never};
8 8
9#[inline(always)] 9#[inline(always)]
10pub fn is_ci() -> bool { 10pub fn is_ci() -> bool {
diff --git a/crates/stdx/src/macros.rs b/crates/stdx/src/macros.rs
index 4f5c6100d..d91fc690c 100644
--- a/crates/stdx/src/macros.rs
+++ b/crates/stdx/src/macros.rs
@@ -1,9 +1,5 @@
1//! Convenience macros. 1//! Convenience macros.
2 2
3use std::{
4 fmt, mem, panic,
5 sync::atomic::{AtomicUsize, Ordering::SeqCst},
6};
7#[macro_export] 3#[macro_export]
8macro_rules! eprintln { 4macro_rules! eprintln {
9 ($($tt:tt)*) => {{ 5 ($($tt:tt)*) => {{
@@ -49,50 +45,3 @@ macro_rules! impl_from {
49 )* 45 )*
50 } 46 }
51} 47}
52
53/// A version of `assert!` macro which allows to handle an assertion failure.
54///
55/// In release mode, it returns the condition and logs an error.
56///
57/// ```
58/// if assert_never!(impossible) {
59/// // Heh, this shouldn't have happened, but lets try to soldier on...
60/// return None;
61/// }
62/// ```
63///
64/// Rust analyzer is a long-running process, and crashing really isn't an option.
65///
66/// Shamelessly stolen from: https://www.sqlite.org/assert.html
67#[macro_export]
68macro_rules! assert_never {
69 ($cond:expr) => { $crate::assert_never!($cond, "") };
70 ($cond:expr, $($fmt:tt)*) => {{
71 let value = $cond;
72 if value {
73 $crate::on_assert_failure(
74 format_args!($($fmt)*)
75 );
76 }
77 value
78 }};
79}
80
81type AssertHook = fn(&panic::Location<'_>, fmt::Arguments<'_>);
82static HOOK: AtomicUsize = AtomicUsize::new(0);
83
84pub fn set_assert_hook(hook: AssertHook) {
85 HOOK.store(hook as usize, SeqCst);
86}
87
88#[cold]
89#[track_caller]
90pub fn on_assert_failure(args: fmt::Arguments) {
91 let hook: usize = HOOK.load(SeqCst);
92 if hook == 0 {
93 panic!("\n assertion failed: {}\n", args);
94 }
95
96 let hook: AssertHook = unsafe { mem::transmute::<usize, AssertHook>(hook) };
97 hook(panic::Location::caller(), args)
98}
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index e70fbba9c..de65585cb 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.10.0" 14itertools = "0.10.0"
15rowan = "0.12.2" 15rowan = "0.12.2"
16rustc_lexer = { version = "700.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "701.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"