diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/fill_match_arms.rs | 28 | ||||
-rw-r--r-- | crates/completion/src/item.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/body.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/ast_id_map.rs | 4 | ||||
-rw-r--r-- | crates/hir_ty/Cargo.toml | 6 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 20 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 6 | ||||
-rw-r--r-- | crates/ide_db/src/source_change.rs | 7 | ||||
-rw-r--r-- | crates/profile/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/project_model/src/build_data.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/args.rs | 49 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/logger.rs | 39 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 26 | ||||
-rw-r--r-- | crates/stdx/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/stdx/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/stdx/src/macros.rs | 51 | ||||
-rw-r--r-- | crates/syntax/Cargo.toml | 2 |
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#" | ||
279 | enum Option<T> { Some(T), None } | ||
280 | use Option::*; | ||
281 | |||
282 | fn main() { | ||
283 | match None$0 { | ||
284 | None => {} | ||
285 | } | ||
286 | } | ||
287 | "#, | ||
288 | r#" | ||
289 | enum Option<T> { Some(T), None } | ||
290 | use Option::*; | ||
291 | |||
292 | fn 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 | }; |
13 | use stdx::{assert_never, impl_from}; | 13 | use stdx::{impl_from, never}; |
14 | use syntax::{algo, TextRange}; | 14 | use syntax::{algo, TextRange}; |
15 | use text_edit::TextEdit; | 15 | use 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 | }; |
19 | use la_arena::{Arena, ArenaMap}; | 19 | use la_arena::{Arena, ArenaMap}; |
20 | use profile::Count; | ||
20 | use rustc_hash::FxHashMap; | 21 | use rustc_hash::FxHashMap; |
21 | use syntax::{ast, AstNode, AstPtr}; | 22 | use syntax::{ast, AstNode, AstPtr}; |
22 | use test_utils::mark; | 23 | use 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 | ||
242 | pub type ExprPtr = AstPtr<ast::Expr>; | 244 | pub 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 | }; |
12 | use la_arena::Arena; | 12 | use la_arena::Arena; |
13 | use profile::Count; | ||
13 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
14 | use syntax::{ | 15 | use 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 | ||
15 | use la_arena::{Arena, Idx}; | 15 | use la_arena::{Arena, Idx}; |
16 | use profile::Count; | ||
16 | use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; | 17 | use 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)] |
63 | pub struct AstIdMap { | 64 | pub struct AstIdMap { |
64 | arena: Arena<SyntaxNodePtr>, | 65 | arena: Arena<SyntaxNodePtr>, |
66 | _c: Count<Self>, | ||
65 | } | 67 | } |
66 | 68 | ||
67 | impl AstIdMap { | 69 | impl 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" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.50", default-features = false } | 20 | chalk-solve = { version = "0.51", default-features = false } |
21 | chalk-ir = "0.50" | 21 | chalk-ir = "0.51" |
22 | chalk-recursive = "0.50" | 22 | chalk-recursive = "0.51" |
23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { 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] } | ||
1449 | fn 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 | }; |
12 | use stdx::assert_never; | 12 | use stdx::never; |
13 | use syntax::{ | 13 | use 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 | ||
287 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { | 287 | fn 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 | ||
11 | use base_db::{AnchoredPathBuf, FileId}; | 11 | use base_db::{AnchoredPathBuf, FileId}; |
12 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
13 | use stdx::assert_never; | 13 | use stdx::never; |
14 | use text_edit::TextEdit; | 14 | use 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" | |||
14 | cfg-if = "1" | 14 | cfg-if = "1" |
15 | libc = "0.2.73" | 15 | libc = "0.2.73" |
16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
17 | countme = { version = "2.0.0", features = ["enable"] } | 17 | countme = { version = "2.0.1", features = ["enable"] } |
18 | jemalloc-ctl = { version = "0.3.3", optional = true } | 18 | jemalloc-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> |
176 | fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) { | 176 | fn 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" | |||
37 | tracing = "0.1" | 37 | tracing = "0.1" |
38 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | 38 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } |
39 | tracing-tree = { version = "0.1.4" } | 39 | tracing-tree = { version = "0.1.4" } |
40 | always-assert = "0.1" | ||
40 | 41 | ||
41 | stdx = { path = "../stdx", version = "0.0.0" } | 42 | stdx = { path = "../stdx", version = "0.0.0" } |
42 | flycheck = { path = "../flycheck", version = "0.0.0" } | 43 | flycheck = { path = "../flycheck", version = "0.0.0" } |
@@ -72,3 +73,4 @@ tt = { path = "../tt" } | |||
72 | 73 | ||
73 | [features] | 74 | [features] |
74 | jemalloc = ["jemallocator", "profile/jemalloc"] | 75 | jemalloc = ["jemallocator", "profile/jemalloc"] |
76 | force-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; | |||
14 | pub(crate) struct Args { | 14 | pub(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 | ||
20 | pub(crate) enum Command { | 23 | pub(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 | ||
52 | ENVIRONMENTAL VARIABLES: | 60 | ENVIRONMENTAL 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 | ||
56 | COMMANDS: | 65 | COMMANDS: |
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 | ||
5 | use std::{ | 5 | use std::{ |
6 | fs::File, | 6 | fs::File, |
7 | io::{BufWriter, Write}, | 7 | io::{self, BufWriter, Write}, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use env_logger::filter::{Builder, Filter}; | 10 | use env_logger::filter::{Builder, Filter}; |
@@ -14,10 +14,11 @@ use parking_lot::Mutex; | |||
14 | pub(crate) struct Logger { | 14 | pub(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 | ||
19 | impl Logger { | 20 | impl 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 | ||
22 | fn main() { | 22 | fn 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 | ||
29 | fn try_main() -> Result<()> { | 30 | fn 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 | ||
59 | fn setup_logging(log_file: Option<PathBuf>) -> Result<()> { | 70 | fn 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] |
13 | backtrace = { version = "0.3.44", optional = true } | 13 | backtrace = { version = "0.3.44", optional = true } |
14 | always-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}; | |||
4 | mod macros; | 4 | mod macros; |
5 | pub mod panic_context; | 5 | pub mod panic_context; |
6 | 6 | ||
7 | pub use crate::macros::{on_assert_failure, set_assert_hook}; | 7 | pub use always_assert::{always, never}; |
8 | 8 | ||
9 | #[inline(always)] | 9 | #[inline(always)] |
10 | pub fn is_ci() -> bool { | 10 | pub 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 | ||
3 | use std::{ | ||
4 | fmt, mem, panic, | ||
5 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, | ||
6 | }; | ||
7 | #[macro_export] | 3 | #[macro_export] |
8 | macro_rules! eprintln { | 4 | macro_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] | ||
68 | macro_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 | |||
81 | type AssertHook = fn(&panic::Location<'_>, fmt::Arguments<'_>); | ||
82 | static HOOK: AtomicUsize = AtomicUsize::new(0); | ||
83 | |||
84 | pub fn set_assert_hook(hook: AssertHook) { | ||
85 | HOOK.store(hook as usize, SeqCst); | ||
86 | } | ||
87 | |||
88 | #[cold] | ||
89 | #[track_caller] | ||
90 | pub 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] |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.12.2" | 15 | rowan = "0.12.2" |
16 | rustc_lexer = { version = "700.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "701.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |