aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/ignore_test.rs34
-rw-r--r--crates/assists/src/handlers/unwrap_block.rs613
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests/generated.rs20
-rw-r--r--crates/assists/src/utils.rs18
-rw-r--r--crates/base_db/src/input.rs20
-rw-r--r--crates/cfg/src/lib.rs6
-rw-r--r--crates/hir/src/diagnostics.rs4
-rw-r--r--crates/hir_expand/src/diagnostics.rs2
-rw-r--r--crates/ide/src/diagnostics.rs40
-rw-r--r--crates/ide/src/fn_references.rs5
-rw-r--r--crates/ide/src/runnables.rs19
-rw-r--r--crates/project_model/src/sysroot.rs2
-rw-r--r--crates/project_model/src/workspace.rs608
-rw-r--r--crates/rust-analyzer/Cargo.toml4
-rw-r--r--crates/rust-analyzer/src/caps.rs1
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs4
-rw-r--r--crates/rust-analyzer/src/document.rs6
-rw-r--r--crates/rust-analyzer/src/global_state.rs4
-rw-r--r--crates/rust-analyzer/src/handlers.rs4
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs2
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs6
-rw-r--r--crates/rust-analyzer/src/main_loop.rs4
-rw-r--r--crates/rust-analyzer/src/reload.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs18
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs4
26 files changed, 792 insertions, 664 deletions
diff --git a/crates/assists/src/handlers/ignore_test.rs b/crates/assists/src/handlers/ignore_test.rs
new file mode 100644
index 000000000..d2339184f
--- /dev/null
+++ b/crates/assists/src/handlers/ignore_test.rs
@@ -0,0 +1,34 @@
1use syntax::{ast, AstNode};
2
3use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists};
4
5// Assist: ignore_test
6//
7// Adds `#[ignore]` attribute to the test.
8//
9// ```
10// <|>#[test]
11// fn arithmetics {
12// assert_eq!(2 + 2, 5);
13// }
14// ```
15// ->
16// ```
17// #[test]
18// #[ignore]
19// fn arithmetics {
20// assert_eq!(2 + 2, 5);
21// }
22// ```
23pub(crate) fn ignore_test(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let attr: ast::Attr = ctx.find_node_at_offset()?;
25 let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
26 let attr = test_related_attribute(&func)?;
27
28 acc.add(
29 AssistId("ignore_test", AssistKind::None),
30 "Ignore this test",
31 attr.syntax().text_range(),
32 |builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")),
33 )
34}
diff --git a/crates/assists/src/handlers/unwrap_block.rs b/crates/assists/src/handlers/unwrap_block.rs
index 36ef871b9..676db7137 100644
--- a/crates/assists/src/handlers/unwrap_block.rs
+++ b/crates/assists/src/handlers/unwrap_block.rs
@@ -3,7 +3,7 @@ use syntax::{
3 self, 3 self,
4 edit::{AstNodeEdit, IndentLevel}, 4 edit::{AstNodeEdit, IndentLevel},
5 }, 5 },
6 AstNode, TextRange, T, 6 AstNode, SyntaxKind, TextRange, T,
7}; 7};
8 8
9use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists}; 9use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
@@ -31,11 +31,21 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
31 31
32 let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?; 32 let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?;
33 let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; 33 let mut block = ast::BlockExpr::cast(l_curly_token.parent())?;
34 let target = block.syntax().text_range();
34 let mut parent = block.syntax().parent()?; 35 let mut parent = block.syntax().parent()?;
35 if ast::MatchArm::can_cast(parent.kind()) { 36 if ast::MatchArm::can_cast(parent.kind()) {
36 parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))? 37 parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))?
37 } 38 }
38 39
40 if matches!(parent.kind(), SyntaxKind::BLOCK_EXPR | SyntaxKind::EXPR_STMT) {
41 return acc.add(assist_id, assist_label, target, |builder| {
42 builder.replace(
43 block.syntax().text_range(),
44 update_expr_string(block.to_string(), &[' ', '{', '\n']),
45 );
46 });
47 }
48
39 let parent = ast::Expr::cast(parent)?; 49 let parent = ast::Expr::cast(parent)?;
40 50
41 match parent.clone() { 51 match parent.clone() {
@@ -48,7 +58,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
48 // For `else if` blocks 58 // For `else if` blocks
49 let ancestor_then_branch = ancestor.then_branch()?; 59 let ancestor_then_branch = ancestor.then_branch()?;
50 60
51 let target = then_branch.syntax().text_range();
52 return acc.add(assist_id, assist_label, target, |edit| { 61 return acc.add(assist_id, assist_label, target, |edit| {
53 let range_to_del_else_if = TextRange::new( 62 let range_to_del_else_if = TextRange::new(
54 ancestor_then_branch.syntax().text_range().end(), 63 ancestor_then_branch.syntax().text_range().end(),
@@ -68,7 +77,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
68 }); 77 });
69 } 78 }
70 } else { 79 } else {
71 let target = block.syntax().text_range();
72 return acc.add(assist_id, assist_label, target, |edit| { 80 return acc.add(assist_id, assist_label, target, |edit| {
73 let range_to_del = TextRange::new( 81 let range_to_del = TextRange::new(
74 then_branch.syntax().text_range().end(), 82 then_branch.syntax().text_range().end(),
@@ -84,7 +92,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
84 }; 92 };
85 93
86 let unwrapped = unwrap_trivial_block(block); 94 let unwrapped = unwrap_trivial_block(block);
87 let target = unwrapped.syntax().text_range();
88 acc.add(assist_id, assist_label, target, |builder| { 95 acc.add(assist_id, assist_label, target, |builder| {
89 builder.replace( 96 builder.replace(
90 parent.syntax().text_range(), 97 parent.syntax().text_range(),
@@ -112,31 +119,89 @@ mod tests {
112 use super::*; 119 use super::*;
113 120
114 #[test] 121 #[test]
122 fn unwrap_tail_expr_block() {
123 check_assist(
124 unwrap_block,
125 r#"
126fn main() {
127 <|>{
128 92
129 }
130}
131"#,
132 r#"
133fn main() {
134 92
135}
136"#,
137 )
138 }
139
140 #[test]
141 fn unwrap_stmt_expr_block() {
142 check_assist(
143 unwrap_block,
144 r#"
145fn main() {
146 <|>{
147 92;
148 }
149 ()
150}
151"#,
152 r#"
153fn main() {
154 92;
155 ()
156}
157"#,
158 );
159 // Pedantically, we should add an `;` here...
160 check_assist(
161 unwrap_block,
162 r#"
163fn main() {
164 <|>{
165 92
166 }
167 ()
168}
169"#,
170 r#"
171fn main() {
172 92
173 ()
174}
175"#,
176 );
177 }
178
179 #[test]
115 fn simple_if() { 180 fn simple_if() {
116 check_assist( 181 check_assist(
117 unwrap_block, 182 unwrap_block,
118 r#" 183 r#"
119 fn main() { 184fn main() {
120 bar(); 185 bar();
121 if true {<|> 186 if true {<|>
122 foo(); 187 foo();
123 188
124 //comment 189 //comment
125 bar(); 190 bar();
126 } else { 191 } else {
127 println!("bar"); 192 println!("bar");
128 } 193 }
129 } 194}
130 "#, 195"#,
131 r#" 196 r#"
132 fn main() { 197fn main() {
133 bar(); 198 bar();
134 foo(); 199 foo();
135 200
136 //comment 201 //comment
137 bar(); 202 bar();
138 } 203}
139 "#, 204"#,
140 ); 205 );
141 } 206 }
142 207
@@ -145,30 +210,30 @@ mod tests {
145 check_assist( 210 check_assist(
146 unwrap_block, 211 unwrap_block,
147 r#" 212 r#"
148 fn main() { 213fn main() {
149 bar(); 214 bar();
150 if true { 215 if true {
151 foo(); 216 foo();
152 217
153 //comment 218 //comment
154 bar(); 219 bar();
155 } else {<|> 220 } else {<|>
156 println!("bar"); 221 println!("bar");
157 } 222 }
158 } 223}
159 "#, 224"#,
160 r#" 225 r#"
161 fn main() { 226fn main() {
162 bar(); 227 bar();
163 if true { 228 if true {
164 foo(); 229 foo();
165 230
166 //comment 231 //comment
167 bar(); 232 bar();
168 } 233 }
169 println!("bar"); 234 println!("bar");
170 } 235}
171 "#, 236"#,
172 ); 237 );
173 } 238 }
174 239
@@ -177,32 +242,32 @@ mod tests {
177 check_assist( 242 check_assist(
178 unwrap_block, 243 unwrap_block,
179 r#" 244 r#"
180 fn main() { 245fn main() {
181 //bar(); 246 //bar();
182 if true { 247 if true {
183 println!("true"); 248 println!("true");
184 249
185 //comment 250 //comment
186 //bar(); 251 //bar();
187 } else if false {<|> 252 } else if false {<|>
188 println!("bar"); 253 println!("bar");
189 } else { 254 } else {
190 println!("foo"); 255 println!("foo");
191 } 256 }
192 } 257}
193 "#, 258"#,
194 r#" 259 r#"
195 fn main() { 260fn main() {
196 //bar(); 261 //bar();
197 if true { 262 if true {
198 println!("true"); 263 println!("true");
199 264
200 //comment 265 //comment
201 //bar(); 266 //bar();
202 } 267 }
203 println!("bar"); 268 println!("bar");
204 } 269}
205 "#, 270"#,
206 ); 271 );
207 } 272 }
208 273
@@ -211,34 +276,34 @@ mod tests {
211 check_assist( 276 check_assist(
212 unwrap_block, 277 unwrap_block,
213 r#" 278 r#"
214 fn main() { 279fn main() {
215 //bar(); 280 //bar();
216 if true { 281 if true {
217 println!("true"); 282 println!("true");
218 283
219 //comment 284 //comment
220 //bar(); 285 //bar();
221 } else if false { 286 } else if false {
222 println!("bar"); 287 println!("bar");
223 } else if true {<|> 288 } else if true {<|>
224 println!("foo"); 289 println!("foo");
225 } 290 }
226 } 291}
227 "#, 292"#,
228 r#" 293 r#"
229 fn main() { 294fn main() {
230 //bar(); 295 //bar();
231 if true { 296 if true {
232 println!("true"); 297 println!("true");
233 298
234 //comment 299 //comment
235 //bar(); 300 //bar();
236 } else if false { 301 } else if false {
237 println!("bar"); 302 println!("bar");
238 } 303 }
239 println!("foo"); 304 println!("foo");
240 } 305}
241 "#, 306"#,
242 ); 307 );
243 } 308 }
244 309
@@ -247,38 +312,38 @@ mod tests {
247 check_assist( 312 check_assist(
248 unwrap_block, 313 unwrap_block,
249 r#" 314 r#"
250 fn main() { 315fn main() {
251 //bar(); 316 //bar();
252 if true { 317 if true {
253 println!("true"); 318 println!("true");
254 319
255 //comment 320 //comment
256 //bar(); 321 //bar();
257 } else if false { 322 } else if false {
258 println!("bar"); 323 println!("bar");
259 } else if true { 324 } else if true {
260 println!("foo"); 325 println!("foo");
261 } else {<|> 326 } else {<|>
262 println!("else"); 327 println!("else");
263 } 328 }
264 } 329}
265 "#, 330"#,
266 r#" 331 r#"
267 fn main() { 332fn main() {
268 //bar(); 333 //bar();
269 if true { 334 if true {
270 println!("true"); 335 println!("true");
271 336
272 //comment 337 //comment
273 //bar(); 338 //bar();
274 } else if false { 339 } else if false {
275 println!("bar"); 340 println!("bar");
276 } else if true { 341 } else if true {
277 println!("foo"); 342 println!("foo");
278 } 343 }
279 println!("else"); 344 println!("else");
280 } 345}
281 "#, 346"#,
282 ); 347 );
283 } 348 }
284 349
@@ -287,36 +352,36 @@ mod tests {
287 check_assist( 352 check_assist(
288 unwrap_block, 353 unwrap_block,
289 r#" 354 r#"
290 fn main() { 355fn main() {
291 //bar(); 356 //bar();
292 if true { 357 if true {
293 println!("true"); 358 println!("true");
294 359
295 //comment 360 //comment
296 //bar(); 361 //bar();
297 } else if false { 362 } else if false {
298 println!("bar"); 363 println!("bar");
299 } else if true {<|> 364 } else if true {<|>
300 println!("foo"); 365 println!("foo");
301 } else { 366 } else {
302 println!("else"); 367 println!("else");
303 } 368 }
304 } 369}
305 "#, 370"#,
306 r#" 371 r#"
307 fn main() { 372fn main() {
308 //bar(); 373 //bar();
309 if true { 374 if true {
310 println!("true"); 375 println!("true");
311 376
312 //comment 377 //comment
313 //bar(); 378 //bar();
314 } else if false { 379 } else if false {
315 println!("bar"); 380 println!("bar");
316 } 381 }
317 println!("foo"); 382 println!("foo");
318 } 383}
319 "#, 384"#,
320 ); 385 );
321 } 386 }
322 387
@@ -325,18 +390,18 @@ mod tests {
325 check_assist_not_applicable( 390 check_assist_not_applicable(
326 unwrap_block, 391 unwrap_block,
327 r#" 392 r#"
328 fn main() { 393fn main() {
329 bar();<|> 394 bar();<|>
330 if true { 395 if true {
331 foo(); 396 foo();
332 397
333 //comment 398 //comment
334 bar(); 399 bar();
335 } else { 400 } else {
336 println!("bar"); 401 println!("bar");
337 } 402 }
338 } 403}
339 "#, 404"#,
340 ); 405 );
341 } 406 }
342 407
@@ -345,31 +410,31 @@ mod tests {
345 check_assist( 410 check_assist(
346 unwrap_block, 411 unwrap_block,
347 r#" 412 r#"
348 fn main() { 413fn main() {
349 for i in 0..5 {<|> 414 for i in 0..5 {<|>
350 if true { 415 if true {
351 foo(); 416 foo();
352 417
353 //comment 418 //comment
354 bar(); 419 bar();
355 } else { 420 } else {
356 println!("bar"); 421 println!("bar");
357 } 422 }
358 } 423 }
359 } 424}
360 "#, 425"#,
361 r#" 426 r#"
362 fn main() { 427fn main() {
363 if true { 428 if true {
364 foo(); 429 foo();
365 430
366 //comment 431 //comment
367 bar(); 432 bar();
368 } else { 433 } else {
369 println!("bar"); 434 println!("bar");
370 } 435 }
371 } 436}
372 "#, 437"#,
373 ); 438 );
374 } 439 }
375 440
@@ -378,29 +443,29 @@ mod tests {
378 check_assist( 443 check_assist(
379 unwrap_block, 444 unwrap_block,
380 r#" 445 r#"
381 fn main() { 446fn main() {
382 for i in 0..5 { 447 for i in 0..5 {
383 if true {<|> 448 if true {<|>
384 foo(); 449 foo();
385 450
386 //comment 451 //comment
387 bar(); 452 bar();
388 } else { 453 } else {
389 println!("bar"); 454 println!("bar");
390 } 455 }
391 } 456 }
392 } 457}
393 "#, 458"#,
394 r#" 459 r#"
395 fn main() { 460fn main() {
396 for i in 0..5 { 461 for i in 0..5 {
397 foo(); 462 foo();
398 463
399 //comment 464 //comment
400 bar(); 465 bar();
401 } 466 }
402 } 467}
403 "#, 468"#,
404 ); 469 );
405 } 470 }
406 471
@@ -409,31 +474,31 @@ mod tests {
409 check_assist( 474 check_assist(
410 unwrap_block, 475 unwrap_block,
411 r#" 476 r#"
412 fn main() { 477fn main() {
413 loop {<|> 478 loop {<|>
414 if true { 479 if true {
415 foo(); 480 foo();
416 481
417 //comment 482 //comment
418 bar(); 483 bar();
419 } else { 484 } else {
420 println!("bar"); 485 println!("bar");
421 } 486 }
422 } 487 }
423 } 488}
424 "#, 489"#,
425 r#" 490 r#"
426 fn main() { 491fn main() {
427 if true { 492 if true {
428 foo(); 493 foo();
429 494
430 //comment 495 //comment
431 bar(); 496 bar();
432 } else { 497 } else {
433 println!("bar"); 498 println!("bar");
434 } 499 }
435 } 500}
436 "#, 501"#,
437 ); 502 );
438 } 503 }
439 504
@@ -442,31 +507,31 @@ mod tests {
442 check_assist( 507 check_assist(
443 unwrap_block, 508 unwrap_block,
444 r#" 509 r#"
445 fn main() { 510fn main() {
446 while true {<|> 511 while true {<|>
447 if true { 512 if true {
448 foo(); 513 foo();
449 514
450 //comment 515 //comment
451 bar(); 516 bar();
452 } else { 517 } else {
453 println!("bar"); 518 println!("bar");
454 } 519 }
455 } 520 }
456 } 521}
457 "#, 522"#,
458 r#" 523 r#"
459 fn main() { 524fn main() {
460 if true { 525 if true {
461 foo(); 526 foo();
462 527
463 //comment 528 //comment
464 bar(); 529 bar();
465 } else { 530 } else {
466 println!("bar"); 531 println!("bar");
467 } 532 }
468 } 533}
469 "#, 534"#,
470 ); 535 );
471 } 536 }
472 537
@@ -499,19 +564,19 @@ fn main() {
499 check_assist_not_applicable( 564 check_assist_not_applicable(
500 unwrap_block, 565 unwrap_block,
501 r#" 566 r#"
502 fn main() { 567fn main() {
503 while true { 568 while true {
504 if true { 569 if true {
505 foo();<|> 570 foo();<|>
506 571
507 //comment 572 //comment
508 bar(); 573 bar();
509 } else { 574 } else {
510 println!("bar"); 575 println!("bar");
511 } 576 }
512 } 577 }
513 } 578}
514 "#, 579"#,
515 ); 580 );
516 } 581 }
517} 582}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index e8d81b33d..17e9312db 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -141,6 +141,7 @@ mod handlers {
141 mod generate_function; 141 mod generate_function;
142 mod generate_impl; 142 mod generate_impl;
143 mod generate_new; 143 mod generate_new;
144 mod ignore_test;
144 mod infer_function_return_type; 145 mod infer_function_return_type;
145 mod inline_local_variable; 146 mod inline_local_variable;
146 mod introduce_named_lifetime; 147 mod introduce_named_lifetime;
@@ -189,6 +190,7 @@ mod handlers {
189 generate_function::generate_function, 190 generate_function::generate_function,
190 generate_impl::generate_impl, 191 generate_impl::generate_impl,
191 generate_new::generate_new, 192 generate_new::generate_new,
193 ignore_test::ignore_test,
192 infer_function_return_type::infer_function_return_type, 194 infer_function_return_type::infer_function_return_type,
193 inline_local_variable::inline_local_variable, 195 inline_local_variable::inline_local_variable,
194 introduce_named_lifetime::introduce_named_lifetime, 196 introduce_named_lifetime::introduce_named_lifetime,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index dbf4f21aa..5a9d1a01b 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -474,6 +474,26 @@ impl<T: Clone> Ctx<T> {
474} 474}
475 475
476#[test] 476#[test]
477fn doctest_ignore_test() {
478 check_doc_test(
479 "ignore_test",
480 r#####"
481<|>#[test]
482fn arithmetics {
483 assert_eq!(2 + 2, 5);
484}
485"#####,
486 r#####"
487#[test]
488#[ignore]
489fn arithmetics {
490 assert_eq!(2 + 2, 5);
491}
492"#####,
493 )
494}
495
496#[test]
477fn doctest_infer_function_return_type() { 497fn doctest_infer_function_return_type() {
478 check_doc_test( 498 check_doc_test(
479 "infer_function_return_type", 499 "infer_function_return_type",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index caabc44de..66c0cdd5f 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -9,6 +9,7 @@ use ide_db::RootDatabase;
9use itertools::Itertools; 9use itertools::Itertools;
10use syntax::{ 10use syntax::{
11 ast::edit::AstNodeEdit, 11 ast::edit::AstNodeEdit,
12 ast::AttrsOwner,
12 ast::NameOwner, 13 ast::NameOwner,
13 ast::{self, edit, make, ArgListOwner}, 14 ast::{self, edit, make, ArgListOwner},
14 AstNode, Direction, 15 AstNode, Direction,
@@ -81,6 +82,23 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
81 None 82 None
82} 83}
83 84
85/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
86/// `#[test_case(...)]`, `#[tokio::test]` and similar.
87/// Also a regular `#[test]` annotation is supported.
88///
89/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
90/// but it's better than not to have the runnables for the tests at all.
91pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
92 fn_def.attrs().find_map(|attr| {
93 let path = attr.path()?;
94 if path.syntax().text().to_string().contains("test") {
95 Some(attr)
96 } else {
97 None
98 }
99 })
100}
101
84#[derive(Copy, Clone, PartialEq)] 102#[derive(Copy, Clone, PartialEq)]
85pub enum DefaultMethods { 103pub enum DefaultMethods {
86 Only, 104 Only,
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 31907ed98..98ba372ad 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -225,7 +225,10 @@ impl CrateGraph {
225 to: CrateId, 225 to: CrateId,
226 ) -> Result<(), CyclicDependenciesError> { 226 ) -> Result<(), CyclicDependenciesError> {
227 if self.dfs_find(from, to, &mut FxHashSet::default()) { 227 if self.dfs_find(from, to, &mut FxHashSet::default()) {
228 return Err(CyclicDependenciesError); 228 return Err(CyclicDependenciesError {
229 from: (from, self[from].display_name.clone()),
230 to: (to, self[to].display_name.clone()),
231 });
229 } 232 }
230 self.arena.get_mut(&from).unwrap().add_dep(name, to); 233 self.arena.get_mut(&from).unwrap().add_dep(name, to);
231 Ok(()) 234 Ok(())
@@ -421,7 +424,20 @@ impl fmt::Display for ParseEditionError {
421impl std::error::Error for ParseEditionError {} 424impl std::error::Error for ParseEditionError {}
422 425
423#[derive(Debug)] 426#[derive(Debug)]
424pub struct CyclicDependenciesError; 427pub struct CyclicDependenciesError {
428 from: (CrateId, Option<CrateDisplayName>),
429 to: (CrateId, Option<CrateDisplayName>),
430}
431
432impl fmt::Display for CyclicDependenciesError {
433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434 let render = |(id, name): &(CrateId, Option<CrateDisplayName>)| match name {
435 Some(it) => format!("{}({:?})", it, id),
436 None => format!("{:?}", id),
437 };
438 write!(f, "cyclic deps: {} -> {}", render(&self.from), render(&self.to))
439 }
440}
425 441
426#[cfg(test)] 442#[cfg(test)]
427mod tests { 443mod tests {
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index d0e08cf5f..d88ecf8b0 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -41,12 +41,6 @@ impl CfgOptions {
41 self.enabled.insert(CfgAtom::KeyValue { key, value }); 41 self.enabled.insert(CfgAtom::KeyValue { key, value });
42 } 42 }
43 43
44 pub fn append(&mut self, other: &CfgOptions) {
45 for atom in &other.enabled {
46 self.enabled.insert(atom.clone());
47 }
48 }
49
50 pub fn apply_diff(&mut self, diff: CfgDiff) { 44 pub fn apply_diff(&mut self, diff: CfgDiff) {
51 for atom in diff.enable { 45 for atom in diff.enable {
52 self.enabled.insert(atom); 46 self.enabled.insert(atom);
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index c18c1c587..d9ad8db6f 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -1,6 +1,8 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule}; 2pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule};
3pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder}; 3pub use hir_expand::diagnostics::{
4 Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
5};
4pub use hir_ty::diagnostics::{ 6pub use hir_ty::diagnostics::{
5 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, 7 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr,
6 NoSuchField, 8 NoSuchField,
diff --git a/crates/hir_expand/src/diagnostics.rs b/crates/hir_expand/src/diagnostics.rs
index 78ccc212c..1043c6aeb 100644
--- a/crates/hir_expand/src/diagnostics.rs
+++ b/crates/hir_expand/src/diagnostics.rs
@@ -20,7 +20,7 @@ use syntax::SyntaxNodePtr;
20 20
21use crate::InFile; 21use crate::InFile;
22 22
23#[derive(Copy, Clone, PartialEq)] 23#[derive(Copy, Clone, Debug, PartialEq)]
24pub struct DiagnosticCode(pub &'static str); 24pub struct DiagnosticCode(pub &'static str);
25 25
26impl DiagnosticCode { 26impl DiagnosticCode {
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 1c7f02763..3df73ed4f 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -10,7 +10,7 @@ mod field_shorthand;
10use std::cell::RefCell; 10use std::cell::RefCell;
11 11
12use hir::{ 12use hir::{
13 diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, 13 diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
14 Semantics, 14 Semantics,
15}; 15};
16use ide_db::base_db::SourceDatabase; 16use ide_db::base_db::SourceDatabase;
@@ -35,15 +35,23 @@ pub struct Diagnostic {
35 pub severity: Severity, 35 pub severity: Severity,
36 pub fix: Option<Fix>, 36 pub fix: Option<Fix>,
37 pub unused: bool, 37 pub unused: bool,
38 pub code: Option<DiagnosticCode>,
38} 39}
39 40
40impl Diagnostic { 41impl Diagnostic {
41 fn error(range: TextRange, message: String) -> Self { 42 fn error(range: TextRange, message: String) -> Self {
42 Self { message, range, severity: Severity::Error, fix: None, unused: false } 43 Self { message, range, severity: Severity::Error, fix: None, unused: false, code: None }
43 } 44 }
44 45
45 fn hint(range: TextRange, message: String) -> Self { 46 fn hint(range: TextRange, message: String) -> Self {
46 Self { message, range, severity: Severity::WeakWarning, fix: None, unused: false } 47 Self {
48 message,
49 range,
50 severity: Severity::WeakWarning,
51 fix: None,
52 unused: false,
53 code: None,
54 }
47 } 55 }
48 56
49 fn with_fix(self, fix: Option<Fix>) -> Self { 57 fn with_fix(self, fix: Option<Fix>) -> Self {
@@ -53,6 +61,10 @@ impl Diagnostic {
53 fn with_unused(self, unused: bool) -> Self { 61 fn with_unused(self, unused: bool) -> Self {
54 Self { unused, ..self } 62 Self { unused, ..self }
55 } 63 }
64
65 fn with_code(self, code: Option<DiagnosticCode>) -> Self {
66 Self { code, ..self }
67 }
56} 68}
57 69
58#[derive(Debug)] 70#[derive(Debug)]
@@ -126,7 +138,8 @@ pub(crate) fn diagnostics(
126 // Override severity and mark as unused. 138 // Override severity and mark as unused.
127 res.borrow_mut().push( 139 res.borrow_mut().push(
128 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) 140 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
129 .with_unused(true), 141 .with_unused(true)
142 .with_code(Some(d.code())),
130 ); 143 );
131 }) 144 })
132 // Only collect experimental diagnostics when they're enabled. 145 // Only collect experimental diagnostics when they're enabled.
@@ -137,8 +150,10 @@ pub(crate) fn diagnostics(
137 let mut sink = sink_builder 150 let mut sink = sink_builder
138 // Diagnostics not handled above get no fix and default treatment. 151 // Diagnostics not handled above get no fix and default treatment.
139 .build(|d| { 152 .build(|d| {
140 res.borrow_mut() 153 res.borrow_mut().push(
141 .push(Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())); 154 Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())
155 .with_code(Some(d.code())),
156 );
142 }); 157 });
143 158
144 if let Some(m) = sema.to_module_def(file_id) { 159 if let Some(m) = sema.to_module_def(file_id) {
@@ -149,11 +164,15 @@ pub(crate) fn diagnostics(
149} 164}
150 165
151fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { 166fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
152 Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema)) 167 Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())
168 .with_fix(d.fix(&sema))
169 .with_code(Some(d.code()))
153} 170}
154 171
155fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { 172fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
156 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema)) 173 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
174 .with_fix(d.fix(&sema))
175 .with_code(Some(d.code()))
157} 176}
158 177
159fn check_unnecessary_braces_in_use_statement( 178fn check_unnecessary_braces_in_use_statement(
@@ -589,6 +608,11 @@ fn test_fn() {
589 }, 608 },
590 ), 609 ),
591 unused: false, 610 unused: false,
611 code: Some(
612 DiagnosticCode(
613 "unresolved-module",
614 ),
615 ),
592 }, 616 },
593 ] 617 ]
594 "#]], 618 "#]],
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs
index 459f201ed..5cbbe306e 100644
--- a/crates/ide/src/fn_references.rs
+++ b/crates/ide/src/fn_references.rs
@@ -1,11 +1,12 @@
1//! This module implements a methods and free functions search in the specified file. 1//! This module implements a methods and free functions search in the specified file.
2//! We have to skip tests, so cannot reuse file_structure module. 2//! We have to skip tests, so cannot reuse file_structure module.
3 3
4use assists::utils::test_related_attribute;
4use hir::Semantics; 5use hir::Semantics;
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
6use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode}; 7use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};
7 8
8use crate::{runnables::has_test_related_attribute, FileId, FileRange}; 9use crate::{FileId, FileRange};
9 10
10pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> { 11pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> {
11 let sema = Semantics::new(db); 12 let sema = Semantics::new(db);
@@ -15,7 +16,7 @@ pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRa
15 16
16fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> { 17fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> {
17 ast::Fn::cast(item).and_then(|fn_def| { 18 ast::Fn::cast(item).and_then(|fn_def| {
18 if has_test_related_attribute(&fn_def) { 19 if test_related_attribute(&fn_def).is_some() {
19 None 20 None
20 } else { 21 } else {
21 fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() }) 22 fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() })
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 2bd0e86e5..e15411777 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -1,5 +1,6 @@
1use std::fmt; 1use std::fmt;
2 2
3use assists::utils::test_related_attribute;
3use cfg::CfgExpr; 4use cfg::CfgExpr;
4use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; 5use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics};
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
@@ -156,7 +157,7 @@ fn runnable_fn(
156 None => TestId::Name(name_string), 157 None => TestId::Name(name_string),
157 }; 158 };
158 159
159 if has_test_related_attribute(&fn_def) { 160 if test_related_attribute(&fn_def).is_some() {
160 let attr = TestAttr::from_fn(&fn_def); 161 let attr = TestAttr::from_fn(&fn_def);
161 RunnableKind::Test { test_id, attr } 162 RunnableKind::Test { test_id, attr }
162 } else if fn_def.has_atom_attr("bench") { 163 } else if fn_def.has_atom_attr("bench") {
@@ -235,20 +236,6 @@ impl TestAttr {
235 } 236 }
236} 237}
237 238
238/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
239/// `#[test_case(...)]`, `#[tokio::test]` and similar.
240/// Also a regular `#[test]` annotation is supported.
241///
242/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
243/// but it's better than not to have the runnables for the tests at all.
244pub(crate) fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
245 fn_def
246 .attrs()
247 .filter_map(|attr| attr.path())
248 .map(|path| path.syntax().to_string().to_lowercase())
249 .any(|attribute_text| attribute_text.contains("test"))
250}
251
252const RUSTDOC_FENCE: &str = "```"; 239const RUSTDOC_FENCE: &str = "```";
253const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 240const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
254 &["", "rust", "should_panic", "edition2015", "edition2018"]; 241 &["", "rust", "should_panic", "edition2015", "edition2018"];
@@ -307,7 +294,7 @@ fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
307 for item in item_list.items() { 294 for item in item_list.items() {
308 match item { 295 match item {
309 ast::Item::Fn(f) => { 296 ast::Item::Fn(f) => {
310 if has_test_related_attribute(&f) { 297 if test_related_attribute(&f).is_some() {
311 return true; 298 return true;
312 } 299 }
313 } 300 }
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index b0e8863f6..f0a43eaf6 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -37,7 +37,7 @@ impl Sysroot {
37 pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ { 37 pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ {
38 // core is added as a dependency before std in order to 38 // core is added as a dependency before std in order to
39 // mimic rustcs dependency order 39 // mimic rustcs dependency order
40 vec!["core", "alloc", "std"].into_iter().filter_map(move |it| Some((it, self.by_name(it)?))) 40 ["core", "alloc", "std"].iter().filter_map(move |&it| Some((it, self.by_name(it)?)))
41 } 41 }
42 42
43 pub fn proc_macro(&self) -> Option<SysrootCrate> { 43 pub fn proc_macro(&self) -> Option<SysrootCrate> {
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 9ebb0a811..a71f96164 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -12,8 +12,8 @@ use proc_macro_api::ProcMacroClient;
12use rustc_hash::{FxHashMap, FxHashSet}; 12use rustc_hash::{FxHashMap, FxHashSet};
13 13
14use crate::{ 14use crate::{
15 cargo_workspace, cfg_flag::CfgFlag, utf8_stdout, CargoConfig, CargoWorkspace, ProjectJson, 15 cargo_workspace, cfg_flag::CfgFlag, sysroot::SysrootCrate, utf8_stdout, CargoConfig,
16 ProjectManifest, Sysroot, TargetKind, 16 CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind,
17}; 17};
18 18
19/// `PackageRoot` describes a package root folder. 19/// `PackageRoot` describes a package root folder.
@@ -70,12 +70,8 @@ impl ProjectWorkspace {
70 format!("Failed to deserialize json file {}", project_json.display()) 70 format!("Failed to deserialize json file {}", project_json.display())
71 })?; 71 })?;
72 let project_location = project_json.parent().unwrap().to_path_buf(); 72 let project_location = project_json.parent().unwrap().to_path_buf();
73 let project = ProjectJson::new(&project_location, data); 73 let project_json = ProjectJson::new(&project_location, data);
74 let sysroot = match &project.sysroot_src { 74 ProjectWorkspace::load_inline(project_json)?
75 Some(path) => Some(Sysroot::load(path)?),
76 None => None,
77 };
78 ProjectWorkspace::Json { project, sysroot }
79 } 75 }
80 ProjectManifest::CargoToml(cargo_toml) => { 76 ProjectManifest::CargoToml(cargo_toml) => {
81 let cargo_version = utf8_stdout({ 77 let cargo_version = utf8_stdout({
@@ -150,43 +146,38 @@ impl ProjectWorkspace {
150 }) 146 })
151 })) 147 }))
152 .collect::<Vec<_>>(), 148 .collect::<Vec<_>>(),
153 ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { 149 ProjectWorkspace::Cargo { cargo, sysroot, rustc } => cargo
154 let roots = cargo 150 .packages()
155 .packages() 151 .map(|pkg| {
156 .map(|pkg| { 152 let is_member = cargo[pkg].is_member;
157 let is_member = cargo[pkg].is_member; 153 let pkg_root = cargo[pkg].root().to_path_buf();
158 let pkg_root = cargo[pkg].root().to_path_buf(); 154
159 155 let mut include = vec![pkg_root.clone()];
160 let mut include = vec![pkg_root.clone()]; 156 include.extend(cargo[pkg].out_dir.clone());
161 include.extend(cargo[pkg].out_dir.clone()); 157
162 158 let mut exclude = vec![pkg_root.join(".git")];
163 let mut exclude = vec![pkg_root.join(".git")]; 159 if is_member {
164 if is_member { 160 exclude.push(pkg_root.join("target"));
165 exclude.push(pkg_root.join("target")); 161 } else {
166 } else { 162 exclude.push(pkg_root.join("tests"));
167 exclude.push(pkg_root.join("tests")); 163 exclude.push(pkg_root.join("examples"));
168 exclude.push(pkg_root.join("examples")); 164 exclude.push(pkg_root.join("benches"));
169 exclude.push(pkg_root.join("benches")); 165 }
170 } 166 PackageRoot { is_member, include, exclude }
171 PackageRoot { is_member, include, exclude } 167 })
172 }) 168 .chain(sysroot.crates().map(|krate| PackageRoot {
173 .chain(sysroot.crates().map(|krate| PackageRoot { 169 is_member: false,
170 include: vec![sysroot[krate].root_dir().to_path_buf()],
171 exclude: Vec::new(),
172 }))
173 .chain(rustc.into_iter().flat_map(|rustc| {
174 rustc.packages().map(move |krate| PackageRoot {
174 is_member: false, 175 is_member: false,
175 include: vec![sysroot[krate].root_dir().to_path_buf()], 176 include: vec![rustc[krate].root().to_path_buf()],
176 exclude: Vec::new(), 177 exclude: Vec::new(),
177 })); 178 })
178 if let Some(rustc_packages) = rustc { 179 }))
179 roots 180 .collect(),
180 .chain(rustc_packages.packages().map(|krate| PackageRoot {
181 is_member: false,
182 include: vec![rustc_packages[krate].root().to_path_buf()],
183 exclude: Vec::new(),
184 }))
185 .collect()
186 } else {
187 roots.collect()
188 }
189 }
190 } 181 }
191 } 182 }
192 183
@@ -206,312 +197,280 @@ impl ProjectWorkspace {
206 proc_macro_client: &ProcMacroClient, 197 proc_macro_client: &ProcMacroClient,
207 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 198 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
208 ) -> CrateGraph { 199 ) -> CrateGraph {
209 let mut crate_graph = CrateGraph::default(); 200 let mut crate_graph = match self {
210 match self {
211 ProjectWorkspace::Json { project, sysroot } => { 201 ProjectWorkspace::Json { project, sysroot } => {
212 let sysroot_dps = sysroot 202 project_json_to_crate_graph(target, proc_macro_client, load, project, sysroot)
213 .as_ref()
214 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
215
216 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
217 let crates: FxHashMap<_, _> = project
218 .crates()
219 .filter_map(|(crate_id, krate)| {
220 let file_path = &krate.root_module;
221 let file_id = match load(&file_path) {
222 Some(id) => id,
223 None => {
224 log::error!("failed to load crate root {}", file_path.display());
225 return None;
226 }
227 };
228
229 let env = krate.env.clone().into_iter().collect();
230 let proc_macro = krate
231 .proc_macro_dylib_path
232 .clone()
233 .map(|it| proc_macro_client.by_dylib_path(&it));
234
235 let target = krate.target.as_deref().or(target);
236 let target_cfgs = cfg_cache
237 .entry(target)
238 .or_insert_with(|| get_rustc_cfg_options(target));
239
240 let mut cfg_options = CfgOptions::default();
241 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
242
243 Some((
244 crate_id,
245 crate_graph.add_crate_root(
246 file_id,
247 krate.edition,
248 krate.display_name.clone(),
249 cfg_options,
250 env,
251 proc_macro.unwrap_or_default(),
252 ),
253 ))
254 })
255 .collect();
256
257 for (from, krate) in project.crates() {
258 if let Some(&from) = crates.get(&from) {
259 if let Some((public_deps, _proc_macro)) = &sysroot_dps {
260 for (name, to) in public_deps.iter() {
261 if let Err(_) = crate_graph.add_dep(from, name.clone(), *to) {
262 log::error!("cyclic dependency on {} for {:?}", name, from)
263 }
264 }
265 }
266
267 for dep in &krate.deps {
268 let to_crate_id = dep.crate_id;
269 if let Some(&to) = crates.get(&to_crate_id) {
270 if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) {
271 log::error!("cyclic dependency {:?} -> {:?}", from, to);
272 }
273 }
274 }
275 }
276 }
277 } 203 }
278 ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { 204 ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
279 let (public_deps, libproc_macro) = 205 cargo_to_crate_graph(target, proc_macro_client, load, cargo, sysroot, rustc)
280 sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); 206 }
207 };
208 if crate_graph.patch_cfg_if() {
209 log::debug!("Patched std to depend on cfg-if")
210 } else {
211 log::debug!("Did not patch std to depend on cfg-if")
212 }
213 crate_graph
214 }
215}
216
217fn project_json_to_crate_graph(
218 target: Option<&str>,
219 proc_macro_client: &ProcMacroClient,
220 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
221 project: &ProjectJson,
222 sysroot: &Option<Sysroot>,
223) -> CrateGraph {
224 let mut crate_graph = CrateGraph::default();
225 let sysroot_deps = sysroot
226 .as_ref()
227 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
228
229 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
230 let crates: FxHashMap<CrateId, CrateId> = project
231 .crates()
232 .filter_map(|(crate_id, krate)| {
233 let file_path = &krate.root_module;
234 let file_id = load(&file_path)?;
235 Some((crate_id, krate, file_id))
236 })
237 .map(|(crate_id, krate, file_id)| {
238 let env = krate.env.clone().into_iter().collect();
239 let proc_macro =
240 krate.proc_macro_dylib_path.clone().map(|it| proc_macro_client.by_dylib_path(&it));
241
242 let target = krate.target.as_deref().or(target);
243 let target_cfgs =
244 cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target));
245
246 let mut cfg_options = CfgOptions::default();
247 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
248 (
249 crate_id,
250 crate_graph.add_crate_root(
251 file_id,
252 krate.edition,
253 krate.display_name.clone(),
254 cfg_options,
255 env,
256 proc_macro.unwrap_or_default(),
257 ),
258 )
259 })
260 .collect();
281 261
282 let mut cfg_options = CfgOptions::default(); 262 for (from, krate) in project.crates() {
283 cfg_options.extend(get_rustc_cfg_options(target)); 263 if let Some(&from) = crates.get(&from) {
264 if let Some((public_deps, _proc_macro)) = &sysroot_deps {
265 for (name, to) in public_deps.iter() {
266 add_dep(&mut crate_graph, from, name.clone(), *to)
267 }
268 }
284 269
285 let mut pkg_to_lib_crate = FxHashMap::default(); 270 for dep in &krate.deps {
271 if let Some(&to) = crates.get(&dep.crate_id) {
272 add_dep(&mut crate_graph, from, dep.name.clone(), to)
273 }
274 }
275 }
276 }
277 crate_graph
278}
286 279
287 // Add test cfg for non-sysroot crates 280fn cargo_to_crate_graph(
288 cfg_options.insert_atom("test".into()); 281 target: Option<&str>,
289 cfg_options.insert_atom("debug_assertions".into()); 282 proc_macro_client: &ProcMacroClient,
283 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
284 cargo: &CargoWorkspace,
285 sysroot: &Sysroot,
286 rustc: &Option<CargoWorkspace>,
287) -> CrateGraph {
288 let mut crate_graph = CrateGraph::default();
289 let (public_deps, libproc_macro) =
290 sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
290 291
291 let mut pkg_crates = FxHashMap::default(); 292 let mut cfg_options = CfgOptions::default();
293 cfg_options.extend(get_rustc_cfg_options(target));
292 294
293 // Next, create crates for each package, target pair 295 let mut pkg_to_lib_crate = FxHashMap::default();
294 for pkg in cargo.packages() { 296
295 let mut lib_tgt = None; 297 // Add test cfg for non-sysroot crates
296 for &tgt in cargo[pkg].targets.iter() { 298 cfg_options.insert_atom("test".into());
297 if let Some(crate_id) = add_target_crate_root( 299 cfg_options.insert_atom("debug_assertions".into());
300
301 let mut pkg_crates = FxHashMap::default();
302
303 // Next, create crates for each package, target pair
304 for pkg in cargo.packages() {
305 let mut lib_tgt = None;
306 for &tgt in cargo[pkg].targets.iter() {
307 if let Some(file_id) = load(&cargo[tgt].root) {
308 let crate_id = add_target_crate_root(
309 &mut crate_graph,
310 &cargo[pkg],
311 &cfg_options,
312 proc_macro_client,
313 file_id,
314 );
315 if cargo[tgt].kind == TargetKind::Lib {
316 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
317 pkg_to_lib_crate.insert(pkg, crate_id);
318 }
319 if cargo[tgt].is_proc_macro {
320 if let Some(proc_macro) = libproc_macro {
321 add_dep(
298 &mut crate_graph, 322 &mut crate_graph,
299 &cargo[pkg], 323 crate_id,
300 &cargo[tgt], 324 CrateName::new("proc_macro").unwrap(),
301 &cfg_options, 325 proc_macro,
302 proc_macro_client, 326 );
303 load,
304 ) {
305 if cargo[tgt].kind == TargetKind::Lib {
306 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
307 pkg_to_lib_crate.insert(pkg, crate_id);
308 }
309 if cargo[tgt].is_proc_macro {
310 if let Some(proc_macro) = libproc_macro {
311 if let Err(_) = crate_graph.add_dep(
312 crate_id,
313 CrateName::new("proc_macro").unwrap(),
314 proc_macro,
315 ) {
316 log::error!(
317 "cyclic dependency on proc_macro for {}",
318 &cargo[pkg].name
319 )
320 }
321 }
322 }
323
324 pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
325 }
326 } 327 }
328 }
327 329
328 // Set deps to the core, std and to the lib target of the current package 330 pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
329 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 331 }
330 if let Some((to, name)) = lib_tgt.clone() { 332 }
331 // For root projects with dashes in their name, 333
332 // cargo metadata does not do any normalization, 334 // Set deps to the core, std and to the lib target of the current package
333 // so we do it ourselves currently 335 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
334 let name = CrateName::normalize_dashes(&name); 336 if let Some((to, name)) = lib_tgt.clone() {
335 if to != from && crate_graph.add_dep(from, name, to).is_err() { 337 if to != from {
336 log::error!( 338 // For root projects with dashes in their name,
337 "cyclic dependency between targets of {}", 339 // cargo metadata does not do any normalization,
338 &cargo[pkg].name 340 // so we do it ourselves currently
339 ) 341 let name = CrateName::normalize_dashes(&name);
340 } 342 add_dep(&mut crate_graph, from, name, to);
341 } 343 }
342 for (name, krate) in public_deps.iter() { 344 }
343 if let Err(_) = crate_graph.add_dep(from, name.clone(), *krate) { 345 for (name, krate) in public_deps.iter() {
344 log::error!( 346 add_dep(&mut crate_graph, from, name.clone(), *krate);
345 "cyclic dependency on {} for {}", 347 }
346 name, 348 }
347 &cargo[pkg].name 349 }
348 ) 350
349 } 351 // Now add a dep edge from all targets of upstream to the lib
350 } 352 // target of downstream.
351 } 353 for pkg in cargo.packages() {
354 for dep in cargo[pkg].dependencies.iter() {
355 let name = CrateName::new(&dep.name).unwrap();
356 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
357 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
358 add_dep(&mut crate_graph, from, name.clone(), to)
352 } 359 }
360 }
361 }
362 }
353 363
354 // Now add a dep edge from all targets of upstream to the lib 364 let mut rustc_pkg_crates = FxHashMap::default();
355 // target of downstream. 365
356 for pkg in cargo.packages() { 366 // If the user provided a path to rustc sources, we add all the rustc_private crates
357 for dep in cargo[pkg].dependencies.iter() { 367 // and create dependencies on them for the crates in the current workspace
358 let name = CrateName::new(&dep.name).unwrap(); 368 if let Some(rustc_workspace) = rustc {
359 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 369 for pkg in rustc_workspace.packages() {
360 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 370 for &tgt in rustc_workspace[pkg].targets.iter() {
361 if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { 371 if rustc_workspace[tgt].kind != TargetKind::Lib {
362 log::error!( 372 continue;
363 "cyclic dependency {} -> {}", 373 }
364 &cargo[pkg].name, 374 // Exclude alloc / core / std
365 &cargo[dep.pkg].name 375 if rustc_workspace[tgt]
366 ) 376 .root
367 } 377 .components()
368 } 378 .any(|c| c == Component::Normal("library".as_ref()))
369 } 379 {
370 } 380 continue;
371 } 381 }
372 382
373 let mut rustc_pkg_crates = FxHashMap::default(); 383 if let Some(file_id) = load(&rustc_workspace[tgt].root) {
374 384 let crate_id = add_target_crate_root(
375 // If the user provided a path to rustc sources, we add all the rustc_private crates 385 &mut crate_graph,
376 // and create dependencies on them for the crates in the current workspace 386 &rustc_workspace[pkg],
377 if let Some(rustc_workspace) = rustc { 387 &cfg_options,
378 for pkg in rustc_workspace.packages() { 388 proc_macro_client,
379 for &tgt in rustc_workspace[pkg].targets.iter() { 389 file_id,
380 if rustc_workspace[tgt].kind != TargetKind::Lib { 390 );
381 continue; 391 pkg_to_lib_crate.insert(pkg, crate_id);
382 } 392 // Add dependencies on the core / std / alloc for rustc
383 // Exclude alloc / core / std 393 for (name, krate) in public_deps.iter() {
384 if rustc_workspace[tgt] 394 add_dep(&mut crate_graph, crate_id, name.clone(), *krate);
385 .root
386 .components()
387 .any(|c| c == Component::Normal("library".as_ref()))
388 {
389 continue;
390 }
391
392 if let Some(crate_id) = add_target_crate_root(
393 &mut crate_graph,
394 &rustc_workspace[pkg],
395 &rustc_workspace[tgt],
396 &cfg_options,
397 proc_macro_client,
398 load,
399 ) {
400 pkg_to_lib_crate.insert(pkg, crate_id);
401 // Add dependencies on the core / std / alloc for rustc
402 for (name, krate) in public_deps.iter() {
403 if let Err(_) =
404 crate_graph.add_dep(crate_id, name.clone(), *krate)
405 {
406 log::error!(
407 "cyclic dependency on {} for {}",
408 name,
409 &cargo[pkg].name
410 )
411 }
412 }
413 rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
414 }
415 }
416 } 395 }
417 // Now add a dep edge from all targets of upstream to the lib 396 rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
418 // target of downstream. 397 }
419 for pkg in rustc_workspace.packages() { 398 }
420 for dep in rustc_workspace[pkg].dependencies.iter() { 399 }
421 let name = CrateName::new(&dep.name).unwrap(); 400 // Now add a dep edge from all targets of upstream to the lib
422 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 401 // target of downstream.
423 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { 402 for pkg in rustc_workspace.packages() {
424 if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { 403 for dep in rustc_workspace[pkg].dependencies.iter() {
425 log::error!( 404 let name = CrateName::new(&dep.name).unwrap();
426 "cyclic dependency {} -> {}", 405 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
427 &rustc_workspace[pkg].name, 406 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
428 &rustc_workspace[dep.pkg].name 407 add_dep(&mut crate_graph, from, name.clone(), to);
429 )
430 }
431 }
432 }
433 }
434 } 408 }
409 }
410 }
411 }
435 412
436 // Add dependencies for all the crates of the current workspace to rustc_private libraries 413 // Add dependencies for all the crates of the current workspace to rustc_private libraries
437 for dep in rustc_workspace.packages() { 414 for dep in rustc_workspace.packages() {
438 let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); 415 let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
439 416
440 if let Some(&to) = pkg_to_lib_crate.get(&dep) { 417 if let Some(&to) = pkg_to_lib_crate.get(&dep) {
441 for pkg in cargo.packages() { 418 for pkg in cargo.packages() {
442 if !cargo[pkg].is_member { 419 if !cargo[pkg].is_member {
443 continue; 420 continue;
444 } 421 }
445 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 422 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
446 if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { 423 add_dep(&mut crate_graph, from, name.clone(), to);
447 log::error!(
448 "cyclic dependency {} -> {}",
449 &cargo[pkg].name,
450 &rustc_workspace[dep].name
451 )
452 }
453 }
454 }
455 }
456 } 424 }
457 } 425 }
458 } 426 }
459 } 427 }
460 if crate_graph.patch_cfg_if() {
461 log::debug!("Patched std to depend on cfg-if")
462 } else {
463 log::debug!("Did not patch std to depend on cfg-if")
464 }
465 crate_graph
466 } 428 }
429 crate_graph
467} 430}
468 431
469fn add_target_crate_root( 432fn add_target_crate_root(
470 crate_graph: &mut CrateGraph, 433 crate_graph: &mut CrateGraph,
471 pkg: &cargo_workspace::PackageData, 434 pkg: &cargo_workspace::PackageData,
472 tgt: &cargo_workspace::TargetData,
473 cfg_options: &CfgOptions, 435 cfg_options: &CfgOptions,
474 proc_macro_client: &ProcMacroClient, 436 proc_macro_client: &ProcMacroClient,
475 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 437 file_id: FileId,
476) -> Option<CrateId> { 438) -> CrateId {
477 let root = tgt.root.as_path(); 439 let edition = pkg.edition;
478 if let Some(file_id) = load(root) { 440 let cfg_options = {
479 let edition = pkg.edition; 441 let mut opts = cfg_options.clone();
480 let cfg_options = { 442 for feature in pkg.features.iter() {
481 let mut opts = cfg_options.clone(); 443 opts.insert_key_value("feature".into(), feature.into());
482 for feature in pkg.features.iter() { 444 }
483 opts.insert_key_value("feature".into(), feature.into()); 445 opts.extend(pkg.cfgs.iter().cloned());
484 } 446 opts
485 opts.extend(pkg.cfgs.iter().cloned()); 447 };
486 opts 448 let mut env = Env::default();
487 }; 449 if let Some(out_dir) = &pkg.out_dir {
488 let mut env = Env::default(); 450 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
489 if let Some(out_dir) = &pkg.out_dir { 451 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
490 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() 452 env.set("OUT_DIR", out_dir);
491 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
492 env.set("OUT_DIR", out_dir);
493 }
494 } 453 }
495 let proc_macro = pkg
496 .proc_macro_dylib_path
497 .as_ref()
498 .map(|it| proc_macro_client.by_dylib_path(&it))
499 .unwrap_or_default();
500
501 let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone());
502 let crate_id = crate_graph.add_crate_root(
503 file_id,
504 edition,
505 Some(display_name),
506 cfg_options,
507 env,
508 proc_macro.clone(),
509 );
510
511 return Some(crate_id);
512 } 454 }
513 None 455 let proc_macro = pkg
456 .proc_macro_dylib_path
457 .as_ref()
458 .map(|it| proc_macro_client.by_dylib_path(&it))
459 .unwrap_or_default();
460
461 let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone());
462 let crate_id = crate_graph.add_crate_root(
463 file_id,
464 edition,
465 Some(display_name),
466 cfg_options,
467 env,
468 proc_macro.clone(),
469 );
470
471 crate_id
514} 472}
473
515fn sysroot_to_crate_graph( 474fn sysroot_to_crate_graph(
516 crate_graph: &mut CrateGraph, 475 crate_graph: &mut CrateGraph,
517 sysroot: &Sysroot, 476 sysroot: &Sysroot,
@@ -520,19 +479,18 @@ fn sysroot_to_crate_graph(
520) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { 479) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) {
521 let mut cfg_options = CfgOptions::default(); 480 let mut cfg_options = CfgOptions::default();
522 cfg_options.extend(get_rustc_cfg_options(target)); 481 cfg_options.extend(get_rustc_cfg_options(target));
523 let sysroot_crates: FxHashMap<_, _> = sysroot 482 let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
524 .crates() 483 .crates()
525 .filter_map(|krate| { 484 .filter_map(|krate| {
526 let file_id = load(&sysroot[krate].root)?; 485 let file_id = load(&sysroot[krate].root)?;
527 486
528 let env = Env::default(); 487 let env = Env::default();
529 let proc_macro = vec![]; 488 let proc_macro = vec![];
530 let name = CrateName::new(&sysroot[krate].name) 489 let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
531 .expect("Sysroot crates' names do not contain dashes");
532 let crate_id = crate_graph.add_crate_root( 490 let crate_id = crate_graph.add_crate_root(
533 file_id, 491 file_id,
534 Edition::Edition2018, 492 Edition::Edition2018,
535 Some(name.into()), 493 Some(display_name),
536 cfg_options.clone(), 494 cfg_options.clone(),
537 env, 495 env,
538 proc_macro, 496 proc_macro,
@@ -545,9 +503,7 @@ fn sysroot_to_crate_graph(
545 for &to in sysroot[from].deps.iter() { 503 for &to in sysroot[from].deps.iter() {
546 let name = CrateName::new(&sysroot[to].name).unwrap(); 504 let name = CrateName::new(&sysroot[to].name).unwrap();
547 if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { 505 if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
548 if let Err(_) = crate_graph.add_dep(from, name, to) { 506 add_dep(crate_graph, from, name, to);
549 log::error!("cyclic dependency between sysroot crates")
550 }
551 } 507 }
552 } 508 }
553 } 509 }
@@ -588,3 +544,9 @@ fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> {
588 544
589 res 545 res
590} 546}
547
548fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
549 if let Err(err) = graph.add_dep(from, name, to) {
550 log::error!("{}", err)
551 }
552}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index d25c4bf83..56c51486f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -21,7 +21,7 @@ env_logger = { version = "0.8.1", default-features = false }
21itertools = "0.9.0" 21itertools = "0.9.0"
22jod-thread = "0.1.0" 22jod-thread = "0.1.0"
23log = "0.4.8" 23log = "0.4.8"
24lsp-types = { version = "0.83.0", features = ["proposed"] } 24lsp-types = { version = "0.83.1", features = ["proposed"] }
25parking_lot = "0.11.0" 25parking_lot = "0.11.0"
26pico-args = "0.3.1" 26pico-args = "0.3.1"
27oorandom = "11.1.2" 27oorandom = "11.1.2"
@@ -31,7 +31,7 @@ serde_json = "1.0.48"
31threadpool = "1.7.1" 31threadpool = "1.7.1"
32rayon = "1.5" 32rayon = "1.5"
33mimalloc = { version = "0.1.19", default-features = false, optional = true } 33mimalloc = { version = "0.1.19", default-features = false, optional = true }
34lsp-server = "0.4.0" 34lsp-server = "0.5.0"
35tracing = "0.1" 35tracing = "0.1"
36tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 36tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
37tracing-tree = { version = "0.1.4" } 37tracing-tree = { version = "0.1.4" }
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 9a8870053..c7203451c 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -62,6 +62,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
62 prepare_provider: Some(true), 62 prepare_provider: Some(true),
63 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, 63 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
64 })), 64 })),
65 on_type_rename_provider: None,
65 document_link_provider: None, 66 document_link_provider: None,
66 color_provider: None, 67 color_provider: None,
67 execute_command_provider: None, 68 execute_command_provider: None,
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 15145415b..93bef5c8b 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -55,8 +55,8 @@ fn location_naive(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Lo
55 55
56 // FIXME: this doesn't handle UTF16 offsets correctly 56 // FIXME: this doesn't handle UTF16 offsets correctly
57 let range = lsp_types::Range::new( 57 let range = lsp_types::Range::new(
58 lsp_types::Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1), 58 lsp_types::Position::new(span.line_start as u32 - 1, span.column_start as u32 - 1),
59 lsp_types::Position::new(span.line_end as u64 - 1, span.column_end as u64 - 1), 59 lsp_types::Position::new(span.line_end as u32 - 1, span.column_end as u32 - 1),
60 ); 60 );
61 61
62 lsp_types::Location { uri, range } 62 lsp_types::Location { uri, range }
diff --git a/crates/rust-analyzer/src/document.rs b/crates/rust-analyzer/src/document.rs
index 04c7ee150..cf091510f 100644
--- a/crates/rust-analyzer/src/document.rs
+++ b/crates/rust-analyzer/src/document.rs
@@ -6,11 +6,11 @@
6/// client notifications. 6/// client notifications.
7#[derive(Debug, Clone)] 7#[derive(Debug, Clone)]
8pub(crate) struct DocumentData { 8pub(crate) struct DocumentData {
9 pub(crate) version: Option<i64>, 9 pub(crate) version: i32,
10} 10}
11 11
12impl DocumentData { 12impl DocumentData {
13 pub(crate) fn new(version: i64) -> Self { 13 pub(crate) fn new(version: i32) -> Self {
14 DocumentData { version: Some(version) } 14 DocumentData { version }
15 } 15 }
16} 16}
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 63c70a09d..defe11c55 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -263,9 +263,9 @@ impl GlobalStateSnapshot {
263 self.vfs.read().1[&id] 263 self.vfs.read().1[&id]
264 } 264 }
265 265
266 pub(crate) fn url_file_version(&self, url: &Url) -> Option<i64> { 266 pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
267 let path = from_proto::vfs_path(&url).ok()?; 267 let path = from_proto::vfs_path(&url).ok()?;
268 self.mem_docs.get(&path)?.version 268 Some(self.mem_docs.get(&path)?.version)
269 } 269 }
270 270
271 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url { 271 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url {
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index c27fd87d7..118e7276f 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -18,7 +18,7 @@ use lsp_types::{
18 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, 18 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
19 CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag, 19 CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag,
20 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, 20 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams,
21 HoverContents, Location, Position, PrepareRenameResponse, Range, RenameParams, 21 HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
22 SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, 22 SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
23 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, 23 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
24 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, 24 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
@@ -1128,7 +1128,7 @@ pub(crate) fn publish_diagnostics(
1128 .map(|d| Diagnostic { 1128 .map(|d| Diagnostic {
1129 range: to_proto::range(&line_index, d.range), 1129 range: to_proto::range(&line_index, d.range),
1130 severity: Some(to_proto::diagnostic_severity(d.severity)), 1130 severity: Some(to_proto::diagnostic_severity(d.severity)),
1131 code: None, 1131 code: d.code.map(|d| d.as_str().to_owned()).map(NumberOrString::String),
1132 code_description: None, 1132 code_description: None,
1133 source: Some("rust-analyzer".to_string()), 1133 source: Some("rust-analyzer".to_string()),
1134 message: d.message, 1134 message: d.message,
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index a5c65fa3e..93ac45415 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -302,7 +302,7 @@ pub enum SnippetDocumentChangeOperation {
302#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] 302#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
303#[serde(rename_all = "camelCase")] 303#[serde(rename_all = "camelCase")]
304pub struct SnippetTextDocumentEdit { 304pub struct SnippetTextDocumentEdit {
305 pub text_document: lsp_types::VersionedTextDocumentIdentifier, 305 pub text_document: lsp_types::OptionalVersionedTextDocumentIdentifier,
306 pub edits: Vec<SnippetTextEdit>, 306 pub edits: Vec<SnippetTextEdit>,
307} 307}
308 308
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index 1d271a9d8..6427c7367 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -51,7 +51,7 @@ impl GlobalState {
51 } 51 }
52 let percentage = fraction.map(|f| { 52 let percentage = fraction.map(|f| {
53 assert!(0.0 <= f && f <= 1.0); 53 assert!(0.0 <= f && f <= 1.0);
54 f * 100.0 54 (f * 100.0) as u32
55 }); 55 });
56 let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title)); 56 let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title));
57 let work_done_progress = match state { 57 let work_done_progress = match state {
@@ -98,11 +98,11 @@ pub(crate) fn apply_document_changes(
98 // The VFS will normalize the end of lines to `\n`. 98 // The VFS will normalize the end of lines to `\n`.
99 enum IndexValid { 99 enum IndexValid {
100 All, 100 All,
101 UpToLineExclusive(u64), 101 UpToLineExclusive(u32),
102 } 102 }
103 103
104 impl IndexValid { 104 impl IndexValid {
105 fn covers(&self, line: u64) -> bool { 105 fn covers(&self, line: u32) -> bool {
106 match *self { 106 match *self {
107 IndexValid::UpToLineExclusive(to) => to > line, 107 IndexValid::UpToLineExclusive(to) => to > line,
108 _ => true, 108 _ => true,
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 68a53bbcb..6ea08adce 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -368,7 +368,7 @@ impl GlobalState {
368 let url = file_id_to_url(&self.vfs.read().0, file_id); 368 let url = file_id_to_url(&self.vfs.read().0, file_id);
369 let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); 369 let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect();
370 let version = from_proto::vfs_path(&url) 370 let version = from_proto::vfs_path(&url)
371 .map(|path| self.mem_docs.get(&path)?.version) 371 .map(|path| self.mem_docs.get(&path).map(|it| it.version))
372 .unwrap_or_default(); 372 .unwrap_or_default();
373 373
374 self.send_notification::<lsp_types::notification::PublishDiagnostics>( 374 self.send_notification::<lsp_types::notification::PublishDiagnostics>(
@@ -521,7 +521,7 @@ impl GlobalState {
521 let mut version = None; 521 let mut version = None;
522 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 522 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
523 match this.mem_docs.remove(&path) { 523 match this.mem_docs.remove(&path) {
524 Some(doc) => version = doc.version, 524 Some(doc) => version = Some(doc.version),
525 None => log::error!("orphan DidCloseTextDocument: {}", path), 525 None => log::error!("orphan DidCloseTextDocument: {}", path),
526 } 526 }
527 527
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index fa6e09f42..001bf5949 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -203,7 +203,11 @@ impl GlobalState {
203 let contents = loader.handle.load_sync(path); 203 let contents = loader.handle.load_sync(path);
204 vfs.set_file_contents(vfs_path.clone(), contents); 204 vfs.set_file_contents(vfs_path.clone(), contents);
205 } 205 }
206 vfs.file_id(&vfs_path) 206 let res = vfs.file_id(&vfs_path);
207 if res.is_none() {
208 log::error!("failed to load {}", path.display())
209 }
210 res
207 }; 211 };
208 for ws in workspaces.iter() { 212 for ws in workspaces.iter() {
209 crate_graph.extend(ws.to_crate_graph( 213 crate_graph.extend(ws.to_crate_graph(
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 4bdf4bf0f..2f35425bb 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -21,9 +21,7 @@ use crate::{
21 21
22pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { 22pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
23 let line_col = line_index.line_col(offset); 23 let line_col = line_index.line_col(offset);
24 let line = u64::from(line_col.line); 24 lsp_types::Position::new(line_col.line, line_col.col_utf16)
25 let character = u64::from(line_col.col_utf16);
26 lsp_types::Position::new(line, character)
27} 25}
28 26
29pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { 27pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range {
@@ -278,9 +276,9 @@ pub(crate) fn signature_help(
278 label.push_str(", "); 276 label.push_str(", ");
279 } 277 }
280 first = false; 278 first = false;
281 let start = label.len() as u64; 279 let start = label.len() as u32;
282 label.push_str(param); 280 label.push_str(param);
283 let end = label.len() as u64; 281 let end = label.len() as u32;
284 params.push(lsp_types::ParameterInformation { 282 params.push(lsp_types::ParameterInformation {
285 label: lsp_types::ParameterLabel::LabelOffsets([start, end]), 283 label: lsp_types::ParameterLabel::LabelOffsets([start, end]),
286 documentation: None, 284 documentation: None,
@@ -302,7 +300,7 @@ pub(crate) fn signature_help(
302 }) 300 })
303 }; 301 };
304 302
305 let active_parameter = call_info.active_parameter.map(|it| it as i64); 303 let active_parameter = call_info.active_parameter.map(|it| it as u32);
306 304
307 let signature = lsp_types::SignatureInformation { 305 let signature = lsp_types::SignatureInformation {
308 label, 306 label,
@@ -518,13 +516,13 @@ pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url {
518 lsp_types::Url::parse(&url).unwrap() 516 lsp_types::Url::parse(&url).unwrap()
519} 517}
520 518
521pub(crate) fn versioned_text_document_identifier( 519pub(crate) fn optional_versioned_text_document_identifier(
522 snap: &GlobalStateSnapshot, 520 snap: &GlobalStateSnapshot,
523 file_id: FileId, 521 file_id: FileId,
524) -> lsp_types::VersionedTextDocumentIdentifier { 522) -> lsp_types::OptionalVersionedTextDocumentIdentifier {
525 let url = url(snap, file_id); 523 let url = url(snap, file_id);
526 let version = snap.url_file_version(&url); 524 let version = snap.url_file_version(&url);
527 lsp_types::VersionedTextDocumentIdentifier { uri: url, version } 525 lsp_types::OptionalVersionedTextDocumentIdentifier { uri: url, version }
528} 526}
529 527
530pub(crate) fn location( 528pub(crate) fn location(
@@ -613,7 +611,7 @@ pub(crate) fn snippet_text_document_edit(
613 is_snippet: bool, 611 is_snippet: bool,
614 source_file_edit: SourceFileEdit, 612 source_file_edit: SourceFileEdit,
615) -> Result<lsp_ext::SnippetTextDocumentEdit> { 613) -> Result<lsp_ext::SnippetTextDocumentEdit> {
616 let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id); 614 let text_document = optional_versioned_text_document_identifier(snap, source_file_edit.file_id);
617 let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?; 615 let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?;
618 let line_endings = snap.file_line_endings(source_file_edit.file_id); 616 let line_endings = snap.file_line_endings(source_file_edit.file_id);
619 let edits = source_file_edit 617 let edits = source_file_edit
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs
index b210b98f0..456125789 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/support.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs
@@ -108,7 +108,7 @@ pub(crate) fn project(fixture: &str) -> Server {
108} 108}
109 109
110pub(crate) struct Server { 110pub(crate) struct Server {
111 req_id: Cell<u64>, 111 req_id: Cell<i32>,
112 messages: RefCell<Vec<Message>>, 112 messages: RefCell<Vec<Message>>,
113 _thread: jod_thread::JoinHandle<()>, 113 _thread: jod_thread::JoinHandle<()>,
114 client: Connection, 114 client: Connection,
@@ -165,7 +165,7 @@ impl Server {
165 R::Params: Serialize, 165 R::Params: Serialize,
166 { 166 {
167 let id = self.req_id.get(); 167 let id = self.req_id.get();
168 self.req_id.set(id + 1); 168 self.req_id.set(id.wrapping_add(1));
169 169
170 let r = Request::new(id.into(), R::METHOD.to_string(), params); 170 let r = Request::new(id.into(), R::METHOD.to_string(), params);
171 self.send_request_(r) 171 self.send_request_(r)