aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/launch.json6
-rw-r--r--Cargo.lock61
-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
-rw-r--r--docs/dev/debugging.md8
-rw-r--r--docs/dev/style.md2
-rw-r--r--xtask/src/install.rs2
24 files changed, 210 insertions, 127 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 8ca27d878..021b8f048 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -120,6 +120,12 @@
120 "sourceMaps": true, 120 "sourceMaps": true,
121 "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ], 121 "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ],
122 "preLaunchTask": "Pretest" 122 "preLaunchTask": "Pretest"
123 },
124 {
125 "name": "Win Attach to Server",
126 "type": "cppvsdbg",
127 "processId":"${command:pickProcess}",
128 "request": "attach"
123 } 129 }
124 ] 130 ]
125} 131}
diff --git a/Cargo.lock b/Cargo.lock
index efd1c6d33..fabe69285 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -16,6 +16,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
16checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" 16checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
17 17
18[[package]] 18[[package]]
19name = "always-assert"
20version = "0.1.1"
21source = "registry+https://github.com/rust-lang/crates.io-index"
22checksum = "727786f78c5bc0cda8011831616589f72084cb16b7df4213a997b78749b55a60"
23dependencies = [
24 "log",
25]
26
27[[package]]
19name = "ansi_term" 28name = "ansi_term"
20version = "0.12.1" 29version = "0.12.1"
21source = "registry+https://github.com/rust-lang/crates.io-index" 30source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -175,9 +184,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
175 184
176[[package]] 185[[package]]
177name = "chalk-derive" 186name = "chalk-derive"
178version = "0.50.0" 187version = "0.51.0"
179source = "registry+https://github.com/rust-lang/crates.io-index" 188source = "registry+https://github.com/rust-lang/crates.io-index"
180checksum = "ac605cf409013573e971d7292d4bec6f5495b19d5f98fc9d8b1a12270c3888e0" 189checksum = "f1a2ad10b964771ffc53ce7a8d6fce4bde3da0da82a1bc7a72668548db1c56ee"
181dependencies = [ 190dependencies = [
182 "proc-macro2", 191 "proc-macro2",
183 "quote", 192 "quote",
@@ -187,9 +196,9 @@ dependencies = [
187 196
188[[package]] 197[[package]]
189name = "chalk-ir" 198name = "chalk-ir"
190version = "0.50.0" 199version = "0.51.0"
191source = "registry+https://github.com/rust-lang/crates.io-index" 200source = "registry+https://github.com/rust-lang/crates.io-index"
192checksum = "fa1dbfb3c2c8b67edb5cd981f720550e43579090574f786145731f90c5d401ff" 201checksum = "17b14b40a09687aa5f0973721841d83a8a0e12a6b3ada1d2e01f0a694bb800ee"
193dependencies = [ 202dependencies = [
194 "bitflags", 203 "bitflags",
195 "chalk-derive", 204 "chalk-derive",
@@ -198,9 +207,9 @@ dependencies = [
198 207
199[[package]] 208[[package]]
200name = "chalk-recursive" 209name = "chalk-recursive"
201version = "0.50.0" 210version = "0.51.0"
202source = "registry+https://github.com/rust-lang/crates.io-index" 211source = "registry+https://github.com/rust-lang/crates.io-index"
203checksum = "0882e2a3ba66901717a64f8bb0655e809f800ac6abed05cb605e7a41d4bf8999" 212checksum = "1c7297bb1683f63a4b334b53cfdd81a721e8adde3441514e1126d24aaafe2552"
204dependencies = [ 213dependencies = [
205 "chalk-derive", 214 "chalk-derive",
206 "chalk-ir", 215 "chalk-ir",
@@ -211,9 +220,9 @@ dependencies = [
211 220
212[[package]] 221[[package]]
213name = "chalk-solve" 222name = "chalk-solve"
214version = "0.50.0" 223version = "0.51.0"
215source = "registry+https://github.com/rust-lang/crates.io-index" 224source = "registry+https://github.com/rust-lang/crates.io-index"
216checksum = "0d43cce07150eac39771ff4b198537cefef744734b2218a89c682295b54cd8d0" 225checksum = "82765c1a19e801d53fc9d145449701ddf79f394e6519f1e9c01fca1ee95d0ba7"
217dependencies = [ 226dependencies = [
218 "chalk-derive", 227 "chalk-derive",
219 "chalk-ir", 228 "chalk-ir",
@@ -275,9 +284,9 @@ checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
275 284
276[[package]] 285[[package]]
277name = "countme" 286name = "countme"
278version = "2.0.0" 287version = "2.0.3"
279source = "registry+https://github.com/rust-lang/crates.io-index" 288source = "registry+https://github.com/rust-lang/crates.io-index"
280checksum = "4f8038ded86523aa26c1321dfe8bb432707d0a3e2608f9d0108803727546e089" 289checksum = "be0bdf97802dfc074a4cf9a1f087f7f8d6478ee039a46eba1644690bcc854d61"
281dependencies = [ 290dependencies = [
282 "dashmap", 291 "dashmap",
283 "once_cell", 292 "once_cell",
@@ -878,11 +887,11 @@ dependencies = [
878 887
879[[package]] 888[[package]]
880name = "log" 889name = "log"
881version = "0.4.13" 890version = "0.4.14"
882source = "registry+https://github.com/rust-lang/crates.io-index" 891source = "registry+https://github.com/rust-lang/crates.io-index"
883checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" 892checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
884dependencies = [ 893dependencies = [
885 "cfg-if 0.1.10", 894 "cfg-if 1.0.0",
886] 895]
887 896
888[[package]] 897[[package]]
@@ -1415,6 +1424,7 @@ dependencies = [
1415name = "rust-analyzer" 1424name = "rust-analyzer"
1416version = "0.0.0" 1425version = "0.0.0"
1417dependencies = [ 1426dependencies = [
1427 "always-assert",
1418 "anyhow", 1428 "anyhow",
1419 "cfg", 1429 "cfg",
1420 "crossbeam-channel 0.5.0", 1430 "crossbeam-channel 0.5.0",
@@ -1464,9 +1474,9 @@ dependencies = [
1464 1474
1465[[package]] 1475[[package]]
1466name = "rustc-ap-rustc_lexer" 1476name = "rustc-ap-rustc_lexer"
1467version = "700.0.0" 1477version = "701.0.0"
1468source = "registry+https://github.com/rust-lang/crates.io-index" 1478source = "registry+https://github.com/rust-lang/crates.io-index"
1469checksum = "5ed36784376b69c941d7aa36e960a52ac712e2663960357121a4d9f2cc58e225" 1479checksum = "3601c20fc378d11e965fb1f670cf8bad1ef5164fe4ec8cbb7c57fa9d656f2541"
1470dependencies = [ 1480dependencies = [
1471 "unicode-xid", 1481 "unicode-xid",
1472] 1482]
@@ -1560,18 +1570,18 @@ dependencies = [
1560 1570
1561[[package]] 1571[[package]]
1562name = "serde" 1572name = "serde"
1563version = "1.0.120" 1573version = "1.0.123"
1564source = "registry+https://github.com/rust-lang/crates.io-index" 1574source = "registry+https://github.com/rust-lang/crates.io-index"
1565checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab" 1575checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
1566dependencies = [ 1576dependencies = [
1567 "serde_derive", 1577 "serde_derive",
1568] 1578]
1569 1579
1570[[package]] 1580[[package]]
1571name = "serde_derive" 1581name = "serde_derive"
1572version = "1.0.120" 1582version = "1.0.123"
1573source = "registry+https://github.com/rust-lang/crates.io-index" 1583source = "registry+https://github.com/rust-lang/crates.io-index"
1574checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775" 1584checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
1575dependencies = [ 1585dependencies = [
1576 "proc-macro2", 1586 "proc-macro2",
1577 "quote", 1587 "quote",
@@ -1658,14 +1668,15 @@ dependencies = [
1658name = "stdx" 1668name = "stdx"
1659version = "0.0.0" 1669version = "0.0.0"
1660dependencies = [ 1670dependencies = [
1671 "always-assert",
1661 "backtrace", 1672 "backtrace",
1662] 1673]
1663 1674
1664[[package]] 1675[[package]]
1665name = "syn" 1676name = "syn"
1666version = "1.0.59" 1677version = "1.0.60"
1667source = "registry+https://github.com/rust-lang/crates.io-index" 1678source = "registry+https://github.com/rust-lang/crates.io-index"
1668checksum = "07cb8b1b4ebf86a89ee88cbd201b022b94138c623644d035185c84d3f41b7e66" 1679checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
1669dependencies = [ 1680dependencies = [
1670 "proc-macro2", 1681 "proc-macro2",
1671 "quote", 1682 "quote",
@@ -1742,9 +1753,9 @@ dependencies = [
1742 1753
1743[[package]] 1754[[package]]
1744name = "thread_local" 1755name = "thread_local"
1745version = "1.1.1" 1756version = "1.1.2"
1746source = "registry+https://github.com/rust-lang/crates.io-index" 1757source = "registry+https://github.com/rust-lang/crates.io-index"
1747checksum = "301bdd13d23c49672926be451130892d274d3ba0b410c18e00daa7990ff38d99" 1758checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915"
1748dependencies = [ 1759dependencies = [
1749 "once_cell", 1760 "once_cell",
1750] 1761]
@@ -1771,9 +1782,9 @@ dependencies = [
1771 1782
1772[[package]] 1783[[package]]
1773name = "tinyvec" 1784name = "tinyvec"
1774version = "1.1.0" 1785version = "1.1.1"
1775source = "registry+https://github.com/rust-lang/crates.io-index" 1786source = "registry+https://github.com/rust-lang/crates.io-index"
1776checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" 1787checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
1777dependencies = [ 1788dependencies = [
1778 "tinyvec_macros", 1789 "tinyvec_macros",
1779] 1790]
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"
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md
index 8c48fd5a1..cc7a790ff 100644
--- a/docs/dev/debugging.md
+++ b/docs/dev/debugging.md
@@ -57,6 +57,14 @@ To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</k
57 57
58- Go back to the `[Extension Development Host]` instance and hover over a Rust variable and your breakpoint should hit. 58- Go back to the `[Extension Development Host]` instance and hover over a Rust variable and your breakpoint should hit.
59 59
60If you need to debug the server from the very beginning, including its initialization code, you can use the `--wait-dbg` command line argument or `RA_WAIT_DBG` environment variable. The server will spin at the beginning of the `try_main` function (see `crates\rust-analyzer\src\bin\main.rs`)
61```rust
62 let mut d = 4;
63 while d == 4 { // set a breakpoint here and change the value
64 d = 4;
65 }
66```
67
60## Demo 68## Demo
61 69
62- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). 70- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM).
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 6dc6868c2..0c5e2ad33 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -232,7 +232,7 @@ if idx >= len {
232## Assertions 232## Assertions
233 233
234Assert liberally. 234Assert liberally.
235Prefer `stdx::assert_never!` to standard `assert!`. 235Prefer `stdx::never!` to standard `assert!`.
236 236
237## Getters & Setters 237## Getters & Setters
238 238
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 202c74426..81b9956b8 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -180,7 +180,7 @@ fn install_server(opts: ServerOpt) -> Result<()> {
180 Malloc::Jemalloc => &["--features", "jemalloc"], 180 Malloc::Jemalloc => &["--features", "jemalloc"],
181 }; 181 };
182 182
183 let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force {features...}"); 183 let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
184 let res = cmd.run(); 184 let res = cmd.run();
185 185
186 if res.is_err() && old_rust { 186 if res.is_err() && old_rust {