diff options
Diffstat (limited to 'crates')
83 files changed, 3960 insertions, 3491 deletions
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 54baa3a63..d26f8f180 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -42,7 +42,7 @@ pub struct FilePosition { | |||
42 | pub offset: TextSize, | 42 | pub offset: TextSize, |
43 | } | 43 | } |
44 | 44 | ||
45 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 45 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] |
46 | pub struct FileRange { | 46 | pub struct FileRange { |
47 | pub file_id: FileId, | 47 | pub file_id: FileId, |
48 | pub range: TextRange, | 48 | pub range: TextRange, |
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 560b15238..7c148fd40 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml | |||
@@ -16,6 +16,7 @@ either = "1.5.3" | |||
16 | arrayvec = "0.7" | 16 | arrayvec = "0.7" |
17 | itertools = "0.10.0" | 17 | itertools = "0.10.0" |
18 | smallvec = "1.4.0" | 18 | smallvec = "1.4.0" |
19 | once_cell = "1" | ||
19 | 20 | ||
20 | stdx = { path = "../stdx", version = "0.0.0" } | 21 | stdx = { path = "../stdx", version = "0.0.0" } |
21 | syntax = { path = "../syntax", version = "0.0.0" } | 22 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 2cdbd172a..8a7c3a4fd 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -7,17 +7,12 @@ use std::any::Any; | |||
7 | 7 | ||
8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; | 8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; |
9 | use hir_def::path::ModPath; | 9 | use hir_def::path::ModPath; |
10 | use hir_expand::{HirFileId, InFile}; | 10 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use stdx::format_to; | 11 | use stdx::format_to; |
12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; | 12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
13 | 13 | ||
14 | pub use hir_ty::{ | 14 | pub use crate::diagnostics_sink::{ |
15 | diagnostics::{ | 15 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, |
16 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, | ||
17 | MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon, | ||
18 | ReplaceFilterMapNextWithFindMap, | ||
19 | }, | ||
20 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, | ||
21 | }; | 16 | }; |
22 | 17 | ||
23 | // Diagnostic: unresolved-module | 18 | // Diagnostic: unresolved-module |
@@ -251,3 +246,364 @@ impl Diagnostic for UnimplementedBuiltinMacro { | |||
251 | self | 246 | self |
252 | } | 247 | } |
253 | } | 248 | } |
249 | |||
250 | // Diagnostic: no-such-field | ||
251 | // | ||
252 | // This diagnostic is triggered if created structure does not have field provided in record. | ||
253 | #[derive(Debug)] | ||
254 | pub struct NoSuchField { | ||
255 | pub file: HirFileId, | ||
256 | pub field: AstPtr<ast::RecordExprField>, | ||
257 | } | ||
258 | |||
259 | impl Diagnostic for NoSuchField { | ||
260 | fn code(&self) -> DiagnosticCode { | ||
261 | DiagnosticCode("no-such-field") | ||
262 | } | ||
263 | |||
264 | fn message(&self) -> String { | ||
265 | "no such field".to_string() | ||
266 | } | ||
267 | |||
268 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
269 | InFile::new(self.file, self.field.clone().into()) | ||
270 | } | ||
271 | |||
272 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
273 | self | ||
274 | } | ||
275 | } | ||
276 | |||
277 | // Diagnostic: break-outside-of-loop | ||
278 | // | ||
279 | // This diagnostic is triggered if the `break` keyword is used outside of a loop. | ||
280 | #[derive(Debug)] | ||
281 | pub struct BreakOutsideOfLoop { | ||
282 | pub file: HirFileId, | ||
283 | pub expr: AstPtr<ast::Expr>, | ||
284 | } | ||
285 | |||
286 | impl Diagnostic for BreakOutsideOfLoop { | ||
287 | fn code(&self) -> DiagnosticCode { | ||
288 | DiagnosticCode("break-outside-of-loop") | ||
289 | } | ||
290 | fn message(&self) -> String { | ||
291 | "break outside of loop".to_string() | ||
292 | } | ||
293 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
294 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
295 | } | ||
296 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
297 | self | ||
298 | } | ||
299 | } | ||
300 | |||
301 | // Diagnostic: missing-unsafe | ||
302 | // | ||
303 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | ||
304 | #[derive(Debug)] | ||
305 | pub struct MissingUnsafe { | ||
306 | pub file: HirFileId, | ||
307 | pub expr: AstPtr<ast::Expr>, | ||
308 | } | ||
309 | |||
310 | impl Diagnostic for MissingUnsafe { | ||
311 | fn code(&self) -> DiagnosticCode { | ||
312 | DiagnosticCode("missing-unsafe") | ||
313 | } | ||
314 | fn message(&self) -> String { | ||
315 | format!("This operation is unsafe and requires an unsafe function or block") | ||
316 | } | ||
317 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
318 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
319 | } | ||
320 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
321 | self | ||
322 | } | ||
323 | } | ||
324 | |||
325 | // Diagnostic: missing-structure-fields | ||
326 | // | ||
327 | // This diagnostic is triggered if record lacks some fields that exist in the corresponding structure. | ||
328 | // | ||
329 | // Example: | ||
330 | // | ||
331 | // ```rust | ||
332 | // struct A { a: u8, b: u8 } | ||
333 | // | ||
334 | // let a = A { a: 10 }; | ||
335 | // ``` | ||
336 | #[derive(Debug)] | ||
337 | pub struct MissingFields { | ||
338 | pub file: HirFileId, | ||
339 | pub field_list_parent: AstPtr<ast::RecordExpr>, | ||
340 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
341 | pub missed_fields: Vec<Name>, | ||
342 | } | ||
343 | |||
344 | impl Diagnostic for MissingFields { | ||
345 | fn code(&self) -> DiagnosticCode { | ||
346 | DiagnosticCode("missing-structure-fields") | ||
347 | } | ||
348 | fn message(&self) -> String { | ||
349 | let mut buf = String::from("Missing structure fields:\n"); | ||
350 | for field in &self.missed_fields { | ||
351 | format_to!(buf, "- {}\n", field); | ||
352 | } | ||
353 | buf | ||
354 | } | ||
355 | |||
356 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
357 | InFile { | ||
358 | file_id: self.file, | ||
359 | value: self | ||
360 | .field_list_parent_path | ||
361 | .clone() | ||
362 | .map(SyntaxNodePtr::from) | ||
363 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
364 | } | ||
365 | } | ||
366 | |||
367 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
368 | self | ||
369 | } | ||
370 | } | ||
371 | |||
372 | // Diagnostic: missing-pat-fields | ||
373 | // | ||
374 | // This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure. | ||
375 | // | ||
376 | // Example: | ||
377 | // | ||
378 | // ```rust | ||
379 | // struct A { a: u8, b: u8 } | ||
380 | // | ||
381 | // let a = A { a: 10, b: 20 }; | ||
382 | // | ||
383 | // if let A { a } = a { | ||
384 | // // ... | ||
385 | // } | ||
386 | // ``` | ||
387 | #[derive(Debug)] | ||
388 | pub struct MissingPatFields { | ||
389 | pub file: HirFileId, | ||
390 | pub field_list_parent: AstPtr<ast::RecordPat>, | ||
391 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
392 | pub missed_fields: Vec<Name>, | ||
393 | } | ||
394 | |||
395 | impl Diagnostic for MissingPatFields { | ||
396 | fn code(&self) -> DiagnosticCode { | ||
397 | DiagnosticCode("missing-pat-fields") | ||
398 | } | ||
399 | fn message(&self) -> String { | ||
400 | let mut buf = String::from("Missing structure fields:\n"); | ||
401 | for field in &self.missed_fields { | ||
402 | format_to!(buf, "- {}\n", field); | ||
403 | } | ||
404 | buf | ||
405 | } | ||
406 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
407 | InFile { | ||
408 | file_id: self.file, | ||
409 | value: self | ||
410 | .field_list_parent_path | ||
411 | .clone() | ||
412 | .map(SyntaxNodePtr::from) | ||
413 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
414 | } | ||
415 | } | ||
416 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
417 | self | ||
418 | } | ||
419 | } | ||
420 | |||
421 | // Diagnostic: replace-filter-map-next-with-find-map | ||
422 | // | ||
423 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. | ||
424 | #[derive(Debug)] | ||
425 | pub struct ReplaceFilterMapNextWithFindMap { | ||
426 | pub file: HirFileId, | ||
427 | /// This expression is the whole method chain up to and including `.filter_map(..).next()`. | ||
428 | pub next_expr: AstPtr<ast::Expr>, | ||
429 | } | ||
430 | |||
431 | impl Diagnostic for ReplaceFilterMapNextWithFindMap { | ||
432 | fn code(&self) -> DiagnosticCode { | ||
433 | DiagnosticCode("replace-filter-map-next-with-find-map") | ||
434 | } | ||
435 | fn message(&self) -> String { | ||
436 | "replace filter_map(..).next() with find_map(..)".to_string() | ||
437 | } | ||
438 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
439 | InFile { file_id: self.file, value: self.next_expr.clone().into() } | ||
440 | } | ||
441 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
442 | self | ||
443 | } | ||
444 | } | ||
445 | |||
446 | // Diagnostic: mismatched-arg-count | ||
447 | // | ||
448 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | ||
449 | #[derive(Debug)] | ||
450 | pub struct MismatchedArgCount { | ||
451 | pub file: HirFileId, | ||
452 | pub call_expr: AstPtr<ast::Expr>, | ||
453 | pub expected: usize, | ||
454 | pub found: usize, | ||
455 | } | ||
456 | |||
457 | impl Diagnostic for MismatchedArgCount { | ||
458 | fn code(&self) -> DiagnosticCode { | ||
459 | DiagnosticCode("mismatched-arg-count") | ||
460 | } | ||
461 | fn message(&self) -> String { | ||
462 | let s = if self.expected == 1 { "" } else { "s" }; | ||
463 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | ||
464 | } | ||
465 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
466 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | ||
467 | } | ||
468 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
469 | self | ||
470 | } | ||
471 | fn is_experimental(&self) -> bool { | ||
472 | true | ||
473 | } | ||
474 | } | ||
475 | |||
476 | #[derive(Debug)] | ||
477 | pub struct RemoveThisSemicolon { | ||
478 | pub file: HirFileId, | ||
479 | pub expr: AstPtr<ast::Expr>, | ||
480 | } | ||
481 | |||
482 | impl Diagnostic for RemoveThisSemicolon { | ||
483 | fn code(&self) -> DiagnosticCode { | ||
484 | DiagnosticCode("remove-this-semicolon") | ||
485 | } | ||
486 | |||
487 | fn message(&self) -> String { | ||
488 | "Remove this semicolon".to_string() | ||
489 | } | ||
490 | |||
491 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
492 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
493 | } | ||
494 | |||
495 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
496 | self | ||
497 | } | ||
498 | } | ||
499 | |||
500 | // Diagnostic: missing-ok-or-some-in-tail-expr | ||
501 | // | ||
502 | // This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`, | ||
503 | // or if a block that should return `Option` returns a value not wrapped in `Some`. | ||
504 | // | ||
505 | // Example: | ||
506 | // | ||
507 | // ```rust | ||
508 | // fn foo() -> Result<u8, ()> { | ||
509 | // 10 | ||
510 | // } | ||
511 | // ``` | ||
512 | #[derive(Debug)] | ||
513 | pub struct MissingOkOrSomeInTailExpr { | ||
514 | pub file: HirFileId, | ||
515 | pub expr: AstPtr<ast::Expr>, | ||
516 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
517 | pub required: String, | ||
518 | } | ||
519 | |||
520 | impl Diagnostic for MissingOkOrSomeInTailExpr { | ||
521 | fn code(&self) -> DiagnosticCode { | ||
522 | DiagnosticCode("missing-ok-or-some-in-tail-expr") | ||
523 | } | ||
524 | fn message(&self) -> String { | ||
525 | format!("wrap return expression in {}", self.required) | ||
526 | } | ||
527 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
528 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
529 | } | ||
530 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
531 | self | ||
532 | } | ||
533 | } | ||
534 | |||
535 | // Diagnostic: missing-match-arm | ||
536 | // | ||
537 | // This diagnostic is triggered if `match` block is missing one or more match arms. | ||
538 | #[derive(Debug)] | ||
539 | pub struct MissingMatchArms { | ||
540 | pub file: HirFileId, | ||
541 | pub match_expr: AstPtr<ast::Expr>, | ||
542 | pub arms: AstPtr<ast::MatchArmList>, | ||
543 | } | ||
544 | |||
545 | impl Diagnostic for MissingMatchArms { | ||
546 | fn code(&self) -> DiagnosticCode { | ||
547 | DiagnosticCode("missing-match-arm") | ||
548 | } | ||
549 | fn message(&self) -> String { | ||
550 | String::from("Missing match arm") | ||
551 | } | ||
552 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
553 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | ||
554 | } | ||
555 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
556 | self | ||
557 | } | ||
558 | } | ||
559 | |||
560 | #[derive(Debug)] | ||
561 | pub struct InternalBailedOut { | ||
562 | pub file: HirFileId, | ||
563 | pub pat_syntax_ptr: SyntaxNodePtr, | ||
564 | } | ||
565 | |||
566 | impl Diagnostic for InternalBailedOut { | ||
567 | fn code(&self) -> DiagnosticCode { | ||
568 | DiagnosticCode("internal:match-check-bailed-out") | ||
569 | } | ||
570 | fn message(&self) -> String { | ||
571 | format!("Internal: match check bailed out") | ||
572 | } | ||
573 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
574 | InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() } | ||
575 | } | ||
576 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
577 | self | ||
578 | } | ||
579 | } | ||
580 | |||
581 | pub use hir_ty::diagnostics::IncorrectCase; | ||
582 | |||
583 | impl Diagnostic for IncorrectCase { | ||
584 | fn code(&self) -> DiagnosticCode { | ||
585 | DiagnosticCode("incorrect-ident-case") | ||
586 | } | ||
587 | |||
588 | fn message(&self) -> String { | ||
589 | format!( | ||
590 | "{} `{}` should have {} name, e.g. `{}`", | ||
591 | self.ident_type, | ||
592 | self.ident_text, | ||
593 | self.expected_case.to_string(), | ||
594 | self.suggested_text | ||
595 | ) | ||
596 | } | ||
597 | |||
598 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
599 | InFile::new(self.file, self.ident.clone().into()) | ||
600 | } | ||
601 | |||
602 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
603 | self | ||
604 | } | ||
605 | |||
606 | fn is_experimental(&self) -> bool { | ||
607 | true | ||
608 | } | ||
609 | } | ||
diff --git a/crates/hir_ty/src/diagnostics_sink.rs b/crates/hir/src/diagnostics_sink.rs index 084fa8b06..084fa8b06 100644 --- a/crates/hir_ty/src/diagnostics_sink.rs +++ b/crates/hir/src/diagnostics_sink.rs | |||
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index b9c1dc44d..2468c0dc6 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -27,6 +27,7 @@ mod attrs; | |||
27 | mod has_source; | 27 | mod has_source; |
28 | 28 | ||
29 | pub mod diagnostics; | 29 | pub mod diagnostics; |
30 | pub mod diagnostics_sink; | ||
30 | pub mod db; | 31 | pub mod db; |
31 | 32 | ||
32 | mod display; | 33 | mod display; |
@@ -35,14 +36,10 @@ use std::{iter, sync::Arc}; | |||
35 | 36 | ||
36 | use arrayvec::ArrayVec; | 37 | use arrayvec::ArrayVec; |
37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 38 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
38 | use diagnostics::{ | ||
39 | InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, | ||
40 | UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | ||
41 | }; | ||
42 | use either::Either; | 39 | use either::Either; |
43 | use hir_def::{ | 40 | use hir_def::{ |
44 | adt::{ReprKind, VariantData}, | 41 | adt::{ReprKind, VariantData}, |
45 | body::BodyDiagnostic, | 42 | body::{BodyDiagnostic, SyntheticSyntax}, |
46 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 43 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
47 | item_tree::ItemTreeNode, | 44 | item_tree::ItemTreeNode, |
48 | lang_item::LangItemTarget, | 45 | lang_item::LangItemTarget, |
@@ -60,8 +57,8 @@ use hir_ty::{ | |||
60 | autoderef, | 57 | autoderef, |
61 | consteval::ConstExt, | 58 | consteval::ConstExt, |
62 | could_unify, | 59 | could_unify, |
63 | diagnostics_sink::DiagnosticSink, | 60 | diagnostics::BodyValidationDiagnostic, |
64 | method_resolution::{self, def_crates, TyFingerprint}, | 61 | method_resolution::{self, TyFingerprint}, |
65 | primitive::UintTy, | 62 | primitive::UintTy, |
66 | subst_prefix, | 63 | subst_prefix, |
67 | traits::FnTrait, | 64 | traits::FnTrait, |
@@ -72,6 +69,7 @@ use hir_ty::{ | |||
72 | }; | 69 | }; |
73 | use itertools::Itertools; | 70 | use itertools::Itertools; |
74 | use nameres::diagnostics::DefDiagnosticKind; | 71 | use nameres::diagnostics::DefDiagnosticKind; |
72 | use once_cell::unsync::Lazy; | ||
75 | use rustc_hash::FxHashSet; | 73 | use rustc_hash::FxHashSet; |
76 | use stdx::{format_to, impl_from}; | 74 | use stdx::{format_to, impl_from}; |
77 | use syntax::{ | 75 | use syntax::{ |
@@ -80,7 +78,17 @@ use syntax::{ | |||
80 | }; | 78 | }; |
81 | use tt::{Ident, Leaf, Literal, TokenTree}; | 79 | use tt::{Ident, Leaf, Literal, TokenTree}; |
82 | 80 | ||
83 | use crate::db::{DefDatabase, HirDatabase}; | 81 | use crate::{ |
82 | db::{DefDatabase, HirDatabase}, | ||
83 | diagnostics::{ | ||
84 | BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount, | ||
85 | MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, MissingPatFields, | ||
86 | MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | ||
87 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | ||
88 | UnresolvedModule, UnresolvedProcMacro, | ||
89 | }, | ||
90 | diagnostics_sink::DiagnosticSink, | ||
91 | }; | ||
84 | 92 | ||
85 | pub use crate::{ | 93 | pub use crate::{ |
86 | attrs::{HasAttrs, Namespace}, | 94 | attrs::{HasAttrs, Namespace}, |
@@ -353,7 +361,9 @@ impl ModuleDef { | |||
353 | None => return, | 361 | None => return, |
354 | }; | 362 | }; |
355 | 363 | ||
356 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | 364 | for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) { |
365 | sink.push(diag) | ||
366 | } | ||
357 | } | 367 | } |
358 | } | 368 | } |
359 | 369 | ||
@@ -445,7 +455,12 @@ impl Module { | |||
445 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | 455 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) |
446 | } | 456 | } |
447 | 457 | ||
448 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 458 | pub fn diagnostics( |
459 | self, | ||
460 | db: &dyn HirDatabase, | ||
461 | sink: &mut DiagnosticSink, | ||
462 | internal_diagnostics: bool, | ||
463 | ) { | ||
449 | let _p = profile::span("Module::diagnostics").detail(|| { | 464 | let _p = profile::span("Module::diagnostics").detail(|| { |
450 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 465 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
451 | }); | 466 | }); |
@@ -591,11 +606,11 @@ impl Module { | |||
591 | } | 606 | } |
592 | for decl in self.declarations(db) { | 607 | for decl in self.declarations(db) { |
593 | match decl { | 608 | match decl { |
594 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 609 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink, internal_diagnostics), |
595 | crate::ModuleDef::Module(m) => { | 610 | crate::ModuleDef::Module(m) => { |
596 | // Only add diagnostics from inline modules | 611 | // Only add diagnostics from inline modules |
597 | if def_map[m.id.local_id].origin.is_inline() { | 612 | if def_map[m.id.local_id].origin.is_inline() { |
598 | m.diagnostics(db, sink) | 613 | m.diagnostics(db, sink, internal_diagnostics) |
599 | } | 614 | } |
600 | } | 615 | } |
601 | _ => { | 616 | _ => { |
@@ -607,7 +622,7 @@ impl Module { | |||
607 | for impl_def in self.impl_defs(db) { | 622 | for impl_def in self.impl_defs(db) { |
608 | for item in impl_def.items(db) { | 623 | for item in impl_def.items(db) { |
609 | if let AssocItem::Function(f) = item { | 624 | if let AssocItem::Function(f) = item { |
610 | f.diagnostics(db, sink); | 625 | f.diagnostics(db, sink, internal_diagnostics); |
611 | } | 626 | } |
612 | } | 627 | } |
613 | } | 628 | } |
@@ -1009,7 +1024,12 @@ impl Function { | |||
1009 | db.function_data(self.id).is_async() | 1024 | db.function_data(self.id).is_async() |
1010 | } | 1025 | } |
1011 | 1026 | ||
1012 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1027 | pub fn diagnostics( |
1028 | self, | ||
1029 | db: &dyn HirDatabase, | ||
1030 | sink: &mut DiagnosticSink, | ||
1031 | internal_diagnostics: bool, | ||
1032 | ) { | ||
1013 | let krate = self.module(db).id.krate(); | 1033 | let krate = self.module(db).id.krate(); |
1014 | 1034 | ||
1015 | let source_map = db.body_with_source_map(self.id.into()).1; | 1035 | let source_map = db.body_with_source_map(self.id.into()).1; |
@@ -1042,8 +1062,174 @@ impl Function { | |||
1042 | } | 1062 | } |
1043 | } | 1063 | } |
1044 | 1064 | ||
1045 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1065 | let infer = db.infer(self.id.into()); |
1046 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | 1066 | let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1); |
1067 | for d in &infer.diagnostics { | ||
1068 | match d { | ||
1069 | hir_ty::InferenceDiagnostic::NoSuchField { expr } => { | ||
1070 | let field = source_map.field_syntax(*expr); | ||
1071 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | ||
1072 | } | ||
1073 | hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
1074 | let ptr = source_map | ||
1075 | .expr_syntax(*expr) | ||
1076 | .expect("break outside of loop in synthetic syntax"); | ||
1077 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
1078 | } | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { | ||
1083 | match source_map.expr_syntax(expr) { | ||
1084 | Ok(in_file) => { | ||
1085 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | ||
1086 | } | ||
1087 | Err(SyntheticSyntax) => { | ||
1088 | // FIXME: Here and eslwhere in this file, the `expr` was | ||
1089 | // desugared, report or assert that this doesn't happen. | ||
1090 | } | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | for diagnostic in | ||
1095 | BodyValidationDiagnostic::collect(db, self.id.into(), internal_diagnostics) | ||
1096 | { | ||
1097 | match diagnostic { | ||
1098 | BodyValidationDiagnostic::RecordLiteralMissingFields { | ||
1099 | record_expr, | ||
1100 | variant, | ||
1101 | missed_fields, | ||
1102 | } => match source_map.expr_syntax(record_expr) { | ||
1103 | Ok(source_ptr) => { | ||
1104 | let root = source_ptr.file_syntax(db.upcast()); | ||
1105 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) | ||
1106 | { | ||
1107 | if let Some(_) = record_expr.record_expr_field_list() { | ||
1108 | let variant_data = variant.variant_data(db.upcast()); | ||
1109 | let missed_fields = missed_fields | ||
1110 | .into_iter() | ||
1111 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1112 | .collect(); | ||
1113 | sink.push(MissingFields { | ||
1114 | file: source_ptr.file_id, | ||
1115 | field_list_parent: AstPtr::new(&record_expr), | ||
1116 | field_list_parent_path: record_expr | ||
1117 | .path() | ||
1118 | .map(|path| AstPtr::new(&path)), | ||
1119 | missed_fields, | ||
1120 | }) | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | Err(SyntheticSyntax) => (), | ||
1125 | }, | ||
1126 | BodyValidationDiagnostic::RecordPatMissingFields { | ||
1127 | record_pat, | ||
1128 | variant, | ||
1129 | missed_fields, | ||
1130 | } => match source_map.pat_syntax(record_pat) { | ||
1131 | Ok(source_ptr) => { | ||
1132 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
1133 | let root = source_ptr.file_syntax(db.upcast()); | ||
1134 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
1135 | if let Some(_) = record_pat.record_pat_field_list() { | ||
1136 | let variant_data = variant.variant_data(db.upcast()); | ||
1137 | let missed_fields = missed_fields | ||
1138 | .into_iter() | ||
1139 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1140 | .collect(); | ||
1141 | sink.push(MissingPatFields { | ||
1142 | file: source_ptr.file_id, | ||
1143 | field_list_parent: AstPtr::new(&record_pat), | ||
1144 | field_list_parent_path: record_pat | ||
1145 | .path() | ||
1146 | .map(|path| AstPtr::new(&path)), | ||
1147 | missed_fields, | ||
1148 | }) | ||
1149 | } | ||
1150 | } | ||
1151 | } | ||
1152 | } | ||
1153 | Err(SyntheticSyntax) => (), | ||
1154 | }, | ||
1155 | |||
1156 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { | ||
1157 | if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { | ||
1158 | sink.push(ReplaceFilterMapNextWithFindMap { | ||
1159 | file: next_source_ptr.file_id, | ||
1160 | next_expr: next_source_ptr.value, | ||
1161 | }); | ||
1162 | } | ||
1163 | } | ||
1164 | BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { | ||
1165 | match source_map.expr_syntax(call_expr) { | ||
1166 | Ok(source_ptr) => sink.push(MismatchedArgCount { | ||
1167 | file: source_ptr.file_id, | ||
1168 | call_expr: source_ptr.value, | ||
1169 | expected, | ||
1170 | found, | ||
1171 | }), | ||
1172 | Err(SyntheticSyntax) => (), | ||
1173 | } | ||
1174 | } | ||
1175 | BodyValidationDiagnostic::RemoveThisSemicolon { expr } => { | ||
1176 | match source_map.expr_syntax(expr) { | ||
1177 | Ok(source_ptr) => sink.push(RemoveThisSemicolon { | ||
1178 | file: source_ptr.file_id, | ||
1179 | expr: source_ptr.value, | ||
1180 | }), | ||
1181 | Err(SyntheticSyntax) => (), | ||
1182 | } | ||
1183 | } | ||
1184 | BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => { | ||
1185 | match source_map.expr_syntax(expr) { | ||
1186 | Ok(source_ptr) => sink.push(MissingOkOrSomeInTailExpr { | ||
1187 | file: source_ptr.file_id, | ||
1188 | expr: source_ptr.value, | ||
1189 | required, | ||
1190 | }), | ||
1191 | Err(SyntheticSyntax) => (), | ||
1192 | } | ||
1193 | } | ||
1194 | BodyValidationDiagnostic::MissingMatchArms { match_expr } => { | ||
1195 | match source_map.expr_syntax(match_expr) { | ||
1196 | Ok(source_ptr) => { | ||
1197 | let root = source_ptr.file_syntax(db.upcast()); | ||
1198 | if let ast::Expr::MatchExpr(match_expr) = | ||
1199 | &source_ptr.value.to_node(&root) | ||
1200 | { | ||
1201 | if let (Some(match_expr), Some(arms)) = | ||
1202 | (match_expr.expr(), match_expr.match_arm_list()) | ||
1203 | { | ||
1204 | sink.push(MissingMatchArms { | ||
1205 | file: source_ptr.file_id, | ||
1206 | match_expr: AstPtr::new(&match_expr), | ||
1207 | arms: AstPtr::new(&arms), | ||
1208 | }) | ||
1209 | } | ||
1210 | } | ||
1211 | } | ||
1212 | Err(SyntheticSyntax) => (), | ||
1213 | } | ||
1214 | } | ||
1215 | BodyValidationDiagnostic::InternalBailedOut { pat } => { | ||
1216 | match source_map.pat_syntax(pat) { | ||
1217 | Ok(source_ptr) => { | ||
1218 | let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into); | ||
1219 | sink.push(InternalBailedOut { | ||
1220 | file: source_ptr.file_id, | ||
1221 | pat_syntax_ptr, | ||
1222 | }); | ||
1223 | } | ||
1224 | Err(SyntheticSyntax) => (), | ||
1225 | } | ||
1226 | } | ||
1227 | } | ||
1228 | } | ||
1229 | |||
1230 | for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) { | ||
1231 | sink.push(diag) | ||
1232 | } | ||
1047 | } | 1233 | } |
1048 | 1234 | ||
1049 | /// Whether this function declaration has a definition. | 1235 | /// Whether this function declaration has a definition. |
@@ -1451,6 +1637,20 @@ impl AssocItem { | |||
1451 | _ => None, | 1637 | _ => None, |
1452 | } | 1638 | } |
1453 | } | 1639 | } |
1640 | |||
1641 | pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1642 | match self.container(db) { | ||
1643 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1644 | _ => None, | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1649 | match self.container(db) { | ||
1650 | AssocItemContainer::Trait(t) => Some(t), | ||
1651 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1652 | } | ||
1653 | } | ||
1454 | } | 1654 | } |
1455 | 1655 | ||
1456 | impl HasVisibility for AssocItem { | 1656 | impl HasVisibility for AssocItem { |
@@ -1748,7 +1948,7 @@ impl Impl { | |||
1748 | } | 1948 | } |
1749 | 1949 | ||
1750 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { | 1950 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { |
1751 | let def_crates = match def_crates(db, &ty, krate) { | 1951 | let def_crates = match method_resolution::def_crates(db, &ty, krate) { |
1752 | Some(def_crates) => def_crates, | 1952 | Some(def_crates) => def_crates, |
1753 | None => return Vec::new(), | 1953 | None => return Vec::new(), |
1754 | }; | 1954 | }; |
@@ -2154,7 +2354,7 @@ impl Type { | |||
2154 | krate: Crate, | 2354 | krate: Crate, |
2155 | mut callback: impl FnMut(AssocItem) -> Option<T>, | 2355 | mut callback: impl FnMut(AssocItem) -> Option<T>, |
2156 | ) -> Option<T> { | 2356 | ) -> Option<T> { |
2157 | for krate in def_crates(db, &self.ty, krate.id)? { | 2357 | for krate in method_resolution::def_crates(db, &self.ty, krate.id)? { |
2158 | let impls = db.inherent_impls_in_crate(krate); | 2358 | let impls = db.inherent_impls_in_crate(krate); |
2159 | 2359 | ||
2160 | for impl_def in impls.for_self_ty(&self.ty) { | 2360 | for impl_def in impls.for_self_ty(&self.ty) { |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 43324d8d9..bb86f6a73 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | dashmap = { version = "4.0.2", features = ["raw-api"] } | 14 | dashmap = { version = "4.0.2", features = ["raw-api"] } |
15 | log = "0.4.8" | 15 | log = "0.4.8" |
16 | once_cell = "1.3.1" | 16 | once_cell = "1.3.1" |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 3886b6c04..d9f9fadc1 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -106,7 +106,9 @@ impl RawAttrs { | |||
106 | ) -> Self { | 106 | ) -> Self { |
107 | let entries = collect_attrs(owner) | 107 | let entries = collect_attrs(owner) |
108 | .flat_map(|(id, attr)| match attr { | 108 | .flat_map(|(id, attr)| match attr { |
109 | Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), | 109 | Either::Left(attr) => { |
110 | attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id)) | ||
111 | } | ||
110 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 112 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
111 | id, | 113 | id, |
112 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), | 114 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), |
@@ -172,10 +174,9 @@ impl RawAttrs { | |||
172 | let index = attr.id; | 174 | let index = attr.id; |
173 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { | 175 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { |
174 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; | 176 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; |
175 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | ||
176 | // FIXME hygiene | 177 | // FIXME hygiene |
177 | let hygiene = Hygiene::new_unhygienic(); | 178 | let hygiene = Hygiene::new_unhygienic(); |
178 | Attr::from_src(db, attr, &hygiene, index) | 179 | Attr::from_tt(db, &tree, &hygiene, index) |
179 | }); | 180 | }); |
180 | 181 | ||
181 | let cfg_options = &crate_graph[krate].cfg_options; | 182 | let cfg_options = &crate_graph[krate].cfg_options; |
@@ -664,7 +665,7 @@ impl fmt::Display for AttrInput { | |||
664 | impl Attr { | 665 | impl Attr { |
665 | fn from_src( | 666 | fn from_src( |
666 | db: &dyn DefDatabase, | 667 | db: &dyn DefDatabase, |
667 | ast: ast::Attr, | 668 | ast: ast::Meta, |
668 | hygiene: &Hygiene, | 669 | hygiene: &Hygiene, |
669 | id: AttrId, | 670 | id: AttrId, |
670 | ) -> Option<Attr> { | 671 | ) -> Option<Attr> { |
@@ -683,6 +684,19 @@ impl Attr { | |||
683 | Some(Attr { id, path, input }) | 684 | Some(Attr { id, path, input }) |
684 | } | 685 | } |
685 | 686 | ||
687 | fn from_tt( | ||
688 | db: &dyn DefDatabase, | ||
689 | tt: &tt::Subtree, | ||
690 | hygiene: &Hygiene, | ||
691 | id: AttrId, | ||
692 | ) -> Option<Attr> { | ||
693 | let (parse, _) = | ||
694 | mbe::token_tree_to_syntax_node(tt, hir_expand::FragmentKind::MetaItem).ok()?; | ||
695 | let ast = ast::Meta::cast(parse.syntax_node())?; | ||
696 | |||
697 | Self::from_src(db, ast, hygiene, id) | ||
698 | } | ||
699 | |||
686 | /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths | 700 | /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths |
687 | /// to derive macros. | 701 | /// to derive macros. |
688 | /// | 702 | /// |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 4b714c6d8..a1894e8d8 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | arrayvec = "0.7" | 15 | arrayvec = "0.7" |
16 | smallvec = "1.2.0" | 16 | smallvec = "1.2.0" |
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 283894704..407273943 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -4,325 +4,31 @@ mod match_check; | |||
4 | mod unsafe_check; | 4 | mod unsafe_check; |
5 | mod decl_check; | 5 | mod decl_check; |
6 | 6 | ||
7 | use std::{any::Any, fmt}; | 7 | use std::fmt; |
8 | 8 | ||
9 | use base_db::CrateId; | 9 | use base_db::CrateId; |
10 | use hir_def::{DefWithBodyId, ModuleDefId}; | 10 | use hir_def::ModuleDefId; |
11 | use hir_expand::{name::Name, HirFileId, InFile}; | 11 | use hir_expand::HirFileId; |
12 | use stdx::format_to; | 12 | use syntax::{ast, AstPtr}; |
13 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | ||
14 | 13 | ||
15 | use crate::{ | 14 | use crate::db::HirDatabase; |
16 | db::HirDatabase, | ||
17 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, | ||
18 | }; | ||
19 | 15 | ||
20 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | 16 | pub use crate::diagnostics::{ |
17 | expr::{ | ||
18 | record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic, | ||
19 | }, | ||
20 | unsafe_check::missing_unsafe, | ||
21 | }; | ||
21 | 22 | ||
22 | pub fn validate_module_item( | 23 | pub fn validate_module_item( |
23 | db: &dyn HirDatabase, | 24 | db: &dyn HirDatabase, |
24 | krate: CrateId, | 25 | krate: CrateId, |
25 | owner: ModuleDefId, | 26 | owner: ModuleDefId, |
26 | sink: &mut DiagnosticSink<'_>, | 27 | ) -> Vec<IncorrectCase> { |
27 | ) { | ||
28 | let _p = profile::span("validate_module_item"); | 28 | let _p = profile::span("validate_module_item"); |
29 | let mut validator = decl_check::DeclValidator::new(db, krate, sink); | 29 | let mut validator = decl_check::DeclValidator::new(db, krate); |
30 | validator.validate_item(owner); | 30 | validator.validate_item(owner); |
31 | } | 31 | validator.sink |
32 | |||
33 | pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { | ||
34 | let _p = profile::span("validate_body"); | ||
35 | let infer = db.infer(owner); | ||
36 | infer.add_diagnostics(db, owner, sink); | ||
37 | let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink); | ||
38 | validator.validate_body(db); | ||
39 | let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink); | ||
40 | validator.validate_body(db); | ||
41 | } | ||
42 | |||
43 | // Diagnostic: no-such-field | ||
44 | // | ||
45 | // This diagnostic is triggered if created structure does not have field provided in record. | ||
46 | #[derive(Debug)] | ||
47 | pub struct NoSuchField { | ||
48 | pub file: HirFileId, | ||
49 | pub field: AstPtr<ast::RecordExprField>, | ||
50 | } | ||
51 | |||
52 | impl Diagnostic for NoSuchField { | ||
53 | fn code(&self) -> DiagnosticCode { | ||
54 | DiagnosticCode("no-such-field") | ||
55 | } | ||
56 | |||
57 | fn message(&self) -> String { | ||
58 | "no such field".to_string() | ||
59 | } | ||
60 | |||
61 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
62 | InFile::new(self.file, self.field.clone().into()) | ||
63 | } | ||
64 | |||
65 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
66 | self | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // Diagnostic: missing-structure-fields | ||
71 | // | ||
72 | // This diagnostic is triggered if record lacks some fields that exist in the corresponding structure. | ||
73 | // | ||
74 | // Example: | ||
75 | // | ||
76 | // ```rust | ||
77 | // struct A { a: u8, b: u8 } | ||
78 | // | ||
79 | // let a = A { a: 10 }; | ||
80 | // ``` | ||
81 | #[derive(Debug)] | ||
82 | pub struct MissingFields { | ||
83 | pub file: HirFileId, | ||
84 | pub field_list_parent: AstPtr<ast::RecordExpr>, | ||
85 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
86 | pub missed_fields: Vec<Name>, | ||
87 | } | ||
88 | |||
89 | impl Diagnostic for MissingFields { | ||
90 | fn code(&self) -> DiagnosticCode { | ||
91 | DiagnosticCode("missing-structure-fields") | ||
92 | } | ||
93 | fn message(&self) -> String { | ||
94 | let mut buf = String::from("Missing structure fields:\n"); | ||
95 | for field in &self.missed_fields { | ||
96 | format_to!(buf, "- {}\n", field); | ||
97 | } | ||
98 | buf | ||
99 | } | ||
100 | |||
101 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
102 | InFile { | ||
103 | file_id: self.file, | ||
104 | value: self | ||
105 | .field_list_parent_path | ||
106 | .clone() | ||
107 | .map(SyntaxNodePtr::from) | ||
108 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
109 | } | ||
110 | } | ||
111 | |||
112 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
113 | self | ||
114 | } | ||
115 | } | ||
116 | |||
117 | // Diagnostic: missing-pat-fields | ||
118 | // | ||
119 | // This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure. | ||
120 | // | ||
121 | // Example: | ||
122 | // | ||
123 | // ```rust | ||
124 | // struct A { a: u8, b: u8 } | ||
125 | // | ||
126 | // let a = A { a: 10, b: 20 }; | ||
127 | // | ||
128 | // if let A { a } = a { | ||
129 | // // ... | ||
130 | // } | ||
131 | // ``` | ||
132 | #[derive(Debug)] | ||
133 | pub struct MissingPatFields { | ||
134 | pub file: HirFileId, | ||
135 | pub field_list_parent: AstPtr<ast::RecordPat>, | ||
136 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
137 | pub missed_fields: Vec<Name>, | ||
138 | } | ||
139 | |||
140 | impl Diagnostic for MissingPatFields { | ||
141 | fn code(&self) -> DiagnosticCode { | ||
142 | DiagnosticCode("missing-pat-fields") | ||
143 | } | ||
144 | fn message(&self) -> String { | ||
145 | let mut buf = String::from("Missing structure fields:\n"); | ||
146 | for field in &self.missed_fields { | ||
147 | format_to!(buf, "- {}\n", field); | ||
148 | } | ||
149 | buf | ||
150 | } | ||
151 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
152 | InFile { | ||
153 | file_id: self.file, | ||
154 | value: self | ||
155 | .field_list_parent_path | ||
156 | .clone() | ||
157 | .map(SyntaxNodePtr::from) | ||
158 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
159 | } | ||
160 | } | ||
161 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
162 | self | ||
163 | } | ||
164 | } | ||
165 | |||
166 | // Diagnostic: missing-match-arm | ||
167 | // | ||
168 | // This diagnostic is triggered if `match` block is missing one or more match arms. | ||
169 | #[derive(Debug)] | ||
170 | pub struct MissingMatchArms { | ||
171 | pub file: HirFileId, | ||
172 | pub match_expr: AstPtr<ast::Expr>, | ||
173 | pub arms: AstPtr<ast::MatchArmList>, | ||
174 | } | ||
175 | |||
176 | impl Diagnostic for MissingMatchArms { | ||
177 | fn code(&self) -> DiagnosticCode { | ||
178 | DiagnosticCode("missing-match-arm") | ||
179 | } | ||
180 | fn message(&self) -> String { | ||
181 | String::from("Missing match arm") | ||
182 | } | ||
183 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
184 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | ||
185 | } | ||
186 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
187 | self | ||
188 | } | ||
189 | } | ||
190 | |||
191 | // Diagnostic: missing-ok-or-some-in-tail-expr | ||
192 | // | ||
193 | // This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`, | ||
194 | // or if a block that should return `Option` returns a value not wrapped in `Some`. | ||
195 | // | ||
196 | // Example: | ||
197 | // | ||
198 | // ```rust | ||
199 | // fn foo() -> Result<u8, ()> { | ||
200 | // 10 | ||
201 | // } | ||
202 | // ``` | ||
203 | #[derive(Debug)] | ||
204 | pub struct MissingOkOrSomeInTailExpr { | ||
205 | pub file: HirFileId, | ||
206 | pub expr: AstPtr<ast::Expr>, | ||
207 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
208 | pub required: String, | ||
209 | } | ||
210 | |||
211 | impl Diagnostic for MissingOkOrSomeInTailExpr { | ||
212 | fn code(&self) -> DiagnosticCode { | ||
213 | DiagnosticCode("missing-ok-or-some-in-tail-expr") | ||
214 | } | ||
215 | fn message(&self) -> String { | ||
216 | format!("wrap return expression in {}", self.required) | ||
217 | } | ||
218 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
219 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
220 | } | ||
221 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
222 | self | ||
223 | } | ||
224 | } | ||
225 | |||
226 | #[derive(Debug)] | ||
227 | pub struct RemoveThisSemicolon { | ||
228 | pub file: HirFileId, | ||
229 | pub expr: AstPtr<ast::Expr>, | ||
230 | } | ||
231 | |||
232 | impl Diagnostic for RemoveThisSemicolon { | ||
233 | fn code(&self) -> DiagnosticCode { | ||
234 | DiagnosticCode("remove-this-semicolon") | ||
235 | } | ||
236 | |||
237 | fn message(&self) -> String { | ||
238 | "Remove this semicolon".to_string() | ||
239 | } | ||
240 | |||
241 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
242 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
243 | } | ||
244 | |||
245 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
246 | self | ||
247 | } | ||
248 | } | ||
249 | |||
250 | // Diagnostic: break-outside-of-loop | ||
251 | // | ||
252 | // This diagnostic is triggered if the `break` keyword is used outside of a loop. | ||
253 | #[derive(Debug)] | ||
254 | pub struct BreakOutsideOfLoop { | ||
255 | pub file: HirFileId, | ||
256 | pub expr: AstPtr<ast::Expr>, | ||
257 | } | ||
258 | |||
259 | impl Diagnostic for BreakOutsideOfLoop { | ||
260 | fn code(&self) -> DiagnosticCode { | ||
261 | DiagnosticCode("break-outside-of-loop") | ||
262 | } | ||
263 | fn message(&self) -> String { | ||
264 | "break outside of loop".to_string() | ||
265 | } | ||
266 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
267 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
268 | } | ||
269 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
270 | self | ||
271 | } | ||
272 | } | ||
273 | |||
274 | // Diagnostic: missing-unsafe | ||
275 | // | ||
276 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | ||
277 | #[derive(Debug)] | ||
278 | pub struct MissingUnsafe { | ||
279 | pub file: HirFileId, | ||
280 | pub expr: AstPtr<ast::Expr>, | ||
281 | } | ||
282 | |||
283 | impl Diagnostic for MissingUnsafe { | ||
284 | fn code(&self) -> DiagnosticCode { | ||
285 | DiagnosticCode("missing-unsafe") | ||
286 | } | ||
287 | fn message(&self) -> String { | ||
288 | format!("This operation is unsafe and requires an unsafe function or block") | ||
289 | } | ||
290 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
291 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
292 | } | ||
293 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
294 | self | ||
295 | } | ||
296 | } | ||
297 | |||
298 | // Diagnostic: mismatched-arg-count | ||
299 | // | ||
300 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | ||
301 | #[derive(Debug)] | ||
302 | pub struct MismatchedArgCount { | ||
303 | pub file: HirFileId, | ||
304 | pub call_expr: AstPtr<ast::Expr>, | ||
305 | pub expected: usize, | ||
306 | pub found: usize, | ||
307 | } | ||
308 | |||
309 | impl Diagnostic for MismatchedArgCount { | ||
310 | fn code(&self) -> DiagnosticCode { | ||
311 | DiagnosticCode("mismatched-arg-count") | ||
312 | } | ||
313 | fn message(&self) -> String { | ||
314 | let s = if self.expected == 1 { "" } else { "s" }; | ||
315 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | ||
316 | } | ||
317 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
318 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | ||
319 | } | ||
320 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
321 | self | ||
322 | } | ||
323 | fn is_experimental(&self) -> bool { | ||
324 | true | ||
325 | } | ||
326 | } | 32 | } |
327 | 33 | ||
328 | #[derive(Debug)] | 34 | #[derive(Debug)] |
@@ -390,450 +96,3 @@ pub struct IncorrectCase { | |||
390 | pub ident_text: String, | 96 | pub ident_text: String, |
391 | pub suggested_text: String, | 97 | pub suggested_text: String, |
392 | } | 98 | } |
393 | |||
394 | impl Diagnostic for IncorrectCase { | ||
395 | fn code(&self) -> DiagnosticCode { | ||
396 | DiagnosticCode("incorrect-ident-case") | ||
397 | } | ||
398 | |||
399 | fn message(&self) -> String { | ||
400 | format!( | ||
401 | "{} `{}` should have {} name, e.g. `{}`", | ||
402 | self.ident_type, | ||
403 | self.ident_text, | ||
404 | self.expected_case.to_string(), | ||
405 | self.suggested_text | ||
406 | ) | ||
407 | } | ||
408 | |||
409 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
410 | InFile::new(self.file, self.ident.clone().into()) | ||
411 | } | ||
412 | |||
413 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
414 | self | ||
415 | } | ||
416 | |||
417 | fn is_experimental(&self) -> bool { | ||
418 | true | ||
419 | } | ||
420 | } | ||
421 | |||
422 | // Diagnostic: replace-filter-map-next-with-find-map | ||
423 | // | ||
424 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. | ||
425 | #[derive(Debug)] | ||
426 | pub struct ReplaceFilterMapNextWithFindMap { | ||
427 | pub file: HirFileId, | ||
428 | /// This expression is the whole method chain up to and including `.filter_map(..).next()`. | ||
429 | pub next_expr: AstPtr<ast::Expr>, | ||
430 | } | ||
431 | |||
432 | impl Diagnostic for ReplaceFilterMapNextWithFindMap { | ||
433 | fn code(&self) -> DiagnosticCode { | ||
434 | DiagnosticCode("replace-filter-map-next-with-find-map") | ||
435 | } | ||
436 | fn message(&self) -> String { | ||
437 | "replace filter_map(..).next() with find_map(..)".to_string() | ||
438 | } | ||
439 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
440 | InFile { file_id: self.file, value: self.next_expr.clone().into() } | ||
441 | } | ||
442 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
443 | self | ||
444 | } | ||
445 | } | ||
446 | |||
447 | #[cfg(test)] | ||
448 | mod tests { | ||
449 | use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | ||
450 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | ||
451 | use hir_expand::db::AstDatabase; | ||
452 | use rustc_hash::FxHashMap; | ||
453 | use syntax::{TextRange, TextSize}; | ||
454 | |||
455 | use crate::{ | ||
456 | diagnostics::{validate_body, validate_module_item}, | ||
457 | diagnostics_sink::{Diagnostic, DiagnosticSinkBuilder}, | ||
458 | test_db::TestDB, | ||
459 | }; | ||
460 | |||
461 | impl TestDB { | ||
462 | fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | ||
463 | let crate_graph = self.crate_graph(); | ||
464 | for krate in crate_graph.iter() { | ||
465 | let crate_def_map = self.crate_def_map(krate); | ||
466 | |||
467 | let mut fns = Vec::new(); | ||
468 | for (module_id, _) in crate_def_map.modules() { | ||
469 | for decl in crate_def_map[module_id].scope.declarations() { | ||
470 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | ||
471 | validate_module_item(self, krate, decl, &mut sink); | ||
472 | |||
473 | if let ModuleDefId::FunctionId(f) = decl { | ||
474 | fns.push(f) | ||
475 | } | ||
476 | } | ||
477 | |||
478 | for impl_id in crate_def_map[module_id].scope.impls() { | ||
479 | let impl_data = self.impl_data(impl_id); | ||
480 | for item in impl_data.items.iter() { | ||
481 | if let AssocItemId::FunctionId(f) = item { | ||
482 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | ||
483 | validate_module_item( | ||
484 | self, | ||
485 | krate, | ||
486 | ModuleDefId::FunctionId(*f), | ||
487 | &mut sink, | ||
488 | ); | ||
489 | fns.push(*f) | ||
490 | } | ||
491 | } | ||
492 | } | ||
493 | } | ||
494 | |||
495 | for f in fns { | ||
496 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | ||
497 | validate_body(self, f.into(), &mut sink); | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | |||
503 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
504 | let db = TestDB::with_files(ra_fixture); | ||
505 | let annotations = db.extract_annotations(); | ||
506 | |||
507 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | ||
508 | db.diagnostics(|d| { | ||
509 | let src = d.display_source(); | ||
510 | let root = db.parse_or_expand(src.file_id).unwrap(); | ||
511 | // FIXME: macros... | ||
512 | let file_id = src.file_id.original_file(&db); | ||
513 | let range = src.value.to_node(&root).text_range(); | ||
514 | let message = d.message(); | ||
515 | actual.entry(file_id).or_default().push((range, message)); | ||
516 | }); | ||
517 | |||
518 | for (file_id, diags) in actual.iter_mut() { | ||
519 | diags.sort_by_key(|it| it.0.start()); | ||
520 | let text = db.file_text(*file_id); | ||
521 | // For multiline spans, place them on line start | ||
522 | for (range, content) in diags { | ||
523 | if text[*range].contains('\n') { | ||
524 | *range = TextRange::new(range.start(), range.start() + TextSize::from(1)); | ||
525 | *content = format!("... {}", content); | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | assert_eq!(annotations, actual); | ||
531 | } | ||
532 | |||
533 | #[test] | ||
534 | fn no_such_field_diagnostics() { | ||
535 | check_diagnostics( | ||
536 | r#" | ||
537 | struct S { foo: i32, bar: () } | ||
538 | impl S { | ||
539 | fn new() -> S { | ||
540 | S { | ||
541 | //^ Missing structure fields: | ||
542 | //| - bar | ||
543 | foo: 92, | ||
544 | baz: 62, | ||
545 | //^^^^^^^ no such field | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | "#, | ||
550 | ); | ||
551 | } | ||
552 | #[test] | ||
553 | fn no_such_field_with_feature_flag_diagnostics() { | ||
554 | check_diagnostics( | ||
555 | r#" | ||
556 | //- /lib.rs crate:foo cfg:feature=foo | ||
557 | struct MyStruct { | ||
558 | my_val: usize, | ||
559 | #[cfg(feature = "foo")] | ||
560 | bar: bool, | ||
561 | } | ||
562 | |||
563 | impl MyStruct { | ||
564 | #[cfg(feature = "foo")] | ||
565 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
566 | Self { my_val, bar } | ||
567 | } | ||
568 | #[cfg(not(feature = "foo"))] | ||
569 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
570 | Self { my_val } | ||
571 | } | ||
572 | } | ||
573 | "#, | ||
574 | ); | ||
575 | } | ||
576 | |||
577 | #[test] | ||
578 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
579 | check_diagnostics( | ||
580 | r#" | ||
581 | //- /lib.rs crate:foo cfg:feature=foo | ||
582 | enum Foo { | ||
583 | #[cfg(not(feature = "foo"))] | ||
584 | Buz, | ||
585 | #[cfg(feature = "foo")] | ||
586 | Bar, | ||
587 | Baz | ||
588 | } | ||
589 | |||
590 | fn test_fn(f: Foo) { | ||
591 | match f { | ||
592 | Foo::Bar => {}, | ||
593 | Foo::Baz => {}, | ||
594 | } | ||
595 | } | ||
596 | "#, | ||
597 | ); | ||
598 | } | ||
599 | |||
600 | #[test] | ||
601 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
602 | check_diagnostics( | ||
603 | r#" | ||
604 | //- /lib.rs crate:foo cfg:feature=foo | ||
605 | struct S { | ||
606 | #[cfg(feature = "foo")] | ||
607 | foo: u32, | ||
608 | #[cfg(not(feature = "foo"))] | ||
609 | bar: u32, | ||
610 | } | ||
611 | |||
612 | impl S { | ||
613 | #[cfg(feature = "foo")] | ||
614 | fn new(foo: u32) -> Self { | ||
615 | Self { foo } | ||
616 | } | ||
617 | #[cfg(not(feature = "foo"))] | ||
618 | fn new(bar: u32) -> Self { | ||
619 | Self { bar } | ||
620 | } | ||
621 | fn new2(bar: u32) -> Self { | ||
622 | #[cfg(feature = "foo")] | ||
623 | { Self { foo: bar } } | ||
624 | #[cfg(not(feature = "foo"))] | ||
625 | { Self { bar } } | ||
626 | } | ||
627 | fn new2(val: u32) -> Self { | ||
628 | Self { | ||
629 | #[cfg(feature = "foo")] | ||
630 | foo: val, | ||
631 | #[cfg(not(feature = "foo"))] | ||
632 | bar: val, | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | "#, | ||
637 | ); | ||
638 | } | ||
639 | |||
640 | #[test] | ||
641 | fn no_such_field_with_type_macro() { | ||
642 | check_diagnostics( | ||
643 | r#" | ||
644 | macro_rules! Type { () => { u32 }; } | ||
645 | struct Foo { bar: Type![] } | ||
646 | |||
647 | impl Foo { | ||
648 | fn new() -> Self { | ||
649 | Foo { bar: 0 } | ||
650 | } | ||
651 | } | ||
652 | "#, | ||
653 | ); | ||
654 | } | ||
655 | |||
656 | #[test] | ||
657 | fn missing_record_pat_field_diagnostic() { | ||
658 | check_diagnostics( | ||
659 | r#" | ||
660 | struct S { foo: i32, bar: () } | ||
661 | fn baz(s: S) { | ||
662 | let S { foo: _ } = s; | ||
663 | //^ Missing structure fields: | ||
664 | //| - bar | ||
665 | } | ||
666 | "#, | ||
667 | ); | ||
668 | } | ||
669 | |||
670 | #[test] | ||
671 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
672 | check_diagnostics( | ||
673 | r" | ||
674 | struct S { foo: i32, bar: () } | ||
675 | fn baz(s: S) -> i32 { | ||
676 | match s { | ||
677 | S { foo, .. } => foo, | ||
678 | } | ||
679 | } | ||
680 | ", | ||
681 | ) | ||
682 | } | ||
683 | |||
684 | #[test] | ||
685 | fn missing_record_pat_field_box() { | ||
686 | check_diagnostics( | ||
687 | r" | ||
688 | struct S { s: Box<u32> } | ||
689 | fn x(a: S) { | ||
690 | let S { box s } = a; | ||
691 | } | ||
692 | ", | ||
693 | ) | ||
694 | } | ||
695 | |||
696 | #[test] | ||
697 | fn missing_record_pat_field_ref() { | ||
698 | check_diagnostics( | ||
699 | r" | ||
700 | struct S { s: u32 } | ||
701 | fn x(a: S) { | ||
702 | let S { ref s } = a; | ||
703 | } | ||
704 | ", | ||
705 | ) | ||
706 | } | ||
707 | |||
708 | #[test] | ||
709 | fn import_extern_crate_clash_with_inner_item() { | ||
710 | // This is more of a resolver test, but doesn't really work with the hir_def testsuite. | ||
711 | |||
712 | check_diagnostics( | ||
713 | r#" | ||
714 | //- /lib.rs crate:lib deps:jwt | ||
715 | mod permissions; | ||
716 | |||
717 | use permissions::jwt; | ||
718 | |||
719 | fn f() { | ||
720 | fn inner() {} | ||
721 | jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic | ||
722 | } | ||
723 | |||
724 | //- /permissions.rs | ||
725 | pub mod jwt { | ||
726 | pub struct Claims {} | ||
727 | } | ||
728 | |||
729 | //- /jwt/lib.rs crate:jwt | ||
730 | pub struct Claims { | ||
731 | field: u8, | ||
732 | } | ||
733 | "#, | ||
734 | ); | ||
735 | } | ||
736 | |||
737 | #[test] | ||
738 | fn break_outside_of_loop() { | ||
739 | check_diagnostics( | ||
740 | r#" | ||
741 | fn foo() { break; } | ||
742 | //^^^^^ break outside of loop | ||
743 | "#, | ||
744 | ); | ||
745 | } | ||
746 | |||
747 | #[test] | ||
748 | fn missing_semicolon() { | ||
749 | check_diagnostics( | ||
750 | r#" | ||
751 | fn test() -> i32 { 123; } | ||
752 | //^^^ Remove this semicolon | ||
753 | "#, | ||
754 | ); | ||
755 | } | ||
756 | |||
757 | // Register the required standard library types to make the tests work | ||
758 | fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { | ||
759 | let prefix = r#" | ||
760 | //- /main.rs crate:main deps:core | ||
761 | use core::iter::Iterator; | ||
762 | use core::option::Option::{self, Some, None}; | ||
763 | "#; | ||
764 | let suffix = r#" | ||
765 | //- /core/lib.rs crate:core | ||
766 | pub mod option { | ||
767 | pub enum Option<T> { Some(T), None } | ||
768 | } | ||
769 | pub mod iter { | ||
770 | pub trait Iterator { | ||
771 | type Item; | ||
772 | fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap } | ||
773 | fn next(&mut self) -> Option<Self::Item>; | ||
774 | } | ||
775 | pub struct FilterMap {} | ||
776 | impl Iterator for FilterMap { | ||
777 | type Item = i32; | ||
778 | fn next(&mut self) -> i32 { 7 } | ||
779 | } | ||
780 | } | ||
781 | "#; | ||
782 | format!("{}{}{}", prefix, body, suffix) | ||
783 | } | ||
784 | |||
785 | #[test] | ||
786 | fn replace_filter_map_next_with_find_map2() { | ||
787 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
788 | r#" | ||
789 | fn foo() { | ||
790 | let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); | ||
791 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) | ||
792 | } | ||
793 | "#, | ||
794 | )); | ||
795 | } | ||
796 | |||
797 | #[test] | ||
798 | fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() { | ||
799 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
800 | r#" | ||
801 | fn foo() { | ||
802 | let m = [1, 2, 3] | ||
803 | .iter() | ||
804 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | ||
805 | .len(); | ||
806 | } | ||
807 | "#, | ||
808 | )); | ||
809 | } | ||
810 | |||
811 | #[test] | ||
812 | fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() { | ||
813 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
814 | r#" | ||
815 | fn foo() { | ||
816 | let m = [1, 2, 3] | ||
817 | .iter() | ||
818 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | ||
819 | .map(|x| x + 2) | ||
820 | .len(); | ||
821 | } | ||
822 | "#, | ||
823 | )); | ||
824 | } | ||
825 | |||
826 | #[test] | ||
827 | fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() { | ||
828 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
829 | r#" | ||
830 | fn foo() { | ||
831 | let m = [1, 2, 3] | ||
832 | .iter() | ||
833 | .filter_map(|x| if *x == 2 { Some (4) } else { None }); | ||
834 | let n = m.next(); | ||
835 | } | ||
836 | "#, | ||
837 | )); | ||
838 | } | ||
839 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index cfb5d7320..f26150b77 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -29,7 +29,6 @@ use syntax::{ | |||
29 | use crate::{ | 29 | use crate::{ |
30 | db::HirDatabase, | 30 | db::HirDatabase, |
31 | diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, | 31 | diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, |
32 | diagnostics_sink::DiagnosticSink, | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | mod allow { | 34 | mod allow { |
@@ -40,10 +39,10 @@ mod allow { | |||
40 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; | 39 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; |
41 | } | 40 | } |
42 | 41 | ||
43 | pub(super) struct DeclValidator<'a, 'b> { | 42 | pub(super) struct DeclValidator<'a> { |
44 | db: &'a dyn HirDatabase, | 43 | db: &'a dyn HirDatabase, |
45 | krate: CrateId, | 44 | krate: CrateId, |
46 | sink: &'a mut DiagnosticSink<'b>, | 45 | pub(super) sink: Vec<IncorrectCase>, |
47 | } | 46 | } |
48 | 47 | ||
49 | #[derive(Debug)] | 48 | #[derive(Debug)] |
@@ -53,13 +52,9 @@ struct Replacement { | |||
53 | expected_case: CaseType, | 52 | expected_case: CaseType, |
54 | } | 53 | } |
55 | 54 | ||
56 | impl<'a, 'b> DeclValidator<'a, 'b> { | 55 | impl<'a> DeclValidator<'a> { |
57 | pub(super) fn new( | 56 | pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> { |
58 | db: &'a dyn HirDatabase, | 57 | DeclValidator { db, krate, sink: Vec::new() } |
59 | krate: CrateId, | ||
60 | sink: &'a mut DiagnosticSink<'b>, | ||
61 | ) -> DeclValidator<'a, 'b> { | ||
62 | DeclValidator { db, krate, sink } | ||
63 | } | 58 | } |
64 | 59 | ||
65 | pub(super) fn validate_item(&mut self, item: ModuleDefId) { | 60 | pub(super) fn validate_item(&mut self, item: ModuleDefId) { |
@@ -131,7 +126,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
131 | for (_, block_def_map) in body.blocks(self.db.upcast()) { | 126 | for (_, block_def_map) in body.blocks(self.db.upcast()) { |
132 | for (_, module) in block_def_map.modules() { | 127 | for (_, module) in block_def_map.modules() { |
133 | for def_id in module.scope.declarations() { | 128 | for def_id in module.scope.declarations() { |
134 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); | 129 | let mut validator = DeclValidator::new(self.db, self.krate); |
135 | validator.validate_item(def_id); | 130 | validator.validate_item(def_id); |
136 | } | 131 | } |
137 | } | 132 | } |
@@ -623,343 +618,3 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
623 | self.sink.push(diagnostic); | 618 | self.sink.push(diagnostic); |
624 | } | 619 | } |
625 | } | 620 | } |
626 | |||
627 | #[cfg(test)] | ||
628 | mod tests { | ||
629 | use crate::diagnostics::tests::check_diagnostics; | ||
630 | |||
631 | #[test] | ||
632 | fn incorrect_function_name() { | ||
633 | check_diagnostics( | ||
634 | r#" | ||
635 | fn NonSnakeCaseName() {} | ||
636 | // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` | ||
637 | "#, | ||
638 | ); | ||
639 | } | ||
640 | |||
641 | #[test] | ||
642 | fn incorrect_function_params() { | ||
643 | check_diagnostics( | ||
644 | r#" | ||
645 | fn foo(SomeParam: u8) {} | ||
646 | // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` | ||
647 | |||
648 | fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | ||
649 | // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` | ||
650 | "#, | ||
651 | ); | ||
652 | } | ||
653 | |||
654 | #[test] | ||
655 | fn incorrect_variable_names() { | ||
656 | check_diagnostics( | ||
657 | r#" | ||
658 | fn foo() { | ||
659 | let SOME_VALUE = 10; | ||
660 | // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` | ||
661 | let AnotherValue = 20; | ||
662 | // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` | ||
663 | } | ||
664 | "#, | ||
665 | ); | ||
666 | } | ||
667 | |||
668 | #[test] | ||
669 | fn incorrect_struct_names() { | ||
670 | check_diagnostics( | ||
671 | r#" | ||
672 | struct non_camel_case_name {} | ||
673 | // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` | ||
674 | |||
675 | struct SCREAMING_CASE {} | ||
676 | // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` | ||
677 | "#, | ||
678 | ); | ||
679 | } | ||
680 | |||
681 | #[test] | ||
682 | fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() { | ||
683 | check_diagnostics( | ||
684 | r#" | ||
685 | struct AABB {} | ||
686 | "#, | ||
687 | ); | ||
688 | } | ||
689 | |||
690 | #[test] | ||
691 | fn incorrect_struct_field() { | ||
692 | check_diagnostics( | ||
693 | r#" | ||
694 | struct SomeStruct { SomeField: u8 } | ||
695 | // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` | ||
696 | "#, | ||
697 | ); | ||
698 | } | ||
699 | |||
700 | #[test] | ||
701 | fn incorrect_enum_names() { | ||
702 | check_diagnostics( | ||
703 | r#" | ||
704 | enum some_enum { Val(u8) } | ||
705 | // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` | ||
706 | |||
707 | enum SOME_ENUM | ||
708 | // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` | ||
709 | "#, | ||
710 | ); | ||
711 | } | ||
712 | |||
713 | #[test] | ||
714 | fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() { | ||
715 | check_diagnostics( | ||
716 | r#" | ||
717 | enum AABB {} | ||
718 | "#, | ||
719 | ); | ||
720 | } | ||
721 | |||
722 | #[test] | ||
723 | fn incorrect_enum_variant_name() { | ||
724 | check_diagnostics( | ||
725 | r#" | ||
726 | enum SomeEnum { SOME_VARIANT(u8) } | ||
727 | // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` | ||
728 | "#, | ||
729 | ); | ||
730 | } | ||
731 | |||
732 | #[test] | ||
733 | fn incorrect_const_name() { | ||
734 | check_diagnostics( | ||
735 | r#" | ||
736 | const some_weird_const: u8 = 10; | ||
737 | // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | ||
738 | |||
739 | fn func() { | ||
740 | const someConstInFunc: &str = "hi there"; | ||
741 | // ^^^^^^^^^^^^^^^ Constant `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC` | ||
742 | |||
743 | } | ||
744 | "#, | ||
745 | ); | ||
746 | } | ||
747 | |||
748 | #[test] | ||
749 | fn incorrect_static_name() { | ||
750 | check_diagnostics( | ||
751 | r#" | ||
752 | static some_weird_const: u8 = 10; | ||
753 | // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | ||
754 | |||
755 | fn func() { | ||
756 | static someConstInFunc: &str = "hi there"; | ||
757 | // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC` | ||
758 | } | ||
759 | "#, | ||
760 | ); | ||
761 | } | ||
762 | |||
763 | #[test] | ||
764 | fn fn_inside_impl_struct() { | ||
765 | check_diagnostics( | ||
766 | r#" | ||
767 | struct someStruct; | ||
768 | // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` | ||
769 | |||
770 | impl someStruct { | ||
771 | fn SomeFunc(&self) { | ||
772 | // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` | ||
773 | static someConstInFunc: &str = "hi there"; | ||
774 | // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC` | ||
775 | let WHY_VAR_IS_CAPS = 10; | ||
776 | // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` | ||
777 | } | ||
778 | } | ||
779 | "#, | ||
780 | ); | ||
781 | } | ||
782 | |||
783 | #[test] | ||
784 | fn no_diagnostic_for_enum_varinats() { | ||
785 | check_diagnostics( | ||
786 | r#" | ||
787 | enum Option { Some, None } | ||
788 | |||
789 | fn main() { | ||
790 | match Option::None { | ||
791 | None => (), | ||
792 | Some => (), | ||
793 | } | ||
794 | } | ||
795 | "#, | ||
796 | ); | ||
797 | } | ||
798 | |||
799 | #[test] | ||
800 | fn non_let_bind() { | ||
801 | check_diagnostics( | ||
802 | r#" | ||
803 | enum Option { Some, None } | ||
804 | |||
805 | fn main() { | ||
806 | match Option::None { | ||
807 | SOME_VAR @ None => (), | ||
808 | // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` | ||
809 | Some => (), | ||
810 | } | ||
811 | } | ||
812 | "#, | ||
813 | ); | ||
814 | } | ||
815 | |||
816 | #[test] | ||
817 | fn allow_attributes() { | ||
818 | check_diagnostics( | ||
819 | r#" | ||
820 | #[allow(non_snake_case)] | ||
821 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ | ||
822 | // cov_flags generated output from elsewhere in this file | ||
823 | extern "C" { | ||
824 | #[no_mangle] | ||
825 | static lower_case: u8; | ||
826 | } | ||
827 | |||
828 | let OtherVar = SOME_VAR + 1; | ||
829 | OtherVar | ||
830 | } | ||
831 | |||
832 | #[allow(nonstandard_style)] | ||
833 | mod CheckNonstandardStyle { | ||
834 | fn HiImABadFnName() {} | ||
835 | } | ||
836 | |||
837 | #[allow(bad_style)] | ||
838 | mod CheckBadStyle { | ||
839 | fn HiImABadFnName() {} | ||
840 | } | ||
841 | |||
842 | mod F { | ||
843 | #![allow(non_snake_case)] | ||
844 | fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {} | ||
845 | } | ||
846 | |||
847 | #[allow(non_snake_case, non_camel_case_types)] | ||
848 | pub struct some_type { | ||
849 | SOME_FIELD: u8, | ||
850 | SomeField: u16, | ||
851 | } | ||
852 | |||
853 | #[allow(non_upper_case_globals)] | ||
854 | pub const some_const: u8 = 10; | ||
855 | |||
856 | #[allow(non_upper_case_globals)] | ||
857 | pub static SomeStatic: u8 = 10; | ||
858 | "#, | ||
859 | ); | ||
860 | } | ||
861 | |||
862 | #[test] | ||
863 | fn allow_attributes_crate_attr() { | ||
864 | check_diagnostics( | ||
865 | r#" | ||
866 | #![allow(non_snake_case)] | ||
867 | |||
868 | mod F { | ||
869 | fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {} | ||
870 | } | ||
871 | "#, | ||
872 | ); | ||
873 | } | ||
874 | |||
875 | #[test] | ||
876 | #[ignore] | ||
877 | fn bug_trait_inside_fn() { | ||
878 | // FIXME: | ||
879 | // This is broken, and in fact, should not even be looked at by this | ||
880 | // lint in the first place. There's weird stuff going on in the | ||
881 | // collection phase. | ||
882 | // It's currently being brought in by: | ||
883 | // * validate_func on `a` recursing into modules | ||
884 | // * then it finds the trait and then the function while iterating | ||
885 | // through modules | ||
886 | // * then validate_func is called on Dirty | ||
887 | // * ... which then proceeds to look at some unknown module taking no | ||
888 | // attrs from either the impl or the fn a, and then finally to the root | ||
889 | // module | ||
890 | // | ||
891 | // It should find the attribute on the trait, but it *doesn't even see | ||
892 | // the trait* as far as I can tell. | ||
893 | |||
894 | check_diagnostics( | ||
895 | r#" | ||
896 | trait T { fn a(); } | ||
897 | struct U {} | ||
898 | impl T for U { | ||
899 | fn a() { | ||
900 | // this comes out of bitflags, mostly | ||
901 | #[allow(non_snake_case)] | ||
902 | trait __BitFlags { | ||
903 | const HiImAlsoBad: u8 = 2; | ||
904 | #[inline] | ||
905 | fn Dirty(&self) -> bool { | ||
906 | false | ||
907 | } | ||
908 | } | ||
909 | |||
910 | } | ||
911 | } | ||
912 | "#, | ||
913 | ); | ||
914 | } | ||
915 | |||
916 | #[test] | ||
917 | #[ignore] | ||
918 | fn bug_traits_arent_checked() { | ||
919 | // FIXME: Traits and functions in traits aren't currently checked by | ||
920 | // r-a, even though rustc will complain about them. | ||
921 | check_diagnostics( | ||
922 | r#" | ||
923 | trait BAD_TRAIT { | ||
924 | // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` | ||
925 | fn BAD_FUNCTION(); | ||
926 | // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` | ||
927 | fn BadFunction(); | ||
928 | // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` | ||
929 | } | ||
930 | "#, | ||
931 | ); | ||
932 | } | ||
933 | |||
934 | #[test] | ||
935 | fn ignores_extern_items() { | ||
936 | cov_mark::check!(extern_func_incorrect_case_ignored); | ||
937 | cov_mark::check!(extern_static_incorrect_case_ignored); | ||
938 | check_diagnostics( | ||
939 | r#" | ||
940 | extern { | ||
941 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8; | ||
942 | pub static SomeStatic: u8 = 10; | ||
943 | } | ||
944 | "#, | ||
945 | ); | ||
946 | } | ||
947 | |||
948 | #[test] | ||
949 | fn infinite_loop_inner_items() { | ||
950 | check_diagnostics( | ||
951 | r#" | ||
952 | fn qualify() { | ||
953 | mod foo { | ||
954 | use super::*; | ||
955 | } | ||
956 | } | ||
957 | "#, | ||
958 | ) | ||
959 | } | ||
960 | |||
961 | #[test] // Issue #8809. | ||
962 | fn parenthesized_parameter() { | ||
963 | check_diagnostics(r#"fn f((O): _) {}"#) | ||
964 | } | ||
965 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index a2a4d61db..c480ed352 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -9,19 +9,13 @@ use hir_def::{ | |||
9 | }; | 9 | }; |
10 | use hir_expand::name; | 10 | use hir_expand::name; |
11 | use rustc_hash::FxHashSet; | 11 | use rustc_hash::FxHashSet; |
12 | use syntax::{ast, AstPtr}; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::HirDatabase, | 14 | db::HirDatabase, |
16 | diagnostics::{ | 15 | diagnostics::match_check::{ |
17 | match_check::{ | 16 | self, |
18 | self, | 17 | usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena}, |
19 | usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena}, | ||
20 | }, | ||
21 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | ||
22 | MissingPatFields, RemoveThisSemicolon, | ||
23 | }, | 18 | }, |
24 | diagnostics_sink::DiagnosticSink, | ||
25 | AdtId, InferenceResult, Interner, TyExt, TyKind, | 19 | AdtId, InferenceResult, Interner, TyExt, TyKind, |
26 | }; | 20 | }; |
27 | 21 | ||
@@ -31,38 +25,81 @@ pub(crate) use hir_def::{ | |||
31 | LocalFieldId, VariantId, | 25 | LocalFieldId, VariantId, |
32 | }; | 26 | }; |
33 | 27 | ||
34 | use super::ReplaceFilterMapNextWithFindMap; | 28 | pub enum BodyValidationDiagnostic { |
29 | RecordLiteralMissingFields { | ||
30 | record_expr: ExprId, | ||
31 | variant: VariantId, | ||
32 | missed_fields: Vec<LocalFieldId>, | ||
33 | }, | ||
34 | RecordPatMissingFields { | ||
35 | record_pat: PatId, | ||
36 | variant: VariantId, | ||
37 | missed_fields: Vec<LocalFieldId>, | ||
38 | }, | ||
39 | ReplaceFilterMapNextWithFindMap { | ||
40 | method_call_expr: ExprId, | ||
41 | }, | ||
42 | MismatchedArgCount { | ||
43 | call_expr: ExprId, | ||
44 | expected: usize, | ||
45 | found: usize, | ||
46 | }, | ||
47 | RemoveThisSemicolon { | ||
48 | expr: ExprId, | ||
49 | }, | ||
50 | MissingOkOrSomeInTailExpr { | ||
51 | expr: ExprId, | ||
52 | required: String, | ||
53 | }, | ||
54 | MissingMatchArms { | ||
55 | match_expr: ExprId, | ||
56 | }, | ||
57 | InternalBailedOut { | ||
58 | pat: PatId, | ||
59 | }, | ||
60 | } | ||
35 | 61 | ||
36 | pub(super) struct ExprValidator<'a, 'b: 'a> { | 62 | impl BodyValidationDiagnostic { |
63 | pub fn collect( | ||
64 | db: &dyn HirDatabase, | ||
65 | owner: DefWithBodyId, | ||
66 | internal_diagnostics: bool, | ||
67 | ) -> Vec<BodyValidationDiagnostic> { | ||
68 | let _p = profile::span("BodyValidationDiagnostic::collect"); | ||
69 | let infer = db.infer(owner); | ||
70 | let mut validator = ExprValidator::new(owner, infer.clone()); | ||
71 | validator.internal_diagnostics = internal_diagnostics; | ||
72 | validator.validate_body(db); | ||
73 | validator.diagnostics | ||
74 | } | ||
75 | } | ||
76 | |||
77 | struct ExprValidator { | ||
37 | owner: DefWithBodyId, | 78 | owner: DefWithBodyId, |
38 | infer: Arc<InferenceResult>, | 79 | infer: Arc<InferenceResult>, |
39 | sink: &'a mut DiagnosticSink<'b>, | 80 | pub(super) diagnostics: Vec<BodyValidationDiagnostic>, |
81 | internal_diagnostics: bool, | ||
40 | } | 82 | } |
41 | 83 | ||
42 | impl<'a, 'b> ExprValidator<'a, 'b> { | 84 | impl ExprValidator { |
43 | pub(super) fn new( | 85 | fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> ExprValidator { |
44 | owner: DefWithBodyId, | 86 | ExprValidator { owner, infer, diagnostics: Vec::new(), internal_diagnostics: false } |
45 | infer: Arc<InferenceResult>, | ||
46 | sink: &'a mut DiagnosticSink<'b>, | ||
47 | ) -> ExprValidator<'a, 'b> { | ||
48 | ExprValidator { owner, infer, sink } | ||
49 | } | 87 | } |
50 | 88 | ||
51 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { | 89 | fn validate_body(&mut self, db: &dyn HirDatabase) { |
52 | self.check_for_filter_map_next(db); | 90 | self.check_for_filter_map_next(db); |
53 | 91 | ||
54 | let body = db.body(self.owner); | 92 | let body = db.body(self.owner); |
55 | 93 | ||
56 | for (id, expr) in body.exprs.iter() { | 94 | for (id, expr) in body.exprs.iter() { |
57 | if let Some((variant_def, missed_fields, true)) = | 95 | if let Some((variant, missed_fields, true)) = |
58 | record_literal_missing_fields(db, &self.infer, id, expr) | 96 | record_literal_missing_fields(db, &self.infer, id, expr) |
59 | { | 97 | { |
60 | self.create_record_literal_missing_fields_diagnostic( | 98 | self.diagnostics.push(BodyValidationDiagnostic::RecordLiteralMissingFields { |
61 | id, | 99 | record_expr: id, |
62 | db, | 100 | variant, |
63 | variant_def, | ||
64 | missed_fields, | 101 | missed_fields, |
65 | ); | 102 | }); |
66 | } | 103 | } |
67 | 104 | ||
68 | match expr { | 105 | match expr { |
@@ -76,15 +113,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
76 | } | 113 | } |
77 | } | 114 | } |
78 | for (id, pat) in body.pats.iter() { | 115 | for (id, pat) in body.pats.iter() { |
79 | if let Some((variant_def, missed_fields, true)) = | 116 | if let Some((variant, missed_fields, true)) = |
80 | record_pattern_missing_fields(db, &self.infer, id, pat) | 117 | record_pattern_missing_fields(db, &self.infer, id, pat) |
81 | { | 118 | { |
82 | self.create_record_pattern_missing_fields_diagnostic( | 119 | self.diagnostics.push(BodyValidationDiagnostic::RecordPatMissingFields { |
83 | id, | 120 | record_pat: id, |
84 | db, | 121 | variant, |
85 | variant_def, | ||
86 | missed_fields, | 122 | missed_fields, |
87 | ); | 123 | }); |
88 | } | 124 | } |
89 | } | 125 | } |
90 | let body_expr = &body[body.body_expr]; | 126 | let body_expr = &body[body.body_expr]; |
@@ -92,71 +128,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
92 | if let Some(t) = tail { | 128 | if let Some(t) = tail { |
93 | self.validate_results_in_tail_expr(body.body_expr, *t, db); | 129 | self.validate_results_in_tail_expr(body.body_expr, *t, db); |
94 | } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() { | 130 | } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() { |
95 | self.validate_missing_tail_expr(body.body_expr, *id, db); | 131 | self.validate_missing_tail_expr(body.body_expr, *id); |
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | fn create_record_literal_missing_fields_diagnostic( | ||
101 | &mut self, | ||
102 | id: ExprId, | ||
103 | db: &dyn HirDatabase, | ||
104 | variant_def: VariantId, | ||
105 | missed_fields: Vec<LocalFieldId>, | ||
106 | ) { | ||
107 | // XXX: only look at source_map if we do have missing fields | ||
108 | let (_, source_map) = db.body_with_source_map(self.owner); | ||
109 | |||
110 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
111 | let root = source_ptr.file_syntax(db.upcast()); | ||
112 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { | ||
113 | if let Some(_) = record_expr.record_expr_field_list() { | ||
114 | let variant_data = variant_def.variant_data(db.upcast()); | ||
115 | let missed_fields = missed_fields | ||
116 | .into_iter() | ||
117 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
118 | .collect(); | ||
119 | self.sink.push(MissingFields { | ||
120 | file: source_ptr.file_id, | ||
121 | field_list_parent: AstPtr::new(&record_expr), | ||
122 | field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)), | ||
123 | missed_fields, | ||
124 | }) | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | fn create_record_pattern_missing_fields_diagnostic( | ||
131 | &mut self, | ||
132 | id: PatId, | ||
133 | db: &dyn HirDatabase, | ||
134 | variant_def: VariantId, | ||
135 | missed_fields: Vec<LocalFieldId>, | ||
136 | ) { | ||
137 | // XXX: only look at source_map if we do have missing fields | ||
138 | let (_, source_map) = db.body_with_source_map(self.owner); | ||
139 | |||
140 | if let Ok(source_ptr) = source_map.pat_syntax(id) { | ||
141 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
142 | let root = source_ptr.file_syntax(db.upcast()); | ||
143 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
144 | if let Some(_) = record_pat.record_pat_field_list() { | ||
145 | let variant_data = variant_def.variant_data(db.upcast()); | ||
146 | let missed_fields = missed_fields | ||
147 | .into_iter() | ||
148 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
149 | .collect(); | ||
150 | self.sink.push(MissingPatFields { | ||
151 | file: source_ptr.file_id, | ||
152 | field_list_parent: AstPtr::new(&record_pat), | ||
153 | field_list_parent_path: record_pat | ||
154 | .path() | ||
155 | .map(|path| AstPtr::new(&path)), | ||
156 | missed_fields, | ||
157 | }) | ||
158 | } | ||
159 | } | ||
160 | } | 132 | } |
161 | } | 133 | } |
162 | } | 134 | } |
@@ -199,13 +171,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
199 | if function_id == *next_function_id { | 171 | if function_id == *next_function_id { |
200 | if let Some(filter_map_id) = prev { | 172 | if let Some(filter_map_id) = prev { |
201 | if *receiver == filter_map_id { | 173 | if *receiver == filter_map_id { |
202 | let (_, source_map) = db.body_with_source_map(self.owner); | 174 | self.diagnostics.push( |
203 | if let Ok(next_source_ptr) = source_map.expr_syntax(id) { | 175 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { |
204 | self.sink.push(ReplaceFilterMapNextWithFindMap { | 176 | method_call_expr: id, |
205 | file: next_source_ptr.file_id, | 177 | }, |
206 | next_expr: next_source_ptr.value, | 178 | ); |
207 | }); | ||
208 | } | ||
209 | } | 179 | } |
210 | } | 180 | } |
211 | } | 181 | } |
@@ -266,19 +236,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
266 | let mut arg_count = args.len(); | 236 | let mut arg_count = args.len(); |
267 | 237 | ||
268 | if arg_count != param_count { | 238 | if arg_count != param_count { |
269 | let (_, source_map) = db.body_with_source_map(self.owner); | 239 | if is_method_call { |
270 | if let Ok(source_ptr) = source_map.expr_syntax(call_id) { | 240 | param_count -= 1; |
271 | if is_method_call { | 241 | arg_count -= 1; |
272 | param_count -= 1; | ||
273 | arg_count -= 1; | ||
274 | } | ||
275 | self.sink.push(MismatchedArgCount { | ||
276 | file: source_ptr.file_id, | ||
277 | call_expr: source_ptr.value, | ||
278 | expected: param_count, | ||
279 | found: arg_count, | ||
280 | }); | ||
281 | } | 242 | } |
243 | self.diagnostics.push(BodyValidationDiagnostic::MismatchedArgCount { | ||
244 | call_expr: call_id, | ||
245 | expected: param_count, | ||
246 | found: arg_count, | ||
247 | }); | ||
282 | } | 248 | } |
283 | } | 249 | } |
284 | 250 | ||
@@ -346,8 +312,9 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
346 | // fit the match expression, we skip this diagnostic. Skipping the entire | 312 | // fit the match expression, we skip this diagnostic. Skipping the entire |
347 | // diagnostic rather than just not including this match arm is preferred | 313 | // diagnostic rather than just not including this match arm is preferred |
348 | // to avoid the chance of false positives. | 314 | // to avoid the chance of false positives. |
349 | #[cfg(test)] | 315 | if self.internal_diagnostics { |
350 | match_check::tests::report_bail_out(db, self.owner, arm.pat, self.sink); | 316 | self.diagnostics.push(BodyValidationDiagnostic::InternalBailedOut { pat: arm.pat }) |
317 | } | ||
351 | return; | 318 | return; |
352 | } | 319 | } |
353 | 320 | ||
@@ -382,20 +349,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
382 | // FIXME Report witnesses | 349 | // FIXME Report witnesses |
383 | // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); | 350 | // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); |
384 | if !witnesses.is_empty() { | 351 | if !witnesses.is_empty() { |
385 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 352 | self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { match_expr: id }); |
386 | let root = source_ptr.file_syntax(db.upcast()); | ||
387 | if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { | ||
388 | if let (Some(match_expr), Some(arms)) = | ||
389 | (match_expr.expr(), match_expr.match_arm_list()) | ||
390 | { | ||
391 | self.sink.push(MissingMatchArms { | ||
392 | file: source_ptr.file_id, | ||
393 | match_expr: AstPtr::new(&match_expr), | ||
394 | arms: AstPtr::new(&arms), | ||
395 | }) | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | } | 353 | } |
400 | } | 354 | } |
401 | 355 | ||
@@ -453,24 +407,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
453 | if params.len(&Interner) > 0 | 407 | if params.len(&Interner) > 0 |
454 | && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual) | 408 | && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual) |
455 | { | 409 | { |
456 | let (_, source_map) = db.body_with_source_map(self.owner); | 410 | self.diagnostics |
457 | 411 | .push(BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr: id, required }); | |
458 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
459 | self.sink.push(MissingOkOrSomeInTailExpr { | ||
460 | file: source_ptr.file_id, | ||
461 | expr: source_ptr.value, | ||
462 | required, | ||
463 | }); | ||
464 | } | ||
465 | } | 412 | } |
466 | } | 413 | } |
467 | 414 | ||
468 | fn validate_missing_tail_expr( | 415 | fn validate_missing_tail_expr(&mut self, body_id: ExprId, possible_tail_id: ExprId) { |
469 | &mut self, | ||
470 | body_id: ExprId, | ||
471 | possible_tail_id: ExprId, | ||
472 | db: &dyn HirDatabase, | ||
473 | ) { | ||
474 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { | 416 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { |
475 | Some(m) => m, | 417 | Some(m) => m, |
476 | None => return, | 418 | None => return, |
@@ -485,12 +427,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
485 | return; | 427 | return; |
486 | } | 428 | } |
487 | 429 | ||
488 | let (_, source_map) = db.body_with_source_map(self.owner); | 430 | self.diagnostics |
489 | 431 | .push(BodyValidationDiagnostic::RemoveThisSemicolon { expr: possible_tail_id }); | |
490 | if let Ok(source_ptr) = source_map.expr_syntax(possible_tail_id) { | ||
491 | self.sink | ||
492 | .push(RemoveThisSemicolon { file: source_ptr.file_id, expr: source_ptr.value }); | ||
493 | } | ||
494 | } | 432 | } |
495 | } | 433 | } |
496 | 434 | ||
@@ -568,258 +506,3 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul | |||
568 | walk(pat, body, infer, &mut has_type_mismatches); | 506 | walk(pat, body, infer, &mut has_type_mismatches); |
569 | !has_type_mismatches | 507 | !has_type_mismatches |
570 | } | 508 | } |
571 | |||
572 | #[cfg(test)] | ||
573 | mod tests { | ||
574 | use crate::diagnostics::tests::check_diagnostics; | ||
575 | |||
576 | #[test] | ||
577 | fn simple_free_fn_zero() { | ||
578 | check_diagnostics( | ||
579 | r#" | ||
580 | fn zero() {} | ||
581 | fn f() { zero(1); } | ||
582 | //^^^^^^^ Expected 0 arguments, found 1 | ||
583 | "#, | ||
584 | ); | ||
585 | |||
586 | check_diagnostics( | ||
587 | r#" | ||
588 | fn zero() {} | ||
589 | fn f() { zero(); } | ||
590 | "#, | ||
591 | ); | ||
592 | } | ||
593 | |||
594 | #[test] | ||
595 | fn simple_free_fn_one() { | ||
596 | check_diagnostics( | ||
597 | r#" | ||
598 | fn one(arg: u8) {} | ||
599 | fn f() { one(); } | ||
600 | //^^^^^ Expected 1 argument, found 0 | ||
601 | "#, | ||
602 | ); | ||
603 | |||
604 | check_diagnostics( | ||
605 | r#" | ||
606 | fn one(arg: u8) {} | ||
607 | fn f() { one(1); } | ||
608 | "#, | ||
609 | ); | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn method_as_fn() { | ||
614 | check_diagnostics( | ||
615 | r#" | ||
616 | struct S; | ||
617 | impl S { fn method(&self) {} } | ||
618 | |||
619 | fn f() { | ||
620 | S::method(); | ||
621 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
622 | "#, | ||
623 | ); | ||
624 | |||
625 | check_diagnostics( | ||
626 | r#" | ||
627 | struct S; | ||
628 | impl S { fn method(&self) {} } | ||
629 | |||
630 | fn f() { | ||
631 | S::method(&S); | ||
632 | S.method(); | ||
633 | } | ||
634 | "#, | ||
635 | ); | ||
636 | } | ||
637 | |||
638 | #[test] | ||
639 | fn method_with_arg() { | ||
640 | check_diagnostics( | ||
641 | r#" | ||
642 | struct S; | ||
643 | impl S { fn method(&self, arg: u8) {} } | ||
644 | |||
645 | fn f() { | ||
646 | S.method(); | ||
647 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
648 | "#, | ||
649 | ); | ||
650 | |||
651 | check_diagnostics( | ||
652 | r#" | ||
653 | struct S; | ||
654 | impl S { fn method(&self, arg: u8) {} } | ||
655 | |||
656 | fn f() { | ||
657 | S::method(&S, 0); | ||
658 | S.method(1); | ||
659 | } | ||
660 | "#, | ||
661 | ); | ||
662 | } | ||
663 | |||
664 | #[test] | ||
665 | fn method_unknown_receiver() { | ||
666 | // note: this is incorrect code, so there might be errors on this in the | ||
667 | // future, but we shouldn't emit an argument count diagnostic here | ||
668 | check_diagnostics( | ||
669 | r#" | ||
670 | trait Foo { fn method(&self, arg: usize) {} } | ||
671 | |||
672 | fn f() { | ||
673 | let x; | ||
674 | x.method(); | ||
675 | } | ||
676 | "#, | ||
677 | ); | ||
678 | } | ||
679 | |||
680 | #[test] | ||
681 | fn tuple_struct() { | ||
682 | check_diagnostics( | ||
683 | r#" | ||
684 | struct Tup(u8, u16); | ||
685 | fn f() { | ||
686 | Tup(0); | ||
687 | } //^^^^^^ Expected 2 arguments, found 1 | ||
688 | "#, | ||
689 | ) | ||
690 | } | ||
691 | |||
692 | #[test] | ||
693 | fn enum_variant() { | ||
694 | check_diagnostics( | ||
695 | r#" | ||
696 | enum En { Variant(u8, u16), } | ||
697 | fn f() { | ||
698 | En::Variant(0); | ||
699 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
700 | "#, | ||
701 | ) | ||
702 | } | ||
703 | |||
704 | #[test] | ||
705 | fn enum_variant_type_macro() { | ||
706 | check_diagnostics( | ||
707 | r#" | ||
708 | macro_rules! Type { | ||
709 | () => { u32 }; | ||
710 | } | ||
711 | enum Foo { | ||
712 | Bar(Type![]) | ||
713 | } | ||
714 | impl Foo { | ||
715 | fn new() { | ||
716 | Foo::Bar(0); | ||
717 | Foo::Bar(0, 1); | ||
718 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
719 | Foo::Bar(); | ||
720 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
721 | } | ||
722 | } | ||
723 | "#, | ||
724 | ); | ||
725 | } | ||
726 | |||
727 | #[test] | ||
728 | fn varargs() { | ||
729 | check_diagnostics( | ||
730 | r#" | ||
731 | extern "C" { | ||
732 | fn fixed(fixed: u8); | ||
733 | fn varargs(fixed: u8, ...); | ||
734 | fn varargs2(...); | ||
735 | } | ||
736 | |||
737 | fn f() { | ||
738 | unsafe { | ||
739 | fixed(0); | ||
740 | fixed(0, 1); | ||
741 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
742 | varargs(0); | ||
743 | varargs(0, 1); | ||
744 | varargs2(); | ||
745 | varargs2(0); | ||
746 | varargs2(0, 1); | ||
747 | } | ||
748 | } | ||
749 | "#, | ||
750 | ) | ||
751 | } | ||
752 | |||
753 | #[test] | ||
754 | fn arg_count_lambda() { | ||
755 | check_diagnostics( | ||
756 | r#" | ||
757 | fn main() { | ||
758 | let f = |()| (); | ||
759 | f(); | ||
760 | //^^^ Expected 1 argument, found 0 | ||
761 | f(()); | ||
762 | f((), ()); | ||
763 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
764 | } | ||
765 | "#, | ||
766 | ) | ||
767 | } | ||
768 | |||
769 | #[test] | ||
770 | fn cfgd_out_call_arguments() { | ||
771 | check_diagnostics( | ||
772 | r#" | ||
773 | struct C(#[cfg(FALSE)] ()); | ||
774 | impl C { | ||
775 | fn new() -> Self { | ||
776 | Self( | ||
777 | #[cfg(FALSE)] | ||
778 | (), | ||
779 | ) | ||
780 | } | ||
781 | |||
782 | fn method(&self) {} | ||
783 | } | ||
784 | |||
785 | fn main() { | ||
786 | C::new().method(#[cfg(FALSE)] 0); | ||
787 | } | ||
788 | "#, | ||
789 | ); | ||
790 | } | ||
791 | |||
792 | #[test] | ||
793 | fn cfgd_out_fn_params() { | ||
794 | check_diagnostics( | ||
795 | r#" | ||
796 | fn foo(#[cfg(NEVER)] x: ()) {} | ||
797 | |||
798 | struct S; | ||
799 | |||
800 | impl S { | ||
801 | fn method(#[cfg(NEVER)] self) {} | ||
802 | fn method2(#[cfg(NEVER)] self, arg: u8) {} | ||
803 | fn method3(self, #[cfg(NEVER)] arg: u8) {} | ||
804 | } | ||
805 | |||
806 | extern "C" { | ||
807 | fn fixed(fixed: u8, #[cfg(NEVER)] ...); | ||
808 | fn varargs(#[cfg(not(NEVER))] ...); | ||
809 | } | ||
810 | |||
811 | fn main() { | ||
812 | foo(); | ||
813 | S::method(); | ||
814 | S::method2(0); | ||
815 | S::method3(S); | ||
816 | S.method3(); | ||
817 | unsafe { | ||
818 | fixed(0); | ||
819 | varargs(1, 2, 3); | ||
820 | } | ||
821 | } | ||
822 | "#, | ||
823 | ) | ||
824 | } | ||
825 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index c8e1b23de..a30e42699 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -364,960 +364,3 @@ impl PatternFoldable for PatKind { | |||
364 | } | 364 | } |
365 | } | 365 | } |
366 | } | 366 | } |
367 | |||
368 | #[cfg(test)] | ||
369 | pub(super) mod tests { | ||
370 | mod report { | ||
371 | use std::any::Any; | ||
372 | |||
373 | use hir_def::{expr::PatId, DefWithBodyId}; | ||
374 | use hir_expand::{HirFileId, InFile}; | ||
375 | use syntax::SyntaxNodePtr; | ||
376 | |||
377 | use crate::{ | ||
378 | db::HirDatabase, | ||
379 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, | ||
380 | }; | ||
381 | |||
382 | /// In tests, match check bails out loudly. | ||
383 | /// This helps to catch incorrect tests that pass due to false negatives. | ||
384 | pub(crate) fn report_bail_out( | ||
385 | db: &dyn HirDatabase, | ||
386 | def: DefWithBodyId, | ||
387 | pat: PatId, | ||
388 | sink: &mut DiagnosticSink, | ||
389 | ) { | ||
390 | let (_, source_map) = db.body_with_source_map(def); | ||
391 | if let Ok(source_ptr) = source_map.pat_syntax(pat) { | ||
392 | let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into); | ||
393 | sink.push(BailedOut { file: source_ptr.file_id, pat_syntax_ptr }); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | #[derive(Debug)] | ||
398 | struct BailedOut { | ||
399 | file: HirFileId, | ||
400 | pat_syntax_ptr: SyntaxNodePtr, | ||
401 | } | ||
402 | |||
403 | impl Diagnostic for BailedOut { | ||
404 | fn code(&self) -> DiagnosticCode { | ||
405 | DiagnosticCode("internal:match-check-bailed-out") | ||
406 | } | ||
407 | fn message(&self) -> String { | ||
408 | format!("Internal: match check bailed out") | ||
409 | } | ||
410 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
411 | InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() } | ||
412 | } | ||
413 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
414 | self | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | |||
419 | use crate::diagnostics::tests::check_diagnostics; | ||
420 | |||
421 | pub(crate) use self::report::report_bail_out; | ||
422 | |||
423 | #[test] | ||
424 | fn empty_tuple() { | ||
425 | check_diagnostics( | ||
426 | r#" | ||
427 | fn main() { | ||
428 | match () { } | ||
429 | //^^ Missing match arm | ||
430 | match (()) { } | ||
431 | //^^^^ Missing match arm | ||
432 | |||
433 | match () { _ => (), } | ||
434 | match () { () => (), } | ||
435 | match (()) { (()) => (), } | ||
436 | } | ||
437 | "#, | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn tuple_of_two_empty_tuple() { | ||
443 | check_diagnostics( | ||
444 | r#" | ||
445 | fn main() { | ||
446 | match ((), ()) { } | ||
447 | //^^^^^^^^ Missing match arm | ||
448 | |||
449 | match ((), ()) { ((), ()) => (), } | ||
450 | } | ||
451 | "#, | ||
452 | ); | ||
453 | } | ||
454 | |||
455 | #[test] | ||
456 | fn boolean() { | ||
457 | check_diagnostics( | ||
458 | r#" | ||
459 | fn test_main() { | ||
460 | match false { } | ||
461 | //^^^^^ Missing match arm | ||
462 | match false { true => (), } | ||
463 | //^^^^^ Missing match arm | ||
464 | match (false, true) {} | ||
465 | //^^^^^^^^^^^^^ Missing match arm | ||
466 | match (false, true) { (true, true) => (), } | ||
467 | //^^^^^^^^^^^^^ Missing match arm | ||
468 | match (false, true) { | ||
469 | //^^^^^^^^^^^^^ Missing match arm | ||
470 | (false, true) => (), | ||
471 | (false, false) => (), | ||
472 | (true, false) => (), | ||
473 | } | ||
474 | match (false, true) { (true, _x) => (), } | ||
475 | //^^^^^^^^^^^^^ Missing match arm | ||
476 | |||
477 | match false { true => (), false => (), } | ||
478 | match (false, true) { | ||
479 | (false, _) => (), | ||
480 | (true, false) => (), | ||
481 | (_, true) => (), | ||
482 | } | ||
483 | match (false, true) { | ||
484 | (true, true) => (), | ||
485 | (true, false) => (), | ||
486 | (false, true) => (), | ||
487 | (false, false) => (), | ||
488 | } | ||
489 | match (false, true) { | ||
490 | (true, _x) => (), | ||
491 | (false, true) => (), | ||
492 | (false, false) => (), | ||
493 | } | ||
494 | match (false, true, false) { | ||
495 | (false, ..) => (), | ||
496 | (true, ..) => (), | ||
497 | } | ||
498 | match (false, true, false) { | ||
499 | (.., false) => (), | ||
500 | (.., true) => (), | ||
501 | } | ||
502 | match (false, true, false) { (..) => (), } | ||
503 | } | ||
504 | "#, | ||
505 | ); | ||
506 | } | ||
507 | |||
508 | #[test] | ||
509 | fn tuple_of_tuple_and_bools() { | ||
510 | check_diagnostics( | ||
511 | r#" | ||
512 | fn main() { | ||
513 | match (false, ((), false)) {} | ||
514 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
515 | match (false, ((), false)) { (true, ((), true)) => (), } | ||
516 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
517 | match (false, ((), false)) { (true, _) => (), } | ||
518 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
519 | |||
520 | match (false, ((), false)) { | ||
521 | (true, ((), true)) => (), | ||
522 | (true, ((), false)) => (), | ||
523 | (false, ((), true)) => (), | ||
524 | (false, ((), false)) => (), | ||
525 | } | ||
526 | match (false, ((), false)) { | ||
527 | (true, ((), true)) => (), | ||
528 | (true, ((), false)) => (), | ||
529 | (false, _) => (), | ||
530 | } | ||
531 | } | ||
532 | "#, | ||
533 | ); | ||
534 | } | ||
535 | |||
536 | #[test] | ||
537 | fn enums() { | ||
538 | check_diagnostics( | ||
539 | r#" | ||
540 | enum Either { A, B, } | ||
541 | |||
542 | fn main() { | ||
543 | match Either::A { } | ||
544 | //^^^^^^^^^ Missing match arm | ||
545 | match Either::B { Either::A => (), } | ||
546 | //^^^^^^^^^ Missing match arm | ||
547 | |||
548 | match &Either::B { | ||
549 | //^^^^^^^^^^ Missing match arm | ||
550 | Either::A => (), | ||
551 | } | ||
552 | |||
553 | match Either::B { | ||
554 | Either::A => (), Either::B => (), | ||
555 | } | ||
556 | match &Either::B { | ||
557 | Either::A => (), Either::B => (), | ||
558 | } | ||
559 | } | ||
560 | "#, | ||
561 | ); | ||
562 | } | ||
563 | |||
564 | #[test] | ||
565 | fn enum_containing_bool() { | ||
566 | check_diagnostics( | ||
567 | r#" | ||
568 | enum Either { A(bool), B } | ||
569 | |||
570 | fn main() { | ||
571 | match Either::B { } | ||
572 | //^^^^^^^^^ Missing match arm | ||
573 | match Either::B { | ||
574 | //^^^^^^^^^ Missing match arm | ||
575 | Either::A(true) => (), Either::B => () | ||
576 | } | ||
577 | |||
578 | match Either::B { | ||
579 | Either::A(true) => (), | ||
580 | Either::A(false) => (), | ||
581 | Either::B => (), | ||
582 | } | ||
583 | match Either::B { | ||
584 | Either::B => (), | ||
585 | _ => (), | ||
586 | } | ||
587 | match Either::B { | ||
588 | Either::A(_) => (), | ||
589 | Either::B => (), | ||
590 | } | ||
591 | |||
592 | } | ||
593 | "#, | ||
594 | ); | ||
595 | } | ||
596 | |||
597 | #[test] | ||
598 | fn enum_different_sizes() { | ||
599 | check_diagnostics( | ||
600 | r#" | ||
601 | enum Either { A(bool), B(bool, bool) } | ||
602 | |||
603 | fn main() { | ||
604 | match Either::A(false) { | ||
605 | //^^^^^^^^^^^^^^^^ Missing match arm | ||
606 | Either::A(_) => (), | ||
607 | Either::B(false, _) => (), | ||
608 | } | ||
609 | |||
610 | match Either::A(false) { | ||
611 | Either::A(_) => (), | ||
612 | Either::B(true, _) => (), | ||
613 | Either::B(false, _) => (), | ||
614 | } | ||
615 | match Either::A(false) { | ||
616 | Either::A(true) | Either::A(false) => (), | ||
617 | Either::B(true, _) => (), | ||
618 | Either::B(false, _) => (), | ||
619 | } | ||
620 | } | ||
621 | "#, | ||
622 | ); | ||
623 | } | ||
624 | |||
625 | #[test] | ||
626 | fn tuple_of_enum_no_diagnostic() { | ||
627 | check_diagnostics( | ||
628 | r#" | ||
629 | enum Either { A(bool), B(bool, bool) } | ||
630 | enum Either2 { C, D } | ||
631 | |||
632 | fn main() { | ||
633 | match (Either::A(false), Either2::C) { | ||
634 | (Either::A(true), _) | (Either::A(false), _) => (), | ||
635 | (Either::B(true, _), Either2::C) => (), | ||
636 | (Either::B(false, _), Either2::C) => (), | ||
637 | (Either::B(_, _), Either2::D) => (), | ||
638 | } | ||
639 | } | ||
640 | "#, | ||
641 | ); | ||
642 | } | ||
643 | |||
644 | #[test] | ||
645 | fn or_pattern_no_diagnostic() { | ||
646 | check_diagnostics( | ||
647 | r#" | ||
648 | enum Either {A, B} | ||
649 | |||
650 | fn main() { | ||
651 | match (Either::A, Either::B) { | ||
652 | (Either::A | Either::B, _) => (), | ||
653 | } | ||
654 | }"#, | ||
655 | ) | ||
656 | } | ||
657 | |||
658 | #[test] | ||
659 | fn mismatched_types() { | ||
660 | // Match statements with arms that don't match the | ||
661 | // expression pattern do not fire this diagnostic. | ||
662 | check_diagnostics( | ||
663 | r#" | ||
664 | enum Either { A, B } | ||
665 | enum Either2 { C, D } | ||
666 | |||
667 | fn main() { | ||
668 | match Either::A { | ||
669 | Either2::C => (), | ||
670 | // ^^^^^^^^^^ Internal: match check bailed out | ||
671 | Either2::D => (), | ||
672 | } | ||
673 | match (true, false) { | ||
674 | (true, false, true) => (), | ||
675 | // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out | ||
676 | (true) => (), | ||
677 | } | ||
678 | match (true, false) { (true,) => {} } | ||
679 | // ^^^^^^^ Internal: match check bailed out | ||
680 | match (0) { () => () } | ||
681 | // ^^ Internal: match check bailed out | ||
682 | match Unresolved::Bar { Unresolved::Baz => () } | ||
683 | } | ||
684 | "#, | ||
685 | ); | ||
686 | } | ||
687 | |||
688 | #[test] | ||
689 | fn mismatched_types_in_or_patterns() { | ||
690 | check_diagnostics( | ||
691 | r#" | ||
692 | fn main() { | ||
693 | match false { true | () => {} } | ||
694 | // ^^^^^^^^^ Internal: match check bailed out | ||
695 | match (false,) { (true | (),) => {} } | ||
696 | // ^^^^^^^^^^^^ Internal: match check bailed out | ||
697 | } | ||
698 | "#, | ||
699 | ); | ||
700 | } | ||
701 | |||
702 | #[test] | ||
703 | fn malformed_match_arm_tuple_enum_missing_pattern() { | ||
704 | // We are testing to be sure we don't panic here when the match | ||
705 | // arm `Either::B` is missing its pattern. | ||
706 | check_diagnostics( | ||
707 | r#" | ||
708 | enum Either { A, B(u32) } | ||
709 | |||
710 | fn main() { | ||
711 | match Either::A { | ||
712 | Either::A => (), | ||
713 | Either::B() => (), | ||
714 | } | ||
715 | } | ||
716 | "#, | ||
717 | ); | ||
718 | } | ||
719 | |||
720 | #[test] | ||
721 | fn malformed_match_arm_extra_fields() { | ||
722 | check_diagnostics( | ||
723 | r#" | ||
724 | enum A { B(isize, isize), C } | ||
725 | fn main() { | ||
726 | match A::B(1, 2) { | ||
727 | A::B(_, _, _) => (), | ||
728 | // ^^^^^^^^^^^^^ Internal: match check bailed out | ||
729 | } | ||
730 | match A::B(1, 2) { | ||
731 | A::C(_) => (), | ||
732 | // ^^^^^^^ Internal: match check bailed out | ||
733 | } | ||
734 | } | ||
735 | "#, | ||
736 | ); | ||
737 | } | ||
738 | |||
739 | #[test] | ||
740 | fn expr_diverges() { | ||
741 | check_diagnostics( | ||
742 | r#" | ||
743 | enum Either { A, B } | ||
744 | |||
745 | fn main() { | ||
746 | match loop {} { | ||
747 | Either::A => (), | ||
748 | // ^^^^^^^^^ Internal: match check bailed out | ||
749 | Either::B => (), | ||
750 | } | ||
751 | match loop {} { | ||
752 | Either::A => (), | ||
753 | // ^^^^^^^^^ Internal: match check bailed out | ||
754 | } | ||
755 | match loop { break Foo::A } { | ||
756 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
757 | Either::A => (), | ||
758 | } | ||
759 | match loop { break Foo::A } { | ||
760 | Either::A => (), | ||
761 | Either::B => (), | ||
762 | } | ||
763 | } | ||
764 | "#, | ||
765 | ); | ||
766 | } | ||
767 | |||
768 | #[test] | ||
769 | fn expr_partially_diverges() { | ||
770 | check_diagnostics( | ||
771 | r#" | ||
772 | enum Either<T> { A(T), B } | ||
773 | |||
774 | fn foo() -> Either<!> { Either::B } | ||
775 | fn main() -> u32 { | ||
776 | match foo() { | ||
777 | Either::A(val) => val, | ||
778 | Either::B => 0, | ||
779 | } | ||
780 | } | ||
781 | "#, | ||
782 | ); | ||
783 | } | ||
784 | |||
785 | #[test] | ||
786 | fn enum_record() { | ||
787 | check_diagnostics( | ||
788 | r#" | ||
789 | enum Either { A { foo: bool }, B } | ||
790 | |||
791 | fn main() { | ||
792 | let a = Either::A { foo: true }; | ||
793 | match a { } | ||
794 | //^ Missing match arm | ||
795 | match a { Either::A { foo: true } => () } | ||
796 | //^ Missing match arm | ||
797 | match a { | ||
798 | Either::A { } => (), | ||
799 | //^^^^^^^^^ Missing structure fields: | ||
800 | // | - foo | ||
801 | Either::B => (), | ||
802 | } | ||
803 | match a { | ||
804 | //^ Missing match arm | ||
805 | Either::A { } => (), | ||
806 | } //^^^^^^^^^ Missing structure fields: | ||
807 | // | - foo | ||
808 | |||
809 | match a { | ||
810 | Either::A { foo: true } => (), | ||
811 | Either::A { foo: false } => (), | ||
812 | Either::B => (), | ||
813 | } | ||
814 | match a { | ||
815 | Either::A { foo: _ } => (), | ||
816 | Either::B => (), | ||
817 | } | ||
818 | } | ||
819 | "#, | ||
820 | ); | ||
821 | } | ||
822 | |||
823 | #[test] | ||
824 | fn enum_record_fields_out_of_order() { | ||
825 | check_diagnostics( | ||
826 | r#" | ||
827 | enum Either { | ||
828 | A { foo: bool, bar: () }, | ||
829 | B, | ||
830 | } | ||
831 | |||
832 | fn main() { | ||
833 | let a = Either::A { foo: true, bar: () }; | ||
834 | match a { | ||
835 | //^ Missing match arm | ||
836 | Either::A { bar: (), foo: false } => (), | ||
837 | Either::A { foo: true, bar: () } => (), | ||
838 | } | ||
839 | |||
840 | match a { | ||
841 | Either::A { bar: (), foo: false } => (), | ||
842 | Either::A { foo: true, bar: () } => (), | ||
843 | Either::B => (), | ||
844 | } | ||
845 | } | ||
846 | "#, | ||
847 | ); | ||
848 | } | ||
849 | |||
850 | #[test] | ||
851 | fn enum_record_ellipsis() { | ||
852 | check_diagnostics( | ||
853 | r#" | ||
854 | enum Either { | ||
855 | A { foo: bool, bar: bool }, | ||
856 | B, | ||
857 | } | ||
858 | |||
859 | fn main() { | ||
860 | let a = Either::B; | ||
861 | match a { | ||
862 | //^ Missing match arm | ||
863 | Either::A { foo: true, .. } => (), | ||
864 | Either::B => (), | ||
865 | } | ||
866 | match a { | ||
867 | //^ Missing match arm | ||
868 | Either::A { .. } => (), | ||
869 | } | ||
870 | |||
871 | match a { | ||
872 | Either::A { foo: true, .. } => (), | ||
873 | Either::A { foo: false, .. } => (), | ||
874 | Either::B => (), | ||
875 | } | ||
876 | |||
877 | match a { | ||
878 | Either::A { .. } => (), | ||
879 | Either::B => (), | ||
880 | } | ||
881 | } | ||
882 | "#, | ||
883 | ); | ||
884 | } | ||
885 | |||
886 | #[test] | ||
887 | fn enum_tuple_partial_ellipsis() { | ||
888 | check_diagnostics( | ||
889 | r#" | ||
890 | enum Either { | ||
891 | A(bool, bool, bool, bool), | ||
892 | B, | ||
893 | } | ||
894 | |||
895 | fn main() { | ||
896 | match Either::B { | ||
897 | //^^^^^^^^^ Missing match arm | ||
898 | Either::A(true, .., true) => (), | ||
899 | Either::A(true, .., false) => (), | ||
900 | Either::A(false, .., false) => (), | ||
901 | Either::B => (), | ||
902 | } | ||
903 | match Either::B { | ||
904 | //^^^^^^^^^ Missing match arm | ||
905 | Either::A(true, .., true) => (), | ||
906 | Either::A(true, .., false) => (), | ||
907 | Either::A(.., true) => (), | ||
908 | Either::B => (), | ||
909 | } | ||
910 | |||
911 | match Either::B { | ||
912 | Either::A(true, .., true) => (), | ||
913 | Either::A(true, .., false) => (), | ||
914 | Either::A(false, .., true) => (), | ||
915 | Either::A(false, .., false) => (), | ||
916 | Either::B => (), | ||
917 | } | ||
918 | match Either::B { | ||
919 | Either::A(true, .., true) => (), | ||
920 | Either::A(true, .., false) => (), | ||
921 | Either::A(.., true) => (), | ||
922 | Either::A(.., false) => (), | ||
923 | Either::B => (), | ||
924 | } | ||
925 | } | ||
926 | "#, | ||
927 | ); | ||
928 | } | ||
929 | |||
930 | #[test] | ||
931 | fn never() { | ||
932 | check_diagnostics( | ||
933 | r#" | ||
934 | enum Never {} | ||
935 | |||
936 | fn enum_(never: Never) { | ||
937 | match never {} | ||
938 | } | ||
939 | fn enum_ref(never: &Never) { | ||
940 | match never {} | ||
941 | //^^^^^ Missing match arm | ||
942 | } | ||
943 | fn bang(never: !) { | ||
944 | match never {} | ||
945 | } | ||
946 | "#, | ||
947 | ); | ||
948 | } | ||
949 | |||
950 | #[test] | ||
951 | fn unknown_type() { | ||
952 | check_diagnostics( | ||
953 | r#" | ||
954 | enum Option<T> { Some(T), None } | ||
955 | |||
956 | fn main() { | ||
957 | // `Never` is deliberately not defined so that it's an uninferred type. | ||
958 | match Option::<Never>::None { | ||
959 | None => (), | ||
960 | Some(never) => match never {}, | ||
961 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
962 | } | ||
963 | match Option::<Never>::None { | ||
964 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
965 | Option::Some(_never) => {}, | ||
966 | } | ||
967 | } | ||
968 | "#, | ||
969 | ); | ||
970 | } | ||
971 | |||
972 | #[test] | ||
973 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
974 | check_diagnostics( | ||
975 | r#" | ||
976 | fn main() { | ||
977 | match (false, true, false) { | ||
978 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
979 | (false, ..) => (), | ||
980 | } | ||
981 | }"#, | ||
982 | ); | ||
983 | } | ||
984 | |||
985 | #[test] | ||
986 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
987 | check_diagnostics( | ||
988 | r#" | ||
989 | fn main() { | ||
990 | match (false, true, false) { | ||
991 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
992 | (.., false) => (), | ||
993 | } | ||
994 | }"#, | ||
995 | ); | ||
996 | } | ||
997 | |||
998 | #[test] | ||
999 | fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() { | ||
1000 | check_diagnostics( | ||
1001 | r#" | ||
1002 | fn main() { | ||
1003 | match (false, true, false) { | ||
1004 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1005 | (true, .., false) => (), | ||
1006 | } | ||
1007 | }"#, | ||
1008 | ); | ||
1009 | } | ||
1010 | |||
1011 | #[test] | ||
1012 | fn record_struct() { | ||
1013 | check_diagnostics( | ||
1014 | r#"struct Foo { a: bool } | ||
1015 | fn main(f: Foo) { | ||
1016 | match f {} | ||
1017 | //^ Missing match arm | ||
1018 | match f { Foo { a: true } => () } | ||
1019 | //^ Missing match arm | ||
1020 | match &f { Foo { a: true } => () } | ||
1021 | //^^ Missing match arm | ||
1022 | match f { Foo { a: _ } => () } | ||
1023 | match f { | ||
1024 | Foo { a: true } => (), | ||
1025 | Foo { a: false } => (), | ||
1026 | } | ||
1027 | match &f { | ||
1028 | Foo { a: true } => (), | ||
1029 | Foo { a: false } => (), | ||
1030 | } | ||
1031 | } | ||
1032 | "#, | ||
1033 | ); | ||
1034 | } | ||
1035 | |||
1036 | #[test] | ||
1037 | fn tuple_struct() { | ||
1038 | check_diagnostics( | ||
1039 | r#"struct Foo(bool); | ||
1040 | fn main(f: Foo) { | ||
1041 | match f {} | ||
1042 | //^ Missing match arm | ||
1043 | match f { Foo(true) => () } | ||
1044 | //^ Missing match arm | ||
1045 | match f { | ||
1046 | Foo(true) => (), | ||
1047 | Foo(false) => (), | ||
1048 | } | ||
1049 | } | ||
1050 | "#, | ||
1051 | ); | ||
1052 | } | ||
1053 | |||
1054 | #[test] | ||
1055 | fn unit_struct() { | ||
1056 | check_diagnostics( | ||
1057 | r#"struct Foo; | ||
1058 | fn main(f: Foo) { | ||
1059 | match f {} | ||
1060 | //^ Missing match arm | ||
1061 | match f { Foo => () } | ||
1062 | } | ||
1063 | "#, | ||
1064 | ); | ||
1065 | } | ||
1066 | |||
1067 | #[test] | ||
1068 | fn record_struct_ellipsis() { | ||
1069 | check_diagnostics( | ||
1070 | r#"struct Foo { foo: bool, bar: bool } | ||
1071 | fn main(f: Foo) { | ||
1072 | match f { Foo { foo: true, .. } => () } | ||
1073 | //^ Missing match arm | ||
1074 | match f { | ||
1075 | //^ Missing match arm | ||
1076 | Foo { foo: true, .. } => (), | ||
1077 | Foo { bar: false, .. } => () | ||
1078 | } | ||
1079 | match f { Foo { .. } => () } | ||
1080 | match f { | ||
1081 | Foo { foo: true, .. } => (), | ||
1082 | Foo { foo: false, .. } => () | ||
1083 | } | ||
1084 | } | ||
1085 | "#, | ||
1086 | ); | ||
1087 | } | ||
1088 | |||
1089 | #[test] | ||
1090 | fn internal_or() { | ||
1091 | check_diagnostics( | ||
1092 | r#" | ||
1093 | fn main() { | ||
1094 | enum Either { A(bool), B } | ||
1095 | match Either::B { | ||
1096 | //^^^^^^^^^ Missing match arm | ||
1097 | Either::A(true | false) => (), | ||
1098 | } | ||
1099 | } | ||
1100 | "#, | ||
1101 | ); | ||
1102 | } | ||
1103 | |||
1104 | #[test] | ||
1105 | fn no_panic_at_unimplemented_subpattern_type() { | ||
1106 | check_diagnostics( | ||
1107 | r#" | ||
1108 | struct S { a: char} | ||
1109 | fn main(v: S) { | ||
1110 | match v { S{ a } => {} } | ||
1111 | match v { S{ a: _x } => {} } | ||
1112 | match v { S{ a: 'a' } => {} } | ||
1113 | //^^^^^^^^^^^ Internal: match check bailed out | ||
1114 | match v { S{..} => {} } | ||
1115 | match v { _ => {} } | ||
1116 | match v { } | ||
1117 | //^ Missing match arm | ||
1118 | } | ||
1119 | "#, | ||
1120 | ); | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1124 | fn binding() { | ||
1125 | check_diagnostics( | ||
1126 | r#" | ||
1127 | fn main() { | ||
1128 | match true { | ||
1129 | _x @ true => {} | ||
1130 | false => {} | ||
1131 | } | ||
1132 | match true { _x @ true => {} } | ||
1133 | //^^^^ Missing match arm | ||
1134 | } | ||
1135 | "#, | ||
1136 | ); | ||
1137 | } | ||
1138 | |||
1139 | #[test] | ||
1140 | fn binding_ref_has_correct_type() { | ||
1141 | // Asserts `PatKind::Binding(ref _x): bool`, not &bool. | ||
1142 | // If that's not true match checking will panic with "incompatible constructors" | ||
1143 | // FIXME: make facilities to test this directly like `tests::check_infer(..)` | ||
1144 | check_diagnostics( | ||
1145 | r#" | ||
1146 | enum Foo { A } | ||
1147 | fn main() { | ||
1148 | // FIXME: this should not bail out but current behavior is such as the old algorithm. | ||
1149 | // ExprValidator::validate_match(..) checks types of top level patterns incorrecly. | ||
1150 | match Foo::A { | ||
1151 | ref _x => {} | ||
1152 | // ^^^^^^ Internal: match check bailed out | ||
1153 | Foo::A => {} | ||
1154 | } | ||
1155 | match (true,) { | ||
1156 | (ref _x,) => {} | ||
1157 | (true,) => {} | ||
1158 | } | ||
1159 | } | ||
1160 | "#, | ||
1161 | ); | ||
1162 | } | ||
1163 | |||
1164 | #[test] | ||
1165 | fn enum_non_exhaustive() { | ||
1166 | check_diagnostics( | ||
1167 | r#" | ||
1168 | //- /lib.rs crate:lib | ||
1169 | #[non_exhaustive] | ||
1170 | pub enum E { A, B } | ||
1171 | fn _local() { | ||
1172 | match E::A { _ => {} } | ||
1173 | match E::A { | ||
1174 | E::A => {} | ||
1175 | E::B => {} | ||
1176 | } | ||
1177 | match E::A { | ||
1178 | E::A | E::B => {} | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | //- /main.rs crate:main deps:lib | ||
1183 | use lib::E; | ||
1184 | fn main() { | ||
1185 | match E::A { _ => {} } | ||
1186 | match E::A { | ||
1187 | //^^^^ Missing match arm | ||
1188 | E::A => {} | ||
1189 | E::B => {} | ||
1190 | } | ||
1191 | match E::A { | ||
1192 | //^^^^ Missing match arm | ||
1193 | E::A | E::B => {} | ||
1194 | } | ||
1195 | } | ||
1196 | "#, | ||
1197 | ); | ||
1198 | } | ||
1199 | |||
1200 | #[test] | ||
1201 | fn match_guard() { | ||
1202 | check_diagnostics( | ||
1203 | r#" | ||
1204 | fn main() { | ||
1205 | match true { | ||
1206 | true if false => {} | ||
1207 | true => {} | ||
1208 | false => {} | ||
1209 | } | ||
1210 | match true { | ||
1211 | //^^^^ Missing match arm | ||
1212 | true if false => {} | ||
1213 | false => {} | ||
1214 | } | ||
1215 | "#, | ||
1216 | ); | ||
1217 | } | ||
1218 | |||
1219 | #[test] | ||
1220 | fn pattern_type_is_of_substitution() { | ||
1221 | cov_mark::check!(match_check_wildcard_expanded_to_substitutions); | ||
1222 | check_diagnostics( | ||
1223 | r#" | ||
1224 | struct Foo<T>(T); | ||
1225 | struct Bar; | ||
1226 | fn main() { | ||
1227 | match Foo(Bar) { | ||
1228 | _ | Foo(Bar) => {} | ||
1229 | } | ||
1230 | } | ||
1231 | "#, | ||
1232 | ); | ||
1233 | } | ||
1234 | |||
1235 | #[test] | ||
1236 | fn record_struct_no_such_field() { | ||
1237 | check_diagnostics( | ||
1238 | r#" | ||
1239 | struct Foo { } | ||
1240 | fn main(f: Foo) { | ||
1241 | match f { Foo { bar } => () } | ||
1242 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
1243 | } | ||
1244 | "#, | ||
1245 | ); | ||
1246 | } | ||
1247 | |||
1248 | #[test] | ||
1249 | fn match_ergonomics_issue_9095() { | ||
1250 | check_diagnostics( | ||
1251 | r#" | ||
1252 | enum Foo<T> { A(T) } | ||
1253 | fn main() { | ||
1254 | match &Foo::A(true) { | ||
1255 | _ => {} | ||
1256 | Foo::A(_) => {} | ||
1257 | } | ||
1258 | } | ||
1259 | "#, | ||
1260 | ); | ||
1261 | } | ||
1262 | |||
1263 | mod false_negatives { | ||
1264 | //! The implementation of match checking here is a work in progress. As we roll this out, we | ||
1265 | //! prefer false negatives to false positives (ideally there would be no false positives). This | ||
1266 | //! test module should document known false negatives. Eventually we will have a complete | ||
1267 | //! implementation of match checking and this module will be empty. | ||
1268 | //! | ||
1269 | //! The reasons for documenting known false negatives: | ||
1270 | //! | ||
1271 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | ||
1272 | //! 2. It ensures the code doesn't panic when handling these cases. | ||
1273 | use super::*; | ||
1274 | |||
1275 | #[test] | ||
1276 | fn integers() { | ||
1277 | // We don't currently check integer exhaustiveness. | ||
1278 | check_diagnostics( | ||
1279 | r#" | ||
1280 | fn main() { | ||
1281 | match 5 { | ||
1282 | 10 => (), | ||
1283 | // ^^ Internal: match check bailed out | ||
1284 | 11..20 => (), | ||
1285 | } | ||
1286 | } | ||
1287 | "#, | ||
1288 | ); | ||
1289 | } | ||
1290 | |||
1291 | #[test] | ||
1292 | fn reference_patterns_at_top_level() { | ||
1293 | check_diagnostics( | ||
1294 | r#" | ||
1295 | fn main() { | ||
1296 | match &false { | ||
1297 | &true => {} | ||
1298 | // ^^^^^ Internal: match check bailed out | ||
1299 | } | ||
1300 | } | ||
1301 | "#, | ||
1302 | ); | ||
1303 | } | ||
1304 | |||
1305 | #[test] | ||
1306 | fn reference_patterns_in_fields() { | ||
1307 | check_diagnostics( | ||
1308 | r#" | ||
1309 | fn main() { | ||
1310 | match (&false,) { | ||
1311 | (true,) => {} | ||
1312 | // ^^^^^^^ Internal: match check bailed out | ||
1313 | } | ||
1314 | match (&false,) { | ||
1315 | (&true,) => {} | ||
1316 | // ^^^^^^^^ Internal: match check bailed out | ||
1317 | } | ||
1318 | } | ||
1319 | "#, | ||
1320 | ); | ||
1321 | } | ||
1322 | } | ||
1323 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs index 1f4219b42..222141bd6 100644 --- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs | |||
@@ -664,7 +664,6 @@ impl Fields { | |||
664 | let is_non_exhaustive = | 664 | let is_non_exhaustive = |
665 | is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; | 665 | is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; |
666 | 666 | ||
667 | cov_mark::hit!(match_check_wildcard_expanded_to_substitutions); | ||
668 | let field_ty_data = cx.db.field_types(variant_id); | 667 | let field_ty_data = cx.db.field_types(variant_id); |
669 | let field_tys = || { | 668 | let field_tys = || { |
670 | field_ty_data | 669 | field_ty_data |
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index c3c483425..777f347b8 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | //! Provides validations for unsafe code. Currently checks if unsafe functions are missing | 1 | //! Provides validations for unsafe code. Currently checks if unsafe functions are missing |
2 | //! unsafe blocks. | 2 | //! unsafe blocks. |
3 | 3 | ||
4 | use std::sync::Arc; | ||
5 | |||
6 | use hir_def::{ | 4 | use hir_def::{ |
7 | body::Body, | 5 | body::Body, |
8 | expr::{Expr, ExprId, UnaryOp}, | 6 | expr::{Expr, ExprId, UnaryOp}, |
@@ -10,60 +8,32 @@ use hir_def::{ | |||
10 | DefWithBodyId, | 8 | DefWithBodyId, |
11 | }; | 9 | }; |
12 | 10 | ||
13 | use crate::{ | 11 | use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind}; |
14 | db::HirDatabase, diagnostics::MissingUnsafe, diagnostics_sink::DiagnosticSink, InferenceResult, | ||
15 | Interner, TyExt, TyKind, | ||
16 | }; | ||
17 | 12 | ||
18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 13 | pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> { |
19 | owner: DefWithBodyId, | 14 | let infer = db.infer(def); |
20 | infer: Arc<InferenceResult>, | ||
21 | sink: &'a mut DiagnosticSink<'b>, | ||
22 | } | ||
23 | 15 | ||
24 | impl<'a, 'b> UnsafeValidator<'a, 'b> { | 16 | let is_unsafe = match def { |
25 | pub(super) fn new( | 17 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), |
26 | owner: DefWithBodyId, | 18 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, |
27 | infer: Arc<InferenceResult>, | 19 | }; |
28 | sink: &'a mut DiagnosticSink<'b>, | 20 | if is_unsafe { |
29 | ) -> UnsafeValidator<'a, 'b> { | 21 | return Vec::new(); |
30 | UnsafeValidator { owner, infer, sink } | ||
31 | } | 22 | } |
32 | 23 | ||
33 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { | 24 | unsafe_expressions(db, &infer, def) |
34 | let def = self.owner; | 25 | .into_iter() |
35 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); | 26 | .filter(|it| !it.inside_unsafe_block) |
36 | let is_unsafe = match self.owner { | 27 | .map(|it| it.expr) |
37 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), | 28 | .collect() |
38 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, | ||
39 | }; | ||
40 | if is_unsafe | ||
41 | || unsafe_expressions | ||
42 | .iter() | ||
43 | .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) | ||
44 | .count() | ||
45 | == 0 | ||
46 | { | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | let (_, body_source) = db.body_with_source_map(def); | ||
51 | for unsafe_expr in unsafe_expressions { | ||
52 | if !unsafe_expr.inside_unsafe_block { | ||
53 | if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) { | ||
54 | self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | 29 | } |
60 | 30 | ||
61 | pub(crate) struct UnsafeExpr { | 31 | struct UnsafeExpr { |
62 | pub(crate) expr: ExprId, | 32 | pub(crate) expr: ExprId, |
63 | pub(crate) inside_unsafe_block: bool, | 33 | pub(crate) inside_unsafe_block: bool, |
64 | } | 34 | } |
65 | 35 | ||
66 | pub(crate) fn unsafe_expressions( | 36 | fn unsafe_expressions( |
67 | db: &dyn HirDatabase, | 37 | db: &dyn HirDatabase, |
68 | infer: &InferenceResult, | 38 | infer: &InferenceResult, |
69 | def: DefWithBodyId, | 39 | def: DefWithBodyId, |
@@ -126,92 +96,3 @@ fn walk_unsafe( | |||
126 | walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); | 96 | walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); |
127 | }); | 97 | }); |
128 | } | 98 | } |
129 | |||
130 | #[cfg(test)] | ||
131 | mod tests { | ||
132 | use crate::diagnostics::tests::check_diagnostics; | ||
133 | |||
134 | #[test] | ||
135 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
136 | check_diagnostics( | ||
137 | r#" | ||
138 | fn main() { | ||
139 | let x = &5 as *const usize; | ||
140 | unsafe { let y = *x; } | ||
141 | let z = *x; | ||
142 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
143 | "#, | ||
144 | ) | ||
145 | } | ||
146 | |||
147 | #[test] | ||
148 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
149 | check_diagnostics( | ||
150 | r#" | ||
151 | struct HasUnsafe; | ||
152 | |||
153 | impl HasUnsafe { | ||
154 | unsafe fn unsafe_fn(&self) { | ||
155 | let x = &5 as *const usize; | ||
156 | let y = *x; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | unsafe fn unsafe_fn() { | ||
161 | let x = &5 as *const usize; | ||
162 | let y = *x; | ||
163 | } | ||
164 | |||
165 | fn main() { | ||
166 | unsafe_fn(); | ||
167 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
168 | HasUnsafe.unsafe_fn(); | ||
169 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
170 | unsafe { | ||
171 | unsafe_fn(); | ||
172 | HasUnsafe.unsafe_fn(); | ||
173 | } | ||
174 | } | ||
175 | "#, | ||
176 | ); | ||
177 | } | ||
178 | |||
179 | #[test] | ||
180 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
181 | check_diagnostics( | ||
182 | r#" | ||
183 | struct Ty { | ||
184 | a: u8, | ||
185 | } | ||
186 | |||
187 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
188 | |||
189 | fn main() { | ||
190 | let x = STATIC_MUT.a; | ||
191 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
192 | unsafe { | ||
193 | let x = STATIC_MUT.a; | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
202 | check_diagnostics( | ||
203 | r#" | ||
204 | extern "rust-intrinsic" { | ||
205 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
206 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
207 | } | ||
208 | |||
209 | fn main() { | ||
210 | let _ = bitreverse(12); | ||
211 | let _ = floorf32(12.0); | ||
212 | //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
213 | } | ||
214 | "#, | ||
215 | ); | ||
216 | } | ||
217 | } | ||
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 0e9f777da..f023c1fb7 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -35,11 +35,9 @@ use stdx::impl_from; | |||
35 | use syntax::SmolStr; | 35 | use syntax::SmolStr; |
36 | 36 | ||
37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; | 37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; |
38 | use crate::diagnostics_sink::DiagnosticSink; | ||
39 | use crate::{ | 38 | use crate::{ |
40 | db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, | 39 | db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, |
41 | lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, | 40 | Goal, Interner, Substitution, TyBuilder, TyExt, TyKind, |
42 | TyBuilder, TyExt, TyKind, | ||
43 | }; | 41 | }; |
44 | 42 | ||
45 | // This lint has a false positive here. See the link below for details. | 43 | // This lint has a false positive here. See the link below for details. |
@@ -111,6 +109,12 @@ pub(crate) struct InferOk { | |||
111 | pub(crate) struct TypeError; | 109 | pub(crate) struct TypeError; |
112 | pub(crate) type InferResult = Result<InferOk, TypeError>; | 110 | pub(crate) type InferResult = Result<InferOk, TypeError>; |
113 | 111 | ||
112 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
113 | pub enum InferenceDiagnostic { | ||
114 | NoSuchField { expr: ExprId }, | ||
115 | BreakOutsideOfLoop { expr: ExprId }, | ||
116 | } | ||
117 | |||
114 | /// A mismatch between an expected and an inferred type. | 118 | /// A mismatch between an expected and an inferred type. |
115 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 119 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
116 | pub struct TypeMismatch { | 120 | pub struct TypeMismatch { |
@@ -140,7 +144,7 @@ pub struct InferenceResult { | |||
140 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, | 144 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, |
141 | /// For each associated item record what it resolves to | 145 | /// For each associated item record what it resolves to |
142 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, | 146 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, |
143 | diagnostics: Vec<InferenceDiagnostic>, | 147 | pub diagnostics: Vec<InferenceDiagnostic>, |
144 | pub type_of_expr: ArenaMap<ExprId, Ty>, | 148 | pub type_of_expr: ArenaMap<ExprId, Ty>, |
145 | /// For each pattern record the type it resolves to. | 149 | /// For each pattern record the type it resolves to. |
146 | /// | 150 | /// |
@@ -191,14 +195,6 @@ impl InferenceResult { | |||
191 | _ => None, | 195 | _ => None, |
192 | }) | 196 | }) |
193 | } | 197 | } |
194 | pub fn add_diagnostics( | ||
195 | &self, | ||
196 | db: &dyn HirDatabase, | ||
197 | owner: DefWithBodyId, | ||
198 | sink: &mut DiagnosticSink, | ||
199 | ) { | ||
200 | self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) | ||
201 | } | ||
202 | } | 198 | } |
203 | 199 | ||
204 | impl Index<ExprId> for InferenceResult { | 200 | impl Index<ExprId> for InferenceResult { |
@@ -765,6 +761,38 @@ impl Expectation { | |||
765 | Expectation::RValueLikeUnsized(_) | Expectation::None => None, | 761 | Expectation::RValueLikeUnsized(_) | Expectation::None => None, |
766 | } | 762 | } |
767 | } | 763 | } |
764 | |||
765 | /// Comment copied from rustc: | ||
766 | /// Disregard "castable to" expectations because they | ||
767 | /// can lead us astray. Consider for example `if cond | ||
768 | /// {22} else {c} as u8` -- if we propagate the | ||
769 | /// "castable to u8" constraint to 22, it will pick the | ||
770 | /// type 22u8, which is overly constrained (c might not | ||
771 | /// be a u8). In effect, the problem is that the | ||
772 | /// "castable to" expectation is not the tightest thing | ||
773 | /// we can say, so we want to drop it in this case. | ||
774 | /// The tightest thing we can say is "must unify with | ||
775 | /// else branch". Note that in the case of a "has type" | ||
776 | /// constraint, this limitation does not hold. | ||
777 | /// | ||
778 | /// If the expected type is just a type variable, then don't use | ||
779 | /// an expected type. Otherwise, we might write parts of the type | ||
780 | /// when checking the 'then' block which are incompatible with the | ||
781 | /// 'else' branch. | ||
782 | fn adjust_for_branches(&self, table: &mut unify::InferenceTable) -> Expectation { | ||
783 | match self { | ||
784 | Expectation::HasType(ety) => { | ||
785 | let ety = table.resolve_ty_shallow(&ety); | ||
786 | if !ety.is_ty_var() { | ||
787 | Expectation::HasType(ety) | ||
788 | } else { | ||
789 | Expectation::None | ||
790 | } | ||
791 | } | ||
792 | Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()), | ||
793 | _ => Expectation::None, | ||
794 | } | ||
795 | } | ||
768 | } | 796 | } |
769 | 797 | ||
770 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | 798 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] |
@@ -804,43 +832,3 @@ impl std::ops::BitOrAssign for Diverges { | |||
804 | *self = *self | other; | 832 | *self = *self | other; |
805 | } | 833 | } |
806 | } | 834 | } |
807 | |||
808 | mod diagnostics { | ||
809 | use hir_def::{expr::ExprId, DefWithBodyId}; | ||
810 | |||
811 | use crate::{ | ||
812 | db::HirDatabase, | ||
813 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | ||
814 | diagnostics_sink::DiagnosticSink, | ||
815 | }; | ||
816 | |||
817 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
818 | pub(super) enum InferenceDiagnostic { | ||
819 | NoSuchField { expr: ExprId }, | ||
820 | BreakOutsideOfLoop { expr: ExprId }, | ||
821 | } | ||
822 | |||
823 | impl InferenceDiagnostic { | ||
824 | pub(super) fn add_to( | ||
825 | &self, | ||
826 | db: &dyn HirDatabase, | ||
827 | owner: DefWithBodyId, | ||
828 | sink: &mut DiagnosticSink, | ||
829 | ) { | ||
830 | match self { | ||
831 | InferenceDiagnostic::NoSuchField { expr } => { | ||
832 | let (_, source_map) = db.body_with_source_map(owner); | ||
833 | let field = source_map.field_syntax(*expr); | ||
834 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | ||
835 | } | ||
836 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
837 | let (_, source_map) = db.body_with_source_map(owner); | ||
838 | let ptr = source_map | ||
839 | .expr_syntax(*expr) | ||
840 | .expect("break outside of loop in synthetic syntax"); | ||
841 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
842 | } | ||
843 | } | ||
844 | } | ||
845 | } | ||
846 | } | ||
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index f73bf43b2..e34f194ff 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -337,10 +337,15 @@ impl<'a> InferenceContext<'a> { | |||
337 | Expr::Match { expr, arms } => { | 337 | Expr::Match { expr, arms } => { |
338 | let input_ty = self.infer_expr(*expr, &Expectation::none()); | 338 | let input_ty = self.infer_expr(*expr, &Expectation::none()); |
339 | 339 | ||
340 | let expected = expected.adjust_for_branches(&mut self.table); | ||
341 | |||
340 | let mut result_ty = if arms.is_empty() { | 342 | let mut result_ty = if arms.is_empty() { |
341 | TyKind::Never.intern(&Interner) | 343 | TyKind::Never.intern(&Interner) |
342 | } else { | 344 | } else { |
343 | self.table.new_type_var() | 345 | match &expected { |
346 | Expectation::HasType(ty) => ty.clone(), | ||
347 | _ => self.table.new_type_var(), | ||
348 | } | ||
344 | }; | 349 | }; |
345 | 350 | ||
346 | let matchee_diverges = self.diverges; | 351 | let matchee_diverges = self.diverges; |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 50e0d6333..128cae830 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -21,7 +21,6 @@ mod utils; | |||
21 | mod walk; | 21 | mod walk; |
22 | pub mod db; | 22 | pub mod db; |
23 | pub mod diagnostics; | 23 | pub mod diagnostics; |
24 | pub mod diagnostics_sink; | ||
25 | pub mod display; | 24 | pub mod display; |
26 | pub mod method_resolution; | 25 | pub mod method_resolution; |
27 | pub mod primitive; | 26 | pub mod primitive; |
@@ -50,7 +49,7 @@ use crate::{db::HirDatabase, utils::generics}; | |||
50 | pub use autoderef::autoderef; | 49 | pub use autoderef::autoderef; |
51 | pub use builder::TyBuilder; | 50 | pub use builder::TyBuilder; |
52 | pub use chalk_ext::*; | 51 | pub use chalk_ext::*; |
53 | pub use infer::{could_unify, InferenceResult}; | 52 | pub use infer::{could_unify, InferenceDiagnostic, InferenceResult}; |
54 | pub use interner::Interner; | 53 | pub use interner::Interner; |
55 | pub use lower::{ | 54 | pub use lower::{ |
56 | associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, | 55 | associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 9d726b024..b873585c4 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -9,7 +9,7 @@ mod macros; | |||
9 | mod display_source_code; | 9 | mod display_source_code; |
10 | mod incremental; | 10 | mod incremental; |
11 | 11 | ||
12 | use std::{env, sync::Arc}; | 12 | use std::{collections::HashMap, env, sync::Arc}; |
13 | 13 | ||
14 | use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; | 14 | use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; |
15 | use expect_test::Expect; | 15 | use expect_test::Expect; |
@@ -83,9 +83,105 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) { | |||
83 | checked_one = true; | 83 | checked_one = true; |
84 | } | 84 | } |
85 | } | 85 | } |
86 | |||
86 | assert!(checked_one, "no `//^` annotations found"); | 87 | assert!(checked_one, "no `//^` annotations found"); |
87 | } | 88 | } |
88 | 89 | ||
90 | fn check_no_mismatches(ra_fixture: &str) { | ||
91 | check_mismatches_impl(ra_fixture, true) | ||
92 | } | ||
93 | |||
94 | #[allow(unused)] | ||
95 | fn check_mismatches(ra_fixture: &str) { | ||
96 | check_mismatches_impl(ra_fixture, false) | ||
97 | } | ||
98 | |||
99 | fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { | ||
100 | let _tracing = setup_tracing(); | ||
101 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | ||
102 | let module = db.module_for_file(file_id); | ||
103 | let def_map = module.def_map(&db); | ||
104 | |||
105 | let mut defs: Vec<DefWithBodyId> = Vec::new(); | ||
106 | visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); | ||
107 | defs.sort_by_key(|def| match def { | ||
108 | DefWithBodyId::FunctionId(it) => { | ||
109 | let loc = it.lookup(&db); | ||
110 | loc.source(&db).value.syntax().text_range().start() | ||
111 | } | ||
112 | DefWithBodyId::ConstId(it) => { | ||
113 | let loc = it.lookup(&db); | ||
114 | loc.source(&db).value.syntax().text_range().start() | ||
115 | } | ||
116 | DefWithBodyId::StaticId(it) => { | ||
117 | let loc = it.lookup(&db); | ||
118 | loc.source(&db).value.syntax().text_range().start() | ||
119 | } | ||
120 | }); | ||
121 | let mut mismatches = HashMap::new(); | ||
122 | let mut push_mismatch = |src_ptr: InFile<SyntaxNode>, mismatch: TypeMismatch| { | ||
123 | let range = src_ptr.value.text_range(); | ||
124 | if src_ptr.file_id.call_node(&db).is_some() { | ||
125 | panic!("type mismatch in macro expansion"); | ||
126 | } | ||
127 | let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range }; | ||
128 | let actual = format!( | ||
129 | "expected {}, got {}", | ||
130 | mismatch.expected.display_test(&db), | ||
131 | mismatch.actual.display_test(&db) | ||
132 | ); | ||
133 | mismatches.insert(file_range, actual); | ||
134 | }; | ||
135 | for def in defs { | ||
136 | let (_body, body_source_map) = db.body_with_source_map(def); | ||
137 | let inference_result = db.infer(def); | ||
138 | for (pat, mismatch) in inference_result.pat_type_mismatches() { | ||
139 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | ||
140 | Ok(sp) => { | ||
141 | let root = db.parse_or_expand(sp.file_id).unwrap(); | ||
142 | sp.map(|ptr| { | ||
143 | ptr.either( | ||
144 | |it| it.to_node(&root).syntax().clone(), | ||
145 | |it| it.to_node(&root).syntax().clone(), | ||
146 | ) | ||
147 | }) | ||
148 | } | ||
149 | Err(SyntheticSyntax) => continue, | ||
150 | }; | ||
151 | push_mismatch(syntax_ptr, mismatch.clone()); | ||
152 | } | ||
153 | for (expr, mismatch) in inference_result.expr_type_mismatches() { | ||
154 | let node = match body_source_map.expr_syntax(expr) { | ||
155 | Ok(sp) => { | ||
156 | let root = db.parse_or_expand(sp.file_id).unwrap(); | ||
157 | sp.map(|ptr| ptr.to_node(&root).syntax().clone()) | ||
158 | } | ||
159 | Err(SyntheticSyntax) => continue, | ||
160 | }; | ||
161 | push_mismatch(node, mismatch.clone()); | ||
162 | } | ||
163 | } | ||
164 | let mut checked_one = false; | ||
165 | for (file_id, annotations) in db.extract_annotations() { | ||
166 | for (range, expected) in annotations { | ||
167 | let file_range = FileRange { file_id, range }; | ||
168 | if let Some(mismatch) = mismatches.remove(&file_range) { | ||
169 | assert_eq!(mismatch, expected); | ||
170 | } else { | ||
171 | assert!(false, "Expected mismatch not encountered: {}\n", expected); | ||
172 | } | ||
173 | checked_one = true; | ||
174 | } | ||
175 | } | ||
176 | let mut buf = String::new(); | ||
177 | for (range, mismatch) in mismatches { | ||
178 | format_to!(buf, "{:?}: {}\n", range.range, mismatch,); | ||
179 | } | ||
180 | assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf); | ||
181 | |||
182 | assert!(checked_one || allow_none, "no `//^` annotations found"); | ||
183 | } | ||
184 | |||
89 | fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { | 185 | fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { |
90 | let file = db.parse(pos.file_id).ok().unwrap(); | 186 | let file = db.parse(pos.file_id).ok().unwrap(); |
91 | let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); | 187 | let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); |
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 6dac7e103..71047703d 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | 2 | ||
3 | use super::{check_infer, check_infer_with_mismatches, check_types}; | 3 | use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_block_expr_type_mismatch() { | 6 | fn infer_block_expr_type_mismatch() { |
@@ -963,7 +963,7 @@ fn test() -> i32 { | |||
963 | 963 | ||
964 | #[test] | 964 | #[test] |
965 | fn panic_macro() { | 965 | fn panic_macro() { |
966 | check_infer_with_mismatches( | 966 | check_no_mismatches( |
967 | r#" | 967 | r#" |
968 | mod panic { | 968 | mod panic { |
969 | #[macro_export] | 969 | #[macro_export] |
@@ -991,15 +991,34 @@ fn main() { | |||
991 | panic!() | 991 | panic!() |
992 | } | 992 | } |
993 | "#, | 993 | "#, |
994 | expect![[r#" | 994 | ); |
995 | 174..185 '{ loop {} }': ! | 995 | } |
996 | 176..183 'loop {}': ! | 996 | |
997 | 181..183 '{}': () | 997 | #[test] |
998 | !0..24 '$crate...:panic': fn panic() -> ! | 998 | fn coerce_unsize_expected_type() { |
999 | !0..26 '$crate...anic()': ! | 999 | check_no_mismatches( |
1000 | !0..26 '$crate...anic()': ! | 1000 | r#" |
1001 | !0..28 '$crate...015!()': ! | 1001 | #[lang = "sized"] |
1002 | 454..470 '{ ...c!() }': () | 1002 | pub trait Sized {} |
1003 | "#]], | 1003 | #[lang = "unsize"] |
1004 | pub trait Unsize<T> {} | ||
1005 | #[lang = "coerce_unsized"] | ||
1006 | pub trait CoerceUnsized<T> {} | ||
1007 | |||
1008 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
1009 | |||
1010 | fn main() { | ||
1011 | let foo: &[u32] = &[1, 2]; | ||
1012 | let foo: &[u32] = match true { | ||
1013 | true => &[1, 2], | ||
1014 | false => &[1, 2, 3], | ||
1015 | }; | ||
1016 | let foo: &[u32] = if true { | ||
1017 | &[1, 2] | ||
1018 | } else { | ||
1019 | &[1, 2, 3] | ||
1020 | }; | ||
1021 | } | ||
1022 | "#, | ||
1004 | ); | 1023 | ); |
1005 | } | 1024 | } |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 7d00cee9b..aa513c56d 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | 2 | ||
3 | use super::{check_infer, check_infer_with_mismatches, check_types}; | 3 | use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_pattern() { | 6 | fn infer_pattern() { |
@@ -518,47 +518,24 @@ fn infer_generics_in_patterns() { | |||
518 | 518 | ||
519 | #[test] | 519 | #[test] |
520 | fn infer_const_pattern() { | 520 | fn infer_const_pattern() { |
521 | check_infer_with_mismatches( | 521 | check_mismatches( |
522 | r#" | 522 | r#" |
523 | enum Option<T> { None } | 523 | enum Option<T> { None } |
524 | use Option::None; | 524 | use Option::None; |
525 | struct Foo; | 525 | struct Foo; |
526 | const Bar: usize = 1; | 526 | const Bar: usize = 1; |
527 | 527 | ||
528 | fn test() { | 528 | fn test() { |
529 | let a: Option<u32> = None; | 529 | let a: Option<u32> = None; |
530 | let b: Option<i64> = match a { | 530 | let b: Option<i64> = match a { |
531 | None => None, | 531 | None => None, |
532 | }; | 532 | }; |
533 | let _: () = match () { Foo => Foo }; // Expected mismatch | 533 | let _: () = match () { Foo => () }; |
534 | let _: () = match () { Bar => Bar }; // Expected mismatch | 534 | // ^^^ expected (), got Foo |
535 | } | 535 | let _: () = match () { Bar => () }; |
536 | // ^^^ expected (), got usize | ||
537 | } | ||
536 | "#, | 538 | "#, |
537 | expect![[r#" | ||
538 | 73..74 '1': usize | ||
539 | 87..309 '{ ...atch }': () | ||
540 | 97..98 'a': Option<u32> | ||
541 | 114..118 'None': Option<u32> | ||
542 | 128..129 'b': Option<i64> | ||
543 | 145..182 'match ... }': Option<i64> | ||
544 | 151..152 'a': Option<u32> | ||
545 | 163..167 'None': Option<u32> | ||
546 | 171..175 'None': Option<i64> | ||
547 | 192..193 '_': () | ||
548 | 200..223 'match ... Foo }': Foo | ||
549 | 206..208 '()': () | ||
550 | 211..214 'Foo': Foo | ||
551 | 218..221 'Foo': Foo | ||
552 | 254..255 '_': () | ||
553 | 262..285 'match ... Bar }': usize | ||
554 | 268..270 '()': () | ||
555 | 273..276 'Bar': usize | ||
556 | 280..283 'Bar': usize | ||
557 | 200..223: expected (), got Foo | ||
558 | 211..214: expected (), got Foo | ||
559 | 262..285: expected (), got usize | ||
560 | 273..276: expected (), got usize | ||
561 | "#]], | ||
562 | ); | 539 | ); |
563 | } | 540 | } |
564 | 541 | ||
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 88f3d09d3..f12928225 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | indexmap = "1.4.0" | 15 | indexmap = "1.4.0" |
16 | itertools = "0.10.0" | 16 | itertools = "0.10.0" |
@@ -39,4 +39,3 @@ hir = { path = "../hir", version = "0.0.0" } | |||
39 | [dev-dependencies] | 39 | [dev-dependencies] |
40 | test_utils = { path = "../test_utils" } | 40 | test_utils = { path = "../test_utils" } |
41 | expect-test = "1.1" | 41 | expect-test = "1.1" |
42 | cov-mark = "1.1.0" | ||
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index d5c954b8b..4193aabf5 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -204,8 +204,9 @@ pub(crate) fn diagnostics( | |||
204 | ); | 204 | ); |
205 | }); | 205 | }); |
206 | 206 | ||
207 | let internal_diagnostics = cfg!(test); | ||
207 | match sema.to_module_def(file_id) { | 208 | match sema.to_module_def(file_id) { |
208 | Some(m) => m.diagnostics(db, &mut sink), | 209 | Some(m) => m.diagnostics(db, &mut sink, internal_diagnostics), |
209 | None => { | 210 | None => { |
210 | sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(&parse.tree().syntax()) }); | 211 | sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(&parse.tree().syntax()) }); |
211 | } | 212 | } |
@@ -305,6 +306,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | |||
305 | #[cfg(test)] | 306 | #[cfg(test)] |
306 | mod tests { | 307 | mod tests { |
307 | use expect_test::Expect; | 308 | use expect_test::Expect; |
309 | use hir::diagnostics::DiagnosticCode; | ||
308 | use ide_assists::AssistResolveStrategy; | 310 | use ide_assists::AssistResolveStrategy; |
309 | use stdx::trim_indent; | 311 | use stdx::trim_indent; |
310 | use test_utils::{assert_eq_text, extract_annotations}; | 312 | use test_utils::{assert_eq_text, extract_annotations}; |
@@ -410,7 +412,12 @@ mod tests { | |||
410 | .unwrap(); | 412 | .unwrap(); |
411 | 413 | ||
412 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | 414 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); |
413 | let actual = diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); | 415 | let mut actual = diagnostics |
416 | .into_iter() | ||
417 | .filter(|d| d.code != Some(DiagnosticCode("inactive-code"))) | ||
418 | .map(|d| (d.range, d.message)) | ||
419 | .collect::<Vec<_>>(); | ||
420 | actual.sort_by_key(|(range, _)| range.start()); | ||
414 | assert_eq!(expected, actual); | 421 | assert_eq!(expected, actual); |
415 | } | 422 | } |
416 | 423 | ||
@@ -719,4 +726,1878 @@ mod foo; | |||
719 | "#, | 726 | "#, |
720 | ); | 727 | ); |
721 | } | 728 | } |
729 | |||
730 | #[test] | ||
731 | fn break_outside_of_loop() { | ||
732 | check_diagnostics( | ||
733 | r#" | ||
734 | fn foo() { break; } | ||
735 | //^^^^^ break outside of loop | ||
736 | "#, | ||
737 | ); | ||
738 | } | ||
739 | |||
740 | #[test] | ||
741 | fn no_such_field_diagnostics() { | ||
742 | check_diagnostics( | ||
743 | r#" | ||
744 | struct S { foo: i32, bar: () } | ||
745 | impl S { | ||
746 | fn new() -> S { | ||
747 | S { | ||
748 | //^ Missing structure fields: | ||
749 | //| - bar | ||
750 | foo: 92, | ||
751 | baz: 62, | ||
752 | //^^^^^^^ no such field | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | "#, | ||
757 | ); | ||
758 | } | ||
759 | #[test] | ||
760 | fn no_such_field_with_feature_flag_diagnostics() { | ||
761 | check_diagnostics( | ||
762 | r#" | ||
763 | //- /lib.rs crate:foo cfg:feature=foo | ||
764 | struct MyStruct { | ||
765 | my_val: usize, | ||
766 | #[cfg(feature = "foo")] | ||
767 | bar: bool, | ||
768 | } | ||
769 | |||
770 | impl MyStruct { | ||
771 | #[cfg(feature = "foo")] | ||
772 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
773 | Self { my_val, bar } | ||
774 | } | ||
775 | #[cfg(not(feature = "foo"))] | ||
776 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
777 | Self { my_val } | ||
778 | } | ||
779 | } | ||
780 | "#, | ||
781 | ); | ||
782 | } | ||
783 | |||
784 | #[test] | ||
785 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
786 | check_diagnostics( | ||
787 | r#" | ||
788 | //- /lib.rs crate:foo cfg:feature=foo | ||
789 | enum Foo { | ||
790 | #[cfg(not(feature = "foo"))] | ||
791 | Buz, | ||
792 | #[cfg(feature = "foo")] | ||
793 | Bar, | ||
794 | Baz | ||
795 | } | ||
796 | |||
797 | fn test_fn(f: Foo) { | ||
798 | match f { | ||
799 | Foo::Bar => {}, | ||
800 | Foo::Baz => {}, | ||
801 | } | ||
802 | } | ||
803 | "#, | ||
804 | ); | ||
805 | } | ||
806 | |||
807 | #[test] | ||
808 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
809 | check_diagnostics( | ||
810 | r#" | ||
811 | //- /lib.rs crate:foo cfg:feature=foo | ||
812 | struct S { | ||
813 | #[cfg(feature = "foo")] | ||
814 | foo: u32, | ||
815 | #[cfg(not(feature = "foo"))] | ||
816 | bar: u32, | ||
817 | } | ||
818 | |||
819 | impl S { | ||
820 | #[cfg(feature = "foo")] | ||
821 | fn new(foo: u32) -> Self { | ||
822 | Self { foo } | ||
823 | } | ||
824 | #[cfg(not(feature = "foo"))] | ||
825 | fn new(bar: u32) -> Self { | ||
826 | Self { bar } | ||
827 | } | ||
828 | fn new2(bar: u32) -> Self { | ||
829 | #[cfg(feature = "foo")] | ||
830 | { Self { foo: bar } } | ||
831 | #[cfg(not(feature = "foo"))] | ||
832 | { Self { bar } } | ||
833 | } | ||
834 | fn new2(val: u32) -> Self { | ||
835 | Self { | ||
836 | #[cfg(feature = "foo")] | ||
837 | foo: val, | ||
838 | #[cfg(not(feature = "foo"))] | ||
839 | bar: val, | ||
840 | } | ||
841 | } | ||
842 | } | ||
843 | "#, | ||
844 | ); | ||
845 | } | ||
846 | |||
847 | #[test] | ||
848 | fn no_such_field_with_type_macro() { | ||
849 | check_diagnostics( | ||
850 | r#" | ||
851 | macro_rules! Type { () => { u32 }; } | ||
852 | struct Foo { bar: Type![] } | ||
853 | |||
854 | impl Foo { | ||
855 | fn new() -> Self { | ||
856 | Foo { bar: 0 } | ||
857 | } | ||
858 | } | ||
859 | "#, | ||
860 | ); | ||
861 | } | ||
862 | |||
863 | #[test] | ||
864 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
865 | check_diagnostics( | ||
866 | r#" | ||
867 | fn main() { | ||
868 | let x = &5 as *const usize; | ||
869 | unsafe { let y = *x; } | ||
870 | let z = *x; | ||
871 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
872 | "#, | ||
873 | ) | ||
874 | } | ||
875 | |||
876 | #[test] | ||
877 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
878 | check_diagnostics( | ||
879 | r#" | ||
880 | struct HasUnsafe; | ||
881 | |||
882 | impl HasUnsafe { | ||
883 | unsafe fn unsafe_fn(&self) { | ||
884 | let x = &5 as *const usize; | ||
885 | let y = *x; | ||
886 | } | ||
887 | } | ||
888 | |||
889 | unsafe fn unsafe_fn() { | ||
890 | let x = &5 as *const usize; | ||
891 | let y = *x; | ||
892 | } | ||
893 | |||
894 | fn main() { | ||
895 | unsafe_fn(); | ||
896 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
897 | HasUnsafe.unsafe_fn(); | ||
898 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
899 | unsafe { | ||
900 | unsafe_fn(); | ||
901 | HasUnsafe.unsafe_fn(); | ||
902 | } | ||
903 | } | ||
904 | "#, | ||
905 | ); | ||
906 | } | ||
907 | |||
908 | #[test] | ||
909 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
910 | check_diagnostics( | ||
911 | r#" | ||
912 | struct Ty { | ||
913 | a: u8, | ||
914 | } | ||
915 | |||
916 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
917 | |||
918 | fn main() { | ||
919 | let x = STATIC_MUT.a; | ||
920 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
921 | unsafe { | ||
922 | let x = STATIC_MUT.a; | ||
923 | } | ||
924 | } | ||
925 | "#, | ||
926 | ); | ||
927 | } | ||
928 | |||
929 | #[test] | ||
930 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
931 | check_diagnostics( | ||
932 | r#" | ||
933 | extern "rust-intrinsic" { | ||
934 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
935 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
936 | } | ||
937 | |||
938 | fn main() { | ||
939 | let _ = bitreverse(12); | ||
940 | let _ = floorf32(12.0); | ||
941 | //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
942 | } | ||
943 | "#, | ||
944 | ); | ||
945 | } | ||
946 | |||
947 | // Register the required standard library types to make the tests work | ||
948 | fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { | ||
949 | let prefix = r#" | ||
950 | //- /main.rs crate:main deps:core | ||
951 | use core::iter::Iterator; | ||
952 | use core::option::Option::{self, Some, None}; | ||
953 | "#; | ||
954 | let suffix = r#" | ||
955 | //- /core/lib.rs crate:core | ||
956 | pub mod option { | ||
957 | pub enum Option<T> { Some(T), None } | ||
958 | } | ||
959 | pub mod iter { | ||
960 | pub trait Iterator { | ||
961 | type Item; | ||
962 | fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap } | ||
963 | fn next(&mut self) -> Option<Self::Item>; | ||
964 | } | ||
965 | pub struct FilterMap {} | ||
966 | impl Iterator for FilterMap { | ||
967 | type Item = i32; | ||
968 | fn next(&mut self) -> i32 { 7 } | ||
969 | } | ||
970 | } | ||
971 | "#; | ||
972 | format!("{}{}{}", prefix, body, suffix) | ||
973 | } | ||
974 | |||
975 | #[test] | ||
976 | fn replace_filter_map_next_with_find_map2() { | ||
977 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
978 | r#" | ||
979 | fn foo() { | ||
980 | let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); | ||
981 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) | ||
982 | } | ||
983 | "#, | ||
984 | )); | ||
985 | } | ||
986 | |||
987 | #[test] | ||
988 | fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() { | ||
989 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
990 | r#" | ||
991 | fn foo() { | ||
992 | let m = [1, 2, 3] | ||
993 | .iter() | ||
994 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | ||
995 | .len(); | ||
996 | } | ||
997 | "#, | ||
998 | )); | ||
999 | } | ||
1000 | |||
1001 | #[test] | ||
1002 | fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() { | ||
1003 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
1004 | r#" | ||
1005 | fn foo() { | ||
1006 | let m = [1, 2, 3] | ||
1007 | .iter() | ||
1008 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | ||
1009 | .map(|x| x + 2) | ||
1010 | .len(); | ||
1011 | } | ||
1012 | "#, | ||
1013 | )); | ||
1014 | } | ||
1015 | |||
1016 | #[test] | ||
1017 | fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() { | ||
1018 | check_diagnostics(&add_filter_map_with_find_next_boilerplate( | ||
1019 | r#" | ||
1020 | fn foo() { | ||
1021 | let m = [1, 2, 3] | ||
1022 | .iter() | ||
1023 | .filter_map(|x| if *x == 2 { Some (4) } else { None }); | ||
1024 | let n = m.next(); | ||
1025 | } | ||
1026 | "#, | ||
1027 | )); | ||
1028 | } | ||
1029 | |||
1030 | #[test] | ||
1031 | fn missing_record_pat_field_diagnostic() { | ||
1032 | check_diagnostics( | ||
1033 | r#" | ||
1034 | struct S { foo: i32, bar: () } | ||
1035 | fn baz(s: S) { | ||
1036 | let S { foo: _ } = s; | ||
1037 | //^ Missing structure fields: | ||
1038 | //| - bar | ||
1039 | } | ||
1040 | "#, | ||
1041 | ); | ||
1042 | } | ||
1043 | |||
1044 | #[test] | ||
1045 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
1046 | check_diagnostics( | ||
1047 | r" | ||
1048 | struct S { foo: i32, bar: () } | ||
1049 | fn baz(s: S) -> i32 { | ||
1050 | match s { | ||
1051 | S { foo, .. } => foo, | ||
1052 | } | ||
1053 | } | ||
1054 | ", | ||
1055 | ) | ||
1056 | } | ||
1057 | |||
1058 | #[test] | ||
1059 | fn missing_record_pat_field_box() { | ||
1060 | check_diagnostics( | ||
1061 | r" | ||
1062 | struct S { s: Box<u32> } | ||
1063 | fn x(a: S) { | ||
1064 | let S { box s } = a; | ||
1065 | } | ||
1066 | ", | ||
1067 | ) | ||
1068 | } | ||
1069 | |||
1070 | #[test] | ||
1071 | fn missing_record_pat_field_ref() { | ||
1072 | check_diagnostics( | ||
1073 | r" | ||
1074 | struct S { s: u32 } | ||
1075 | fn x(a: S) { | ||
1076 | let S { ref s } = a; | ||
1077 | } | ||
1078 | ", | ||
1079 | ) | ||
1080 | } | ||
1081 | |||
1082 | #[test] | ||
1083 | fn simple_free_fn_zero() { | ||
1084 | check_diagnostics( | ||
1085 | r#" | ||
1086 | fn zero() {} | ||
1087 | fn f() { zero(1); } | ||
1088 | //^^^^^^^ Expected 0 arguments, found 1 | ||
1089 | "#, | ||
1090 | ); | ||
1091 | |||
1092 | check_diagnostics( | ||
1093 | r#" | ||
1094 | fn zero() {} | ||
1095 | fn f() { zero(); } | ||
1096 | "#, | ||
1097 | ); | ||
1098 | } | ||
1099 | |||
1100 | #[test] | ||
1101 | fn simple_free_fn_one() { | ||
1102 | check_diagnostics( | ||
1103 | r#" | ||
1104 | fn one(arg: u8) {} | ||
1105 | fn f() { one(); } | ||
1106 | //^^^^^ Expected 1 argument, found 0 | ||
1107 | "#, | ||
1108 | ); | ||
1109 | |||
1110 | check_diagnostics( | ||
1111 | r#" | ||
1112 | fn one(arg: u8) {} | ||
1113 | fn f() { one(1); } | ||
1114 | "#, | ||
1115 | ); | ||
1116 | } | ||
1117 | |||
1118 | #[test] | ||
1119 | fn method_as_fn() { | ||
1120 | check_diagnostics( | ||
1121 | r#" | ||
1122 | struct S; | ||
1123 | impl S { fn method(&self) {} } | ||
1124 | |||
1125 | fn f() { | ||
1126 | S::method(); | ||
1127 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
1128 | "#, | ||
1129 | ); | ||
1130 | |||
1131 | check_diagnostics( | ||
1132 | r#" | ||
1133 | struct S; | ||
1134 | impl S { fn method(&self) {} } | ||
1135 | |||
1136 | fn f() { | ||
1137 | S::method(&S); | ||
1138 | S.method(); | ||
1139 | } | ||
1140 | "#, | ||
1141 | ); | ||
1142 | } | ||
1143 | |||
1144 | #[test] | ||
1145 | fn method_with_arg() { | ||
1146 | check_diagnostics( | ||
1147 | r#" | ||
1148 | struct S; | ||
1149 | impl S { fn method(&self, arg: u8) {} } | ||
1150 | |||
1151 | fn f() { | ||
1152 | S.method(); | ||
1153 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
1154 | "#, | ||
1155 | ); | ||
1156 | |||
1157 | check_diagnostics( | ||
1158 | r#" | ||
1159 | struct S; | ||
1160 | impl S { fn method(&self, arg: u8) {} } | ||
1161 | |||
1162 | fn f() { | ||
1163 | S::method(&S, 0); | ||
1164 | S.method(1); | ||
1165 | } | ||
1166 | "#, | ||
1167 | ); | ||
1168 | } | ||
1169 | |||
1170 | #[test] | ||
1171 | fn method_unknown_receiver() { | ||
1172 | // note: this is incorrect code, so there might be errors on this in the | ||
1173 | // future, but we shouldn't emit an argument count diagnostic here | ||
1174 | check_diagnostics( | ||
1175 | r#" | ||
1176 | trait Foo { fn method(&self, arg: usize) {} } | ||
1177 | |||
1178 | fn f() { | ||
1179 | let x; | ||
1180 | x.method(); | ||
1181 | } | ||
1182 | "#, | ||
1183 | ); | ||
1184 | } | ||
1185 | |||
1186 | #[test] | ||
1187 | fn tuple_struct() { | ||
1188 | check_diagnostics( | ||
1189 | r#" | ||
1190 | struct Tup(u8, u16); | ||
1191 | fn f() { | ||
1192 | Tup(0); | ||
1193 | } //^^^^^^ Expected 2 arguments, found 1 | ||
1194 | "#, | ||
1195 | ) | ||
1196 | } | ||
1197 | |||
1198 | #[test] | ||
1199 | fn enum_variant() { | ||
1200 | check_diagnostics( | ||
1201 | r#" | ||
1202 | enum En { Variant(u8, u16), } | ||
1203 | fn f() { | ||
1204 | En::Variant(0); | ||
1205 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
1206 | "#, | ||
1207 | ) | ||
1208 | } | ||
1209 | |||
1210 | #[test] | ||
1211 | fn enum_variant_type_macro() { | ||
1212 | check_diagnostics( | ||
1213 | r#" | ||
1214 | macro_rules! Type { | ||
1215 | () => { u32 }; | ||
1216 | } | ||
1217 | enum Foo { | ||
1218 | Bar(Type![]) | ||
1219 | } | ||
1220 | impl Foo { | ||
1221 | fn new() { | ||
1222 | Foo::Bar(0); | ||
1223 | Foo::Bar(0, 1); | ||
1224 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
1225 | Foo::Bar(); | ||
1226 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
1227 | } | ||
1228 | } | ||
1229 | "#, | ||
1230 | ); | ||
1231 | } | ||
1232 | |||
1233 | #[test] | ||
1234 | fn varargs() { | ||
1235 | check_diagnostics( | ||
1236 | r#" | ||
1237 | extern "C" { | ||
1238 | fn fixed(fixed: u8); | ||
1239 | fn varargs(fixed: u8, ...); | ||
1240 | fn varargs2(...); | ||
1241 | } | ||
1242 | |||
1243 | fn f() { | ||
1244 | unsafe { | ||
1245 | fixed(0); | ||
1246 | fixed(0, 1); | ||
1247 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
1248 | varargs(0); | ||
1249 | varargs(0, 1); | ||
1250 | varargs2(); | ||
1251 | varargs2(0); | ||
1252 | varargs2(0, 1); | ||
1253 | } | ||
1254 | } | ||
1255 | "#, | ||
1256 | ) | ||
1257 | } | ||
1258 | |||
1259 | #[test] | ||
1260 | fn arg_count_lambda() { | ||
1261 | check_diagnostics( | ||
1262 | r#" | ||
1263 | fn main() { | ||
1264 | let f = |()| (); | ||
1265 | f(); | ||
1266 | //^^^ Expected 1 argument, found 0 | ||
1267 | f(()); | ||
1268 | f((), ()); | ||
1269 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
1270 | } | ||
1271 | "#, | ||
1272 | ) | ||
1273 | } | ||
1274 | |||
1275 | #[test] | ||
1276 | fn cfgd_out_call_arguments() { | ||
1277 | check_diagnostics( | ||
1278 | r#" | ||
1279 | struct C(#[cfg(FALSE)] ()); | ||
1280 | impl C { | ||
1281 | fn new() -> Self { | ||
1282 | Self( | ||
1283 | #[cfg(FALSE)] | ||
1284 | (), | ||
1285 | ) | ||
1286 | } | ||
1287 | |||
1288 | fn method(&self) {} | ||
1289 | } | ||
1290 | |||
1291 | fn main() { | ||
1292 | C::new().method(#[cfg(FALSE)] 0); | ||
1293 | } | ||
1294 | "#, | ||
1295 | ); | ||
1296 | } | ||
1297 | |||
1298 | #[test] | ||
1299 | fn cfgd_out_fn_params() { | ||
1300 | check_diagnostics( | ||
1301 | r#" | ||
1302 | fn foo(#[cfg(NEVER)] x: ()) {} | ||
1303 | |||
1304 | struct S; | ||
1305 | |||
1306 | impl S { | ||
1307 | fn method(#[cfg(NEVER)] self) {} | ||
1308 | fn method2(#[cfg(NEVER)] self, arg: u8) {} | ||
1309 | fn method3(self, #[cfg(NEVER)] arg: u8) {} | ||
1310 | } | ||
1311 | |||
1312 | extern "C" { | ||
1313 | fn fixed(fixed: u8, #[cfg(NEVER)] ...); | ||
1314 | fn varargs(#[cfg(not(NEVER))] ...); | ||
1315 | } | ||
1316 | |||
1317 | fn main() { | ||
1318 | foo(); | ||
1319 | S::method(); | ||
1320 | S::method2(0); | ||
1321 | S::method3(S); | ||
1322 | S.method3(); | ||
1323 | unsafe { | ||
1324 | fixed(0); | ||
1325 | varargs(1, 2, 3); | ||
1326 | } | ||
1327 | } | ||
1328 | "#, | ||
1329 | ) | ||
1330 | } | ||
1331 | |||
1332 | #[test] | ||
1333 | fn missing_semicolon() { | ||
1334 | check_diagnostics( | ||
1335 | r#" | ||
1336 | fn test() -> i32 { 123; } | ||
1337 | //^^^ Remove this semicolon | ||
1338 | "#, | ||
1339 | ); | ||
1340 | } | ||
1341 | |||
1342 | #[test] | ||
1343 | fn import_extern_crate_clash_with_inner_item() { | ||
1344 | // This is more of a resolver test, but doesn't really work with the hir_def testsuite. | ||
1345 | |||
1346 | check_diagnostics( | ||
1347 | r#" | ||
1348 | //- /lib.rs crate:lib deps:jwt | ||
1349 | mod permissions; | ||
1350 | |||
1351 | use permissions::jwt; | ||
1352 | |||
1353 | fn f() { | ||
1354 | fn inner() {} | ||
1355 | jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic | ||
1356 | } | ||
1357 | |||
1358 | //- /permissions.rs | ||
1359 | pub mod jwt { | ||
1360 | pub struct Claims {} | ||
1361 | } | ||
1362 | |||
1363 | //- /jwt/lib.rs crate:jwt | ||
1364 | pub struct Claims { | ||
1365 | field: u8, | ||
1366 | } | ||
1367 | "#, | ||
1368 | ); | ||
1369 | } | ||
1370 | } | ||
1371 | |||
1372 | #[cfg(test)] | ||
1373 | pub(super) mod match_check_tests { | ||
1374 | use crate::diagnostics::tests::check_diagnostics; | ||
1375 | |||
1376 | #[test] | ||
1377 | fn empty_tuple() { | ||
1378 | check_diagnostics( | ||
1379 | r#" | ||
1380 | fn main() { | ||
1381 | match () { } | ||
1382 | //^^ Missing match arm | ||
1383 | match (()) { } | ||
1384 | //^^^^ Missing match arm | ||
1385 | |||
1386 | match () { _ => (), } | ||
1387 | match () { () => (), } | ||
1388 | match (()) { (()) => (), } | ||
1389 | } | ||
1390 | "#, | ||
1391 | ); | ||
1392 | } | ||
1393 | |||
1394 | #[test] | ||
1395 | fn tuple_of_two_empty_tuple() { | ||
1396 | check_diagnostics( | ||
1397 | r#" | ||
1398 | fn main() { | ||
1399 | match ((), ()) { } | ||
1400 | //^^^^^^^^ Missing match arm | ||
1401 | |||
1402 | match ((), ()) { ((), ()) => (), } | ||
1403 | } | ||
1404 | "#, | ||
1405 | ); | ||
1406 | } | ||
1407 | |||
1408 | #[test] | ||
1409 | fn boolean() { | ||
1410 | check_diagnostics( | ||
1411 | r#" | ||
1412 | fn test_main() { | ||
1413 | match false { } | ||
1414 | //^^^^^ Missing match arm | ||
1415 | match false { true => (), } | ||
1416 | //^^^^^ Missing match arm | ||
1417 | match (false, true) {} | ||
1418 | //^^^^^^^^^^^^^ Missing match arm | ||
1419 | match (false, true) { (true, true) => (), } | ||
1420 | //^^^^^^^^^^^^^ Missing match arm | ||
1421 | match (false, true) { | ||
1422 | //^^^^^^^^^^^^^ Missing match arm | ||
1423 | (false, true) => (), | ||
1424 | (false, false) => (), | ||
1425 | (true, false) => (), | ||
1426 | } | ||
1427 | match (false, true) { (true, _x) => (), } | ||
1428 | //^^^^^^^^^^^^^ Missing match arm | ||
1429 | |||
1430 | match false { true => (), false => (), } | ||
1431 | match (false, true) { | ||
1432 | (false, _) => (), | ||
1433 | (true, false) => (), | ||
1434 | (_, true) => (), | ||
1435 | } | ||
1436 | match (false, true) { | ||
1437 | (true, true) => (), | ||
1438 | (true, false) => (), | ||
1439 | (false, true) => (), | ||
1440 | (false, false) => (), | ||
1441 | } | ||
1442 | match (false, true) { | ||
1443 | (true, _x) => (), | ||
1444 | (false, true) => (), | ||
1445 | (false, false) => (), | ||
1446 | } | ||
1447 | match (false, true, false) { | ||
1448 | (false, ..) => (), | ||
1449 | (true, ..) => (), | ||
1450 | } | ||
1451 | match (false, true, false) { | ||
1452 | (.., false) => (), | ||
1453 | (.., true) => (), | ||
1454 | } | ||
1455 | match (false, true, false) { (..) => (), } | ||
1456 | } | ||
1457 | "#, | ||
1458 | ); | ||
1459 | } | ||
1460 | |||
1461 | #[test] | ||
1462 | fn tuple_of_tuple_and_bools() { | ||
1463 | check_diagnostics( | ||
1464 | r#" | ||
1465 | fn main() { | ||
1466 | match (false, ((), false)) {} | ||
1467 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1468 | match (false, ((), false)) { (true, ((), true)) => (), } | ||
1469 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1470 | match (false, ((), false)) { (true, _) => (), } | ||
1471 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1472 | |||
1473 | match (false, ((), false)) { | ||
1474 | (true, ((), true)) => (), | ||
1475 | (true, ((), false)) => (), | ||
1476 | (false, ((), true)) => (), | ||
1477 | (false, ((), false)) => (), | ||
1478 | } | ||
1479 | match (false, ((), false)) { | ||
1480 | (true, ((), true)) => (), | ||
1481 | (true, ((), false)) => (), | ||
1482 | (false, _) => (), | ||
1483 | } | ||
1484 | } | ||
1485 | "#, | ||
1486 | ); | ||
1487 | } | ||
1488 | |||
1489 | #[test] | ||
1490 | fn enums() { | ||
1491 | check_diagnostics( | ||
1492 | r#" | ||
1493 | enum Either { A, B, } | ||
1494 | |||
1495 | fn main() { | ||
1496 | match Either::A { } | ||
1497 | //^^^^^^^^^ Missing match arm | ||
1498 | match Either::B { Either::A => (), } | ||
1499 | //^^^^^^^^^ Missing match arm | ||
1500 | |||
1501 | match &Either::B { | ||
1502 | //^^^^^^^^^^ Missing match arm | ||
1503 | Either::A => (), | ||
1504 | } | ||
1505 | |||
1506 | match Either::B { | ||
1507 | Either::A => (), Either::B => (), | ||
1508 | } | ||
1509 | match &Either::B { | ||
1510 | Either::A => (), Either::B => (), | ||
1511 | } | ||
1512 | } | ||
1513 | "#, | ||
1514 | ); | ||
1515 | } | ||
1516 | |||
1517 | #[test] | ||
1518 | fn enum_containing_bool() { | ||
1519 | check_diagnostics( | ||
1520 | r#" | ||
1521 | enum Either { A(bool), B } | ||
1522 | |||
1523 | fn main() { | ||
1524 | match Either::B { } | ||
1525 | //^^^^^^^^^ Missing match arm | ||
1526 | match Either::B { | ||
1527 | //^^^^^^^^^ Missing match arm | ||
1528 | Either::A(true) => (), Either::B => () | ||
1529 | } | ||
1530 | |||
1531 | match Either::B { | ||
1532 | Either::A(true) => (), | ||
1533 | Either::A(false) => (), | ||
1534 | Either::B => (), | ||
1535 | } | ||
1536 | match Either::B { | ||
1537 | Either::B => (), | ||
1538 | _ => (), | ||
1539 | } | ||
1540 | match Either::B { | ||
1541 | Either::A(_) => (), | ||
1542 | Either::B => (), | ||
1543 | } | ||
1544 | |||
1545 | } | ||
1546 | "#, | ||
1547 | ); | ||
1548 | } | ||
1549 | |||
1550 | #[test] | ||
1551 | fn enum_different_sizes() { | ||
1552 | check_diagnostics( | ||
1553 | r#" | ||
1554 | enum Either { A(bool), B(bool, bool) } | ||
1555 | |||
1556 | fn main() { | ||
1557 | match Either::A(false) { | ||
1558 | //^^^^^^^^^^^^^^^^ Missing match arm | ||
1559 | Either::A(_) => (), | ||
1560 | Either::B(false, _) => (), | ||
1561 | } | ||
1562 | |||
1563 | match Either::A(false) { | ||
1564 | Either::A(_) => (), | ||
1565 | Either::B(true, _) => (), | ||
1566 | Either::B(false, _) => (), | ||
1567 | } | ||
1568 | match Either::A(false) { | ||
1569 | Either::A(true) | Either::A(false) => (), | ||
1570 | Either::B(true, _) => (), | ||
1571 | Either::B(false, _) => (), | ||
1572 | } | ||
1573 | } | ||
1574 | "#, | ||
1575 | ); | ||
1576 | } | ||
1577 | |||
1578 | #[test] | ||
1579 | fn tuple_of_enum_no_diagnostic() { | ||
1580 | check_diagnostics( | ||
1581 | r#" | ||
1582 | enum Either { A(bool), B(bool, bool) } | ||
1583 | enum Either2 { C, D } | ||
1584 | |||
1585 | fn main() { | ||
1586 | match (Either::A(false), Either2::C) { | ||
1587 | (Either::A(true), _) | (Either::A(false), _) => (), | ||
1588 | (Either::B(true, _), Either2::C) => (), | ||
1589 | (Either::B(false, _), Either2::C) => (), | ||
1590 | (Either::B(_, _), Either2::D) => (), | ||
1591 | } | ||
1592 | } | ||
1593 | "#, | ||
1594 | ); | ||
1595 | } | ||
1596 | |||
1597 | #[test] | ||
1598 | fn or_pattern_no_diagnostic() { | ||
1599 | check_diagnostics( | ||
1600 | r#" | ||
1601 | enum Either {A, B} | ||
1602 | |||
1603 | fn main() { | ||
1604 | match (Either::A, Either::B) { | ||
1605 | (Either::A | Either::B, _) => (), | ||
1606 | } | ||
1607 | }"#, | ||
1608 | ) | ||
1609 | } | ||
1610 | |||
1611 | #[test] | ||
1612 | fn mismatched_types() { | ||
1613 | // Match statements with arms that don't match the | ||
1614 | // expression pattern do not fire this diagnostic. | ||
1615 | check_diagnostics( | ||
1616 | r#" | ||
1617 | enum Either { A, B } | ||
1618 | enum Either2 { C, D } | ||
1619 | |||
1620 | fn main() { | ||
1621 | match Either::A { | ||
1622 | Either2::C => (), | ||
1623 | // ^^^^^^^^^^ Internal: match check bailed out | ||
1624 | Either2::D => (), | ||
1625 | } | ||
1626 | match (true, false) { | ||
1627 | (true, false, true) => (), | ||
1628 | // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out | ||
1629 | (true) => (), | ||
1630 | } | ||
1631 | match (true, false) { (true,) => {} } | ||
1632 | // ^^^^^^^ Internal: match check bailed out | ||
1633 | match (0) { () => () } | ||
1634 | // ^^ Internal: match check bailed out | ||
1635 | match Unresolved::Bar { Unresolved::Baz => () } | ||
1636 | } | ||
1637 | "#, | ||
1638 | ); | ||
1639 | } | ||
1640 | |||
1641 | #[test] | ||
1642 | fn mismatched_types_in_or_patterns() { | ||
1643 | check_diagnostics( | ||
1644 | r#" | ||
1645 | fn main() { | ||
1646 | match false { true | () => {} } | ||
1647 | // ^^^^^^^^^ Internal: match check bailed out | ||
1648 | match (false,) { (true | (),) => {} } | ||
1649 | // ^^^^^^^^^^^^ Internal: match check bailed out | ||
1650 | } | ||
1651 | "#, | ||
1652 | ); | ||
1653 | } | ||
1654 | |||
1655 | #[test] | ||
1656 | fn malformed_match_arm_tuple_enum_missing_pattern() { | ||
1657 | // We are testing to be sure we don't panic here when the match | ||
1658 | // arm `Either::B` is missing its pattern. | ||
1659 | check_diagnostics( | ||
1660 | r#" | ||
1661 | enum Either { A, B(u32) } | ||
1662 | |||
1663 | fn main() { | ||
1664 | match Either::A { | ||
1665 | Either::A => (), | ||
1666 | Either::B() => (), | ||
1667 | } | ||
1668 | } | ||
1669 | "#, | ||
1670 | ); | ||
1671 | } | ||
1672 | |||
1673 | #[test] | ||
1674 | fn malformed_match_arm_extra_fields() { | ||
1675 | check_diagnostics( | ||
1676 | r#" | ||
1677 | enum A { B(isize, isize), C } | ||
1678 | fn main() { | ||
1679 | match A::B(1, 2) { | ||
1680 | A::B(_, _, _) => (), | ||
1681 | // ^^^^^^^^^^^^^ Internal: match check bailed out | ||
1682 | } | ||
1683 | match A::B(1, 2) { | ||
1684 | A::C(_) => (), | ||
1685 | // ^^^^^^^ Internal: match check bailed out | ||
1686 | } | ||
1687 | } | ||
1688 | "#, | ||
1689 | ); | ||
1690 | } | ||
1691 | |||
1692 | #[test] | ||
1693 | fn expr_diverges() { | ||
1694 | check_diagnostics( | ||
1695 | r#" | ||
1696 | enum Either { A, B } | ||
1697 | |||
1698 | fn main() { | ||
1699 | match loop {} { | ||
1700 | Either::A => (), | ||
1701 | // ^^^^^^^^^ Internal: match check bailed out | ||
1702 | Either::B => (), | ||
1703 | } | ||
1704 | match loop {} { | ||
1705 | Either::A => (), | ||
1706 | // ^^^^^^^^^ Internal: match check bailed out | ||
1707 | } | ||
1708 | match loop { break Foo::A } { | ||
1709 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1710 | Either::A => (), | ||
1711 | } | ||
1712 | match loop { break Foo::A } { | ||
1713 | Either::A => (), | ||
1714 | Either::B => (), | ||
1715 | } | ||
1716 | } | ||
1717 | "#, | ||
1718 | ); | ||
1719 | } | ||
1720 | |||
1721 | #[test] | ||
1722 | fn expr_partially_diverges() { | ||
1723 | check_diagnostics( | ||
1724 | r#" | ||
1725 | enum Either<T> { A(T), B } | ||
1726 | |||
1727 | fn foo() -> Either<!> { Either::B } | ||
1728 | fn main() -> u32 { | ||
1729 | match foo() { | ||
1730 | Either::A(val) => val, | ||
1731 | Either::B => 0, | ||
1732 | } | ||
1733 | } | ||
1734 | "#, | ||
1735 | ); | ||
1736 | } | ||
1737 | |||
1738 | #[test] | ||
1739 | fn enum_record() { | ||
1740 | check_diagnostics( | ||
1741 | r#" | ||
1742 | enum Either { A { foo: bool }, B } | ||
1743 | |||
1744 | fn main() { | ||
1745 | let a = Either::A { foo: true }; | ||
1746 | match a { } | ||
1747 | //^ Missing match arm | ||
1748 | match a { Either::A { foo: true } => () } | ||
1749 | //^ Missing match arm | ||
1750 | match a { | ||
1751 | Either::A { } => (), | ||
1752 | //^^^^^^^^^ Missing structure fields: | ||
1753 | // | - foo | ||
1754 | Either::B => (), | ||
1755 | } | ||
1756 | match a { | ||
1757 | //^ Missing match arm | ||
1758 | Either::A { } => (), | ||
1759 | } //^^^^^^^^^ Missing structure fields: | ||
1760 | // | - foo | ||
1761 | |||
1762 | match a { | ||
1763 | Either::A { foo: true } => (), | ||
1764 | Either::A { foo: false } => (), | ||
1765 | Either::B => (), | ||
1766 | } | ||
1767 | match a { | ||
1768 | Either::A { foo: _ } => (), | ||
1769 | Either::B => (), | ||
1770 | } | ||
1771 | } | ||
1772 | "#, | ||
1773 | ); | ||
1774 | } | ||
1775 | |||
1776 | #[test] | ||
1777 | fn enum_record_fields_out_of_order() { | ||
1778 | check_diagnostics( | ||
1779 | r#" | ||
1780 | enum Either { | ||
1781 | A { foo: bool, bar: () }, | ||
1782 | B, | ||
1783 | } | ||
1784 | |||
1785 | fn main() { | ||
1786 | let a = Either::A { foo: true, bar: () }; | ||
1787 | match a { | ||
1788 | //^ Missing match arm | ||
1789 | Either::A { bar: (), foo: false } => (), | ||
1790 | Either::A { foo: true, bar: () } => (), | ||
1791 | } | ||
1792 | |||
1793 | match a { | ||
1794 | Either::A { bar: (), foo: false } => (), | ||
1795 | Either::A { foo: true, bar: () } => (), | ||
1796 | Either::B => (), | ||
1797 | } | ||
1798 | } | ||
1799 | "#, | ||
1800 | ); | ||
1801 | } | ||
1802 | |||
1803 | #[test] | ||
1804 | fn enum_record_ellipsis() { | ||
1805 | check_diagnostics( | ||
1806 | r#" | ||
1807 | enum Either { | ||
1808 | A { foo: bool, bar: bool }, | ||
1809 | B, | ||
1810 | } | ||
1811 | |||
1812 | fn main() { | ||
1813 | let a = Either::B; | ||
1814 | match a { | ||
1815 | //^ Missing match arm | ||
1816 | Either::A { foo: true, .. } => (), | ||
1817 | Either::B => (), | ||
1818 | } | ||
1819 | match a { | ||
1820 | //^ Missing match arm | ||
1821 | Either::A { .. } => (), | ||
1822 | } | ||
1823 | |||
1824 | match a { | ||
1825 | Either::A { foo: true, .. } => (), | ||
1826 | Either::A { foo: false, .. } => (), | ||
1827 | Either::B => (), | ||
1828 | } | ||
1829 | |||
1830 | match a { | ||
1831 | Either::A { .. } => (), | ||
1832 | Either::B => (), | ||
1833 | } | ||
1834 | } | ||
1835 | "#, | ||
1836 | ); | ||
1837 | } | ||
1838 | |||
1839 | #[test] | ||
1840 | fn enum_tuple_partial_ellipsis() { | ||
1841 | check_diagnostics( | ||
1842 | r#" | ||
1843 | enum Either { | ||
1844 | A(bool, bool, bool, bool), | ||
1845 | B, | ||
1846 | } | ||
1847 | |||
1848 | fn main() { | ||
1849 | match Either::B { | ||
1850 | //^^^^^^^^^ Missing match arm | ||
1851 | Either::A(true, .., true) => (), | ||
1852 | Either::A(true, .., false) => (), | ||
1853 | Either::A(false, .., false) => (), | ||
1854 | Either::B => (), | ||
1855 | } | ||
1856 | match Either::B { | ||
1857 | //^^^^^^^^^ Missing match arm | ||
1858 | Either::A(true, .., true) => (), | ||
1859 | Either::A(true, .., false) => (), | ||
1860 | Either::A(.., true) => (), | ||
1861 | Either::B => (), | ||
1862 | } | ||
1863 | |||
1864 | match Either::B { | ||
1865 | Either::A(true, .., true) => (), | ||
1866 | Either::A(true, .., false) => (), | ||
1867 | Either::A(false, .., true) => (), | ||
1868 | Either::A(false, .., false) => (), | ||
1869 | Either::B => (), | ||
1870 | } | ||
1871 | match Either::B { | ||
1872 | Either::A(true, .., true) => (), | ||
1873 | Either::A(true, .., false) => (), | ||
1874 | Either::A(.., true) => (), | ||
1875 | Either::A(.., false) => (), | ||
1876 | Either::B => (), | ||
1877 | } | ||
1878 | } | ||
1879 | "#, | ||
1880 | ); | ||
1881 | } | ||
1882 | |||
1883 | #[test] | ||
1884 | fn never() { | ||
1885 | check_diagnostics( | ||
1886 | r#" | ||
1887 | enum Never {} | ||
1888 | |||
1889 | fn enum_(never: Never) { | ||
1890 | match never {} | ||
1891 | } | ||
1892 | fn enum_ref(never: &Never) { | ||
1893 | match never {} | ||
1894 | //^^^^^ Missing match arm | ||
1895 | } | ||
1896 | fn bang(never: !) { | ||
1897 | match never {} | ||
1898 | } | ||
1899 | "#, | ||
1900 | ); | ||
1901 | } | ||
1902 | |||
1903 | #[test] | ||
1904 | fn unknown_type() { | ||
1905 | check_diagnostics( | ||
1906 | r#" | ||
1907 | enum Option<T> { Some(T), None } | ||
1908 | |||
1909 | fn main() { | ||
1910 | // `Never` is deliberately not defined so that it's an uninferred type. | ||
1911 | match Option::<Never>::None { | ||
1912 | None => (), | ||
1913 | Some(never) => match never {}, | ||
1914 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
1915 | } | ||
1916 | match Option::<Never>::None { | ||
1917 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1918 | Option::Some(_never) => {}, | ||
1919 | } | ||
1920 | } | ||
1921 | "#, | ||
1922 | ); | ||
1923 | } | ||
1924 | |||
1925 | #[test] | ||
1926 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1927 | check_diagnostics( | ||
1928 | r#" | ||
1929 | fn main() { | ||
1930 | match (false, true, false) { | ||
1931 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1932 | (false, ..) => (), | ||
1933 | } | ||
1934 | }"#, | ||
1935 | ); | ||
1936 | } | ||
1937 | |||
1938 | #[test] | ||
1939 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1940 | check_diagnostics( | ||
1941 | r#" | ||
1942 | fn main() { | ||
1943 | match (false, true, false) { | ||
1944 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1945 | (.., false) => (), | ||
1946 | } | ||
1947 | }"#, | ||
1948 | ); | ||
1949 | } | ||
1950 | |||
1951 | #[test] | ||
1952 | fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() { | ||
1953 | check_diagnostics( | ||
1954 | r#" | ||
1955 | fn main() { | ||
1956 | match (false, true, false) { | ||
1957 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1958 | (true, .., false) => (), | ||
1959 | } | ||
1960 | }"#, | ||
1961 | ); | ||
1962 | } | ||
1963 | |||
1964 | #[test] | ||
1965 | fn record_struct() { | ||
1966 | check_diagnostics( | ||
1967 | r#"struct Foo { a: bool } | ||
1968 | fn main(f: Foo) { | ||
1969 | match f {} | ||
1970 | //^ Missing match arm | ||
1971 | match f { Foo { a: true } => () } | ||
1972 | //^ Missing match arm | ||
1973 | match &f { Foo { a: true } => () } | ||
1974 | //^^ Missing match arm | ||
1975 | match f { Foo { a: _ } => () } | ||
1976 | match f { | ||
1977 | Foo { a: true } => (), | ||
1978 | Foo { a: false } => (), | ||
1979 | } | ||
1980 | match &f { | ||
1981 | Foo { a: true } => (), | ||
1982 | Foo { a: false } => (), | ||
1983 | } | ||
1984 | } | ||
1985 | "#, | ||
1986 | ); | ||
1987 | } | ||
1988 | |||
1989 | #[test] | ||
1990 | fn tuple_struct() { | ||
1991 | check_diagnostics( | ||
1992 | r#"struct Foo(bool); | ||
1993 | fn main(f: Foo) { | ||
1994 | match f {} | ||
1995 | //^ Missing match arm | ||
1996 | match f { Foo(true) => () } | ||
1997 | //^ Missing match arm | ||
1998 | match f { | ||
1999 | Foo(true) => (), | ||
2000 | Foo(false) => (), | ||
2001 | } | ||
2002 | } | ||
2003 | "#, | ||
2004 | ); | ||
2005 | } | ||
2006 | |||
2007 | #[test] | ||
2008 | fn unit_struct() { | ||
2009 | check_diagnostics( | ||
2010 | r#"struct Foo; | ||
2011 | fn main(f: Foo) { | ||
2012 | match f {} | ||
2013 | //^ Missing match arm | ||
2014 | match f { Foo => () } | ||
2015 | } | ||
2016 | "#, | ||
2017 | ); | ||
2018 | } | ||
2019 | |||
2020 | #[test] | ||
2021 | fn record_struct_ellipsis() { | ||
2022 | check_diagnostics( | ||
2023 | r#"struct Foo { foo: bool, bar: bool } | ||
2024 | fn main(f: Foo) { | ||
2025 | match f { Foo { foo: true, .. } => () } | ||
2026 | //^ Missing match arm | ||
2027 | match f { | ||
2028 | //^ Missing match arm | ||
2029 | Foo { foo: true, .. } => (), | ||
2030 | Foo { bar: false, .. } => () | ||
2031 | } | ||
2032 | match f { Foo { .. } => () } | ||
2033 | match f { | ||
2034 | Foo { foo: true, .. } => (), | ||
2035 | Foo { foo: false, .. } => () | ||
2036 | } | ||
2037 | } | ||
2038 | "#, | ||
2039 | ); | ||
2040 | } | ||
2041 | |||
2042 | #[test] | ||
2043 | fn internal_or() { | ||
2044 | check_diagnostics( | ||
2045 | r#" | ||
2046 | fn main() { | ||
2047 | enum Either { A(bool), B } | ||
2048 | match Either::B { | ||
2049 | //^^^^^^^^^ Missing match arm | ||
2050 | Either::A(true | false) => (), | ||
2051 | } | ||
2052 | } | ||
2053 | "#, | ||
2054 | ); | ||
2055 | } | ||
2056 | |||
2057 | #[test] | ||
2058 | fn no_panic_at_unimplemented_subpattern_type() { | ||
2059 | check_diagnostics( | ||
2060 | r#" | ||
2061 | struct S { a: char} | ||
2062 | fn main(v: S) { | ||
2063 | match v { S{ a } => {} } | ||
2064 | match v { S{ a: _x } => {} } | ||
2065 | match v { S{ a: 'a' } => {} } | ||
2066 | //^^^^^^^^^^^ Internal: match check bailed out | ||
2067 | match v { S{..} => {} } | ||
2068 | match v { _ => {} } | ||
2069 | match v { } | ||
2070 | //^ Missing match arm | ||
2071 | } | ||
2072 | "#, | ||
2073 | ); | ||
2074 | } | ||
2075 | |||
2076 | #[test] | ||
2077 | fn binding() { | ||
2078 | check_diagnostics( | ||
2079 | r#" | ||
2080 | fn main() { | ||
2081 | match true { | ||
2082 | _x @ true => {} | ||
2083 | false => {} | ||
2084 | } | ||
2085 | match true { _x @ true => {} } | ||
2086 | //^^^^ Missing match arm | ||
2087 | } | ||
2088 | "#, | ||
2089 | ); | ||
2090 | } | ||
2091 | |||
2092 | #[test] | ||
2093 | fn binding_ref_has_correct_type() { | ||
2094 | // Asserts `PatKind::Binding(ref _x): bool`, not &bool. | ||
2095 | // If that's not true match checking will panic with "incompatible constructors" | ||
2096 | // FIXME: make facilities to test this directly like `tests::check_infer(..)` | ||
2097 | check_diagnostics( | ||
2098 | r#" | ||
2099 | enum Foo { A } | ||
2100 | fn main() { | ||
2101 | // FIXME: this should not bail out but current behavior is such as the old algorithm. | ||
2102 | // ExprValidator::validate_match(..) checks types of top level patterns incorrecly. | ||
2103 | match Foo::A { | ||
2104 | ref _x => {} | ||
2105 | // ^^^^^^ Internal: match check bailed out | ||
2106 | Foo::A => {} | ||
2107 | } | ||
2108 | match (true,) { | ||
2109 | (ref _x,) => {} | ||
2110 | (true,) => {} | ||
2111 | } | ||
2112 | } | ||
2113 | "#, | ||
2114 | ); | ||
2115 | } | ||
2116 | |||
2117 | #[test] | ||
2118 | fn enum_non_exhaustive() { | ||
2119 | check_diagnostics( | ||
2120 | r#" | ||
2121 | //- /lib.rs crate:lib | ||
2122 | #[non_exhaustive] | ||
2123 | pub enum E { A, B } | ||
2124 | fn _local() { | ||
2125 | match E::A { _ => {} } | ||
2126 | match E::A { | ||
2127 | E::A => {} | ||
2128 | E::B => {} | ||
2129 | } | ||
2130 | match E::A { | ||
2131 | E::A | E::B => {} | ||
2132 | } | ||
2133 | } | ||
2134 | |||
2135 | //- /main.rs crate:main deps:lib | ||
2136 | use lib::E; | ||
2137 | fn main() { | ||
2138 | match E::A { _ => {} } | ||
2139 | match E::A { | ||
2140 | //^^^^ Missing match arm | ||
2141 | E::A => {} | ||
2142 | E::B => {} | ||
2143 | } | ||
2144 | match E::A { | ||
2145 | //^^^^ Missing match arm | ||
2146 | E::A | E::B => {} | ||
2147 | } | ||
2148 | } | ||
2149 | "#, | ||
2150 | ); | ||
2151 | } | ||
2152 | |||
2153 | #[test] | ||
2154 | fn match_guard() { | ||
2155 | check_diagnostics( | ||
2156 | r#" | ||
2157 | fn main() { | ||
2158 | match true { | ||
2159 | true if false => {} | ||
2160 | true => {} | ||
2161 | false => {} | ||
2162 | } | ||
2163 | match true { | ||
2164 | //^^^^ Missing match arm | ||
2165 | true if false => {} | ||
2166 | false => {} | ||
2167 | } | ||
2168 | } | ||
2169 | "#, | ||
2170 | ); | ||
2171 | } | ||
2172 | |||
2173 | #[test] | ||
2174 | fn pattern_type_is_of_substitution() { | ||
2175 | check_diagnostics( | ||
2176 | r#" | ||
2177 | struct Foo<T>(T); | ||
2178 | struct Bar; | ||
2179 | fn main() { | ||
2180 | match Foo(Bar) { | ||
2181 | _ | Foo(Bar) => {} | ||
2182 | } | ||
2183 | } | ||
2184 | "#, | ||
2185 | ); | ||
2186 | } | ||
2187 | |||
2188 | #[test] | ||
2189 | fn record_struct_no_such_field() { | ||
2190 | check_diagnostics( | ||
2191 | r#" | ||
2192 | struct Foo { } | ||
2193 | fn main(f: Foo) { | ||
2194 | match f { Foo { bar } => () } | ||
2195 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
2196 | } | ||
2197 | "#, | ||
2198 | ); | ||
2199 | } | ||
2200 | |||
2201 | #[test] | ||
2202 | fn match_ergonomics_issue_9095() { | ||
2203 | check_diagnostics( | ||
2204 | r#" | ||
2205 | enum Foo<T> { A(T) } | ||
2206 | fn main() { | ||
2207 | match &Foo::A(true) { | ||
2208 | _ => {} | ||
2209 | Foo::A(_) => {} | ||
2210 | } | ||
2211 | } | ||
2212 | "#, | ||
2213 | ); | ||
2214 | } | ||
2215 | |||
2216 | mod false_negatives { | ||
2217 | //! The implementation of match checking here is a work in progress. As we roll this out, we | ||
2218 | //! prefer false negatives to false positives (ideally there would be no false positives). This | ||
2219 | //! test module should document known false negatives. Eventually we will have a complete | ||
2220 | //! implementation of match checking and this module will be empty. | ||
2221 | //! | ||
2222 | //! The reasons for documenting known false negatives: | ||
2223 | //! | ||
2224 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | ||
2225 | //! 2. It ensures the code doesn't panic when handling these cases. | ||
2226 | use super::*; | ||
2227 | |||
2228 | #[test] | ||
2229 | fn integers() { | ||
2230 | // We don't currently check integer exhaustiveness. | ||
2231 | check_diagnostics( | ||
2232 | r#" | ||
2233 | fn main() { | ||
2234 | match 5 { | ||
2235 | 10 => (), | ||
2236 | // ^^ Internal: match check bailed out | ||
2237 | 11..20 => (), | ||
2238 | } | ||
2239 | } | ||
2240 | "#, | ||
2241 | ); | ||
2242 | } | ||
2243 | |||
2244 | #[test] | ||
2245 | fn reference_patterns_at_top_level() { | ||
2246 | check_diagnostics( | ||
2247 | r#" | ||
2248 | fn main() { | ||
2249 | match &false { | ||
2250 | &true => {} | ||
2251 | // ^^^^^ Internal: match check bailed out | ||
2252 | } | ||
2253 | } | ||
2254 | "#, | ||
2255 | ); | ||
2256 | } | ||
2257 | |||
2258 | #[test] | ||
2259 | fn reference_patterns_in_fields() { | ||
2260 | check_diagnostics( | ||
2261 | r#" | ||
2262 | fn main() { | ||
2263 | match (&false,) { | ||
2264 | (true,) => {} | ||
2265 | // ^^^^^^^ Internal: match check bailed out | ||
2266 | } | ||
2267 | match (&false,) { | ||
2268 | (&true,) => {} | ||
2269 | // ^^^^^^^^ Internal: match check bailed out | ||
2270 | } | ||
2271 | } | ||
2272 | "#, | ||
2273 | ); | ||
2274 | } | ||
2275 | } | ||
2276 | } | ||
2277 | |||
2278 | #[cfg(test)] | ||
2279 | mod decl_check_tests { | ||
2280 | use crate::diagnostics::tests::check_diagnostics; | ||
2281 | |||
2282 | #[test] | ||
2283 | fn incorrect_function_name() { | ||
2284 | check_diagnostics( | ||
2285 | r#" | ||
2286 | fn NonSnakeCaseName() {} | ||
2287 | // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` | ||
2288 | "#, | ||
2289 | ); | ||
2290 | } | ||
2291 | |||
2292 | #[test] | ||
2293 | fn incorrect_function_params() { | ||
2294 | check_diagnostics( | ||
2295 | r#" | ||
2296 | fn foo(SomeParam: u8) {} | ||
2297 | // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` | ||
2298 | |||
2299 | fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | ||
2300 | // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` | ||
2301 | "#, | ||
2302 | ); | ||
2303 | } | ||
2304 | |||
2305 | #[test] | ||
2306 | fn incorrect_variable_names() { | ||
2307 | check_diagnostics( | ||
2308 | r#" | ||
2309 | fn foo() { | ||
2310 | let SOME_VALUE = 10; | ||
2311 | // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` | ||
2312 | let AnotherValue = 20; | ||
2313 | // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` | ||
2314 | } | ||
2315 | "#, | ||
2316 | ); | ||
2317 | } | ||
2318 | |||
2319 | #[test] | ||
2320 | fn incorrect_struct_names() { | ||
2321 | check_diagnostics( | ||
2322 | r#" | ||
2323 | struct non_camel_case_name {} | ||
2324 | // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` | ||
2325 | |||
2326 | struct SCREAMING_CASE {} | ||
2327 | // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` | ||
2328 | "#, | ||
2329 | ); | ||
2330 | } | ||
2331 | |||
2332 | #[test] | ||
2333 | fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() { | ||
2334 | check_diagnostics( | ||
2335 | r#" | ||
2336 | struct AABB {} | ||
2337 | "#, | ||
2338 | ); | ||
2339 | } | ||
2340 | |||
2341 | #[test] | ||
2342 | fn incorrect_struct_field() { | ||
2343 | check_diagnostics( | ||
2344 | r#" | ||
2345 | struct SomeStruct { SomeField: u8 } | ||
2346 | // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` | ||
2347 | "#, | ||
2348 | ); | ||
2349 | } | ||
2350 | |||
2351 | #[test] | ||
2352 | fn incorrect_enum_names() { | ||
2353 | check_diagnostics( | ||
2354 | r#" | ||
2355 | enum some_enum { Val(u8) } | ||
2356 | // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` | ||
2357 | |||
2358 | enum SOME_ENUM {} | ||
2359 | // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` | ||
2360 | "#, | ||
2361 | ); | ||
2362 | } | ||
2363 | |||
2364 | #[test] | ||
2365 | fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() { | ||
2366 | check_diagnostics( | ||
2367 | r#" | ||
2368 | enum AABB {} | ||
2369 | "#, | ||
2370 | ); | ||
2371 | } | ||
2372 | |||
2373 | #[test] | ||
2374 | fn incorrect_enum_variant_name() { | ||
2375 | check_diagnostics( | ||
2376 | r#" | ||
2377 | enum SomeEnum { SOME_VARIANT(u8) } | ||
2378 | // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` | ||
2379 | "#, | ||
2380 | ); | ||
2381 | } | ||
2382 | |||
2383 | #[test] | ||
2384 | fn incorrect_const_name() { | ||
2385 | check_diagnostics( | ||
2386 | r#" | ||
2387 | const some_weird_const: u8 = 10; | ||
2388 | // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | ||
2389 | "#, | ||
2390 | ); | ||
2391 | } | ||
2392 | |||
2393 | #[test] | ||
2394 | fn incorrect_static_name() { | ||
2395 | check_diagnostics( | ||
2396 | r#" | ||
2397 | static some_weird_const: u8 = 10; | ||
2398 | // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | ||
2399 | "#, | ||
2400 | ); | ||
2401 | } | ||
2402 | |||
2403 | #[test] | ||
2404 | fn fn_inside_impl_struct() { | ||
2405 | check_diagnostics( | ||
2406 | r#" | ||
2407 | struct someStruct; | ||
2408 | // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` | ||
2409 | |||
2410 | impl someStruct { | ||
2411 | fn SomeFunc(&self) { | ||
2412 | // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` | ||
2413 | let WHY_VAR_IS_CAPS = 10; | ||
2414 | // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` | ||
2415 | } | ||
2416 | } | ||
2417 | "#, | ||
2418 | ); | ||
2419 | } | ||
2420 | |||
2421 | #[test] | ||
2422 | fn no_diagnostic_for_enum_varinats() { | ||
2423 | check_diagnostics( | ||
2424 | r#" | ||
2425 | enum Option { Some, None } | ||
2426 | |||
2427 | fn main() { | ||
2428 | match Option::None { | ||
2429 | None => (), | ||
2430 | Some => (), | ||
2431 | } | ||
2432 | } | ||
2433 | "#, | ||
2434 | ); | ||
2435 | } | ||
2436 | |||
2437 | #[test] | ||
2438 | fn non_let_bind() { | ||
2439 | check_diagnostics( | ||
2440 | r#" | ||
2441 | enum Option { Some, None } | ||
2442 | |||
2443 | fn main() { | ||
2444 | match Option::None { | ||
2445 | SOME_VAR @ None => (), | ||
2446 | // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` | ||
2447 | Some => (), | ||
2448 | } | ||
2449 | } | ||
2450 | "#, | ||
2451 | ); | ||
2452 | } | ||
2453 | |||
2454 | #[test] | ||
2455 | fn allow_attributes() { | ||
2456 | check_diagnostics( | ||
2457 | r#" | ||
2458 | #[allow(non_snake_case)] | ||
2459 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ | ||
2460 | // cov_flags generated output from elsewhere in this file | ||
2461 | extern "C" { | ||
2462 | #[no_mangle] | ||
2463 | static lower_case: u8; | ||
2464 | } | ||
2465 | |||
2466 | let OtherVar = SOME_VAR + 1; | ||
2467 | OtherVar | ||
2468 | } | ||
2469 | |||
2470 | #[allow(nonstandard_style)] | ||
2471 | mod CheckNonstandardStyle { | ||
2472 | fn HiImABadFnName() {} | ||
2473 | } | ||
2474 | |||
2475 | #[allow(bad_style)] | ||
2476 | mod CheckBadStyle { | ||
2477 | fn HiImABadFnName() {} | ||
2478 | } | ||
2479 | |||
2480 | mod F { | ||
2481 | #![allow(non_snake_case)] | ||
2482 | fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {} | ||
2483 | } | ||
2484 | |||
2485 | #[allow(non_snake_case, non_camel_case_types)] | ||
2486 | pub struct some_type { | ||
2487 | SOME_FIELD: u8, | ||
2488 | SomeField: u16, | ||
2489 | } | ||
2490 | |||
2491 | #[allow(non_upper_case_globals)] | ||
2492 | pub const some_const: u8 = 10; | ||
2493 | |||
2494 | #[allow(non_upper_case_globals)] | ||
2495 | pub static SomeStatic: u8 = 10; | ||
2496 | "#, | ||
2497 | ); | ||
2498 | } | ||
2499 | |||
2500 | #[test] | ||
2501 | fn allow_attributes_crate_attr() { | ||
2502 | check_diagnostics( | ||
2503 | r#" | ||
2504 | #![allow(non_snake_case)] | ||
2505 | |||
2506 | mod F { | ||
2507 | fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {} | ||
2508 | } | ||
2509 | "#, | ||
2510 | ); | ||
2511 | } | ||
2512 | |||
2513 | #[test] | ||
2514 | #[ignore] | ||
2515 | fn bug_trait_inside_fn() { | ||
2516 | // FIXME: | ||
2517 | // This is broken, and in fact, should not even be looked at by this | ||
2518 | // lint in the first place. There's weird stuff going on in the | ||
2519 | // collection phase. | ||
2520 | // It's currently being brought in by: | ||
2521 | // * validate_func on `a` recursing into modules | ||
2522 | // * then it finds the trait and then the function while iterating | ||
2523 | // through modules | ||
2524 | // * then validate_func is called on Dirty | ||
2525 | // * ... which then proceeds to look at some unknown module taking no | ||
2526 | // attrs from either the impl or the fn a, and then finally to the root | ||
2527 | // module | ||
2528 | // | ||
2529 | // It should find the attribute on the trait, but it *doesn't even see | ||
2530 | // the trait* as far as I can tell. | ||
2531 | |||
2532 | check_diagnostics( | ||
2533 | r#" | ||
2534 | trait T { fn a(); } | ||
2535 | struct U {} | ||
2536 | impl T for U { | ||
2537 | fn a() { | ||
2538 | // this comes out of bitflags, mostly | ||
2539 | #[allow(non_snake_case)] | ||
2540 | trait __BitFlags { | ||
2541 | const HiImAlsoBad: u8 = 2; | ||
2542 | #[inline] | ||
2543 | fn Dirty(&self) -> bool { | ||
2544 | false | ||
2545 | } | ||
2546 | } | ||
2547 | |||
2548 | } | ||
2549 | } | ||
2550 | "#, | ||
2551 | ); | ||
2552 | } | ||
2553 | |||
2554 | #[test] | ||
2555 | #[ignore] | ||
2556 | fn bug_traits_arent_checked() { | ||
2557 | // FIXME: Traits and functions in traits aren't currently checked by | ||
2558 | // r-a, even though rustc will complain about them. | ||
2559 | check_diagnostics( | ||
2560 | r#" | ||
2561 | trait BAD_TRAIT { | ||
2562 | // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` | ||
2563 | fn BAD_FUNCTION(); | ||
2564 | // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` | ||
2565 | fn BadFunction(); | ||
2566 | // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` | ||
2567 | } | ||
2568 | "#, | ||
2569 | ); | ||
2570 | } | ||
2571 | |||
2572 | #[test] | ||
2573 | fn ignores_extern_items() { | ||
2574 | cov_mark::check!(extern_func_incorrect_case_ignored); | ||
2575 | cov_mark::check!(extern_static_incorrect_case_ignored); | ||
2576 | check_diagnostics( | ||
2577 | r#" | ||
2578 | extern { | ||
2579 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8; | ||
2580 | pub static SomeStatic: u8 = 10; | ||
2581 | } | ||
2582 | "#, | ||
2583 | ); | ||
2584 | } | ||
2585 | |||
2586 | #[test] | ||
2587 | fn infinite_loop_inner_items() { | ||
2588 | check_diagnostics( | ||
2589 | r#" | ||
2590 | fn qualify() { | ||
2591 | mod foo { | ||
2592 | use super::*; | ||
2593 | } | ||
2594 | } | ||
2595 | "#, | ||
2596 | ) | ||
2597 | } | ||
2598 | |||
2599 | #[test] // Issue #8809. | ||
2600 | fn parenthesized_parameter() { | ||
2601 | check_diagnostics(r#"fn f((O): _) {}"#) | ||
2602 | } | ||
722 | } | 2603 | } |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 43356a94e..95fd39850 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -52,13 +52,13 @@ pub(crate) fn goto_implementation( | |||
52 | hir::ModuleDef::Function(f) => { | 52 | hir::ModuleDef::Function(f) => { |
53 | let assoc = f.as_assoc_item(sema.db)?; | 53 | let assoc = f.as_assoc_item(sema.db)?; |
54 | let name = assoc.name(sema.db)?; | 54 | let name = assoc.name(sema.db)?; |
55 | let trait_ = assoc.containing_trait(sema.db)?; | 55 | let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; |
56 | impls_for_trait_item(&sema, trait_, name) | 56 | impls_for_trait_item(&sema, trait_, name) |
57 | } | 57 | } |
58 | hir::ModuleDef::Const(c) => { | 58 | hir::ModuleDef::Const(c) => { |
59 | let assoc = c.as_assoc_item(sema.db)?; | 59 | let assoc = c.as_assoc_item(sema.db)?; |
60 | let name = assoc.name(sema.db)?; | 60 | let name = assoc.name(sema.db)?; |
61 | let trait_ = assoc.containing_trait(sema.db)?; | 61 | let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; |
62 | impls_for_trait_item(&sema, trait_, name) | 62 | impls_for_trait_item(&sema, trait_, name) |
63 | } | 63 | } |
64 | _ => return None, | 64 | _ => return None, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index ed4f18e1f..1c6d36939 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -208,7 +208,7 @@ pub(crate) fn hover( | |||
208 | } | 208 | } |
209 | 209 | ||
210 | fn try_hover_for_attribute(token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> { | 210 | fn try_hover_for_attribute(token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> { |
211 | let attr = token.ancestors().nth(1).and_then(ast::Attr::cast)?; | 211 | let attr = token.ancestors().find_map(ast::Attr::cast)?; |
212 | let (path, tt) = attr.as_simple_call()?; | 212 | let (path, tt) = attr.as_simple_call()?; |
213 | if !tt.syntax().text_range().contains(token.text_range().start()) { | 213 | if !tt.syntax().text_range().contains(token.text_range().start()) { |
214 | return None; | 214 | return None; |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 2a4a1c3c8..7dfc5043e 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -239,7 +239,7 @@ fn rename_mod( | |||
239 | 239 | ||
240 | fn rename_reference( | 240 | fn rename_reference( |
241 | sema: &Semantics<RootDatabase>, | 241 | sema: &Semantics<RootDatabase>, |
242 | def: Definition, | 242 | mut def: Definition, |
243 | new_name: &str, | 243 | new_name: &str, |
244 | ) -> RenameResult<SourceChange> { | 244 | ) -> RenameResult<SourceChange> { |
245 | let ident_kind = check_identifier(new_name)?; | 245 | let ident_kind = check_identifier(new_name)?; |
@@ -285,7 +285,38 @@ fn rename_reference( | |||
285 | } | 285 | } |
286 | } | 286 | } |
287 | 287 | ||
288 | def = match def { | ||
289 | // HACK: resolve trait impl items to the item def of the trait definition | ||
290 | // so that we properly resolve all trait item references | ||
291 | Definition::ModuleDef(mod_def) => mod_def | ||
292 | .as_assoc_item(sema.db) | ||
293 | .and_then(|it| it.containing_trait_impl(sema.db)) | ||
294 | .and_then(|it| { | ||
295 | it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) { | ||
296 | (hir::AssocItem::Function(trait_func), ModuleDef::Function(func)) | ||
297 | if trait_func.name(sema.db) == func.name(sema.db) => | ||
298 | { | ||
299 | Some(Definition::ModuleDef(ModuleDef::Function(trait_func))) | ||
300 | } | ||
301 | (hir::AssocItem::Const(trait_konst), ModuleDef::Const(konst)) | ||
302 | if trait_konst.name(sema.db) == konst.name(sema.db) => | ||
303 | { | ||
304 | Some(Definition::ModuleDef(ModuleDef::Const(trait_konst))) | ||
305 | } | ||
306 | ( | ||
307 | hir::AssocItem::TypeAlias(trait_type_alias), | ||
308 | ModuleDef::TypeAlias(type_alias), | ||
309 | ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => { | ||
310 | Some(Definition::ModuleDef(ModuleDef::TypeAlias(trait_type_alias))) | ||
311 | } | ||
312 | _ => None, | ||
313 | }) | ||
314 | }) | ||
315 | .unwrap_or(def), | ||
316 | _ => def, | ||
317 | }; | ||
288 | let usages = def.usages(sema).all(); | 318 | let usages = def.usages(sema).all(); |
319 | |||
289 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { | 320 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { |
290 | cov_mark::hit!(rename_underscore_multiple); | 321 | cov_mark::hit!(rename_underscore_multiple); |
291 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | 322 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); |
@@ -1938,4 +1969,136 @@ use Bar$0; | |||
1938 | "error: Renaming aliases is currently unsupported", | 1969 | "error: Renaming aliases is currently unsupported", |
1939 | ); | 1970 | ); |
1940 | } | 1971 | } |
1972 | |||
1973 | #[test] | ||
1974 | fn test_rename_trait_method() { | ||
1975 | let res = r" | ||
1976 | trait Foo { | ||
1977 | fn foo(&self) { | ||
1978 | self.foo(); | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | impl Foo for () { | ||
1983 | fn foo(&self) { | ||
1984 | self.foo(); | ||
1985 | } | ||
1986 | }"; | ||
1987 | check( | ||
1988 | "foo", | ||
1989 | r#" | ||
1990 | trait Foo { | ||
1991 | fn bar$0(&self) { | ||
1992 | self.bar(); | ||
1993 | } | ||
1994 | } | ||
1995 | |||
1996 | impl Foo for () { | ||
1997 | fn bar(&self) { | ||
1998 | self.bar(); | ||
1999 | } | ||
2000 | }"#, | ||
2001 | res, | ||
2002 | ); | ||
2003 | check( | ||
2004 | "foo", | ||
2005 | r#" | ||
2006 | trait Foo { | ||
2007 | fn bar(&self) { | ||
2008 | self.bar$0(); | ||
2009 | } | ||
2010 | } | ||
2011 | |||
2012 | impl Foo for () { | ||
2013 | fn bar(&self) { | ||
2014 | self.bar(); | ||
2015 | } | ||
2016 | }"#, | ||
2017 | res, | ||
2018 | ); | ||
2019 | check( | ||
2020 | "foo", | ||
2021 | r#" | ||
2022 | trait Foo { | ||
2023 | fn bar(&self) { | ||
2024 | self.bar(); | ||
2025 | } | ||
2026 | } | ||
2027 | |||
2028 | impl Foo for () { | ||
2029 | fn bar$0(&self) { | ||
2030 | self.bar(); | ||
2031 | } | ||
2032 | }"#, | ||
2033 | res, | ||
2034 | ); | ||
2035 | check( | ||
2036 | "foo", | ||
2037 | r#" | ||
2038 | trait Foo { | ||
2039 | fn bar(&self) { | ||
2040 | self.bar(); | ||
2041 | } | ||
2042 | } | ||
2043 | |||
2044 | impl Foo for () { | ||
2045 | fn bar(&self) { | ||
2046 | self.bar$0(); | ||
2047 | } | ||
2048 | }"#, | ||
2049 | res, | ||
2050 | ); | ||
2051 | } | ||
2052 | |||
2053 | #[test] | ||
2054 | fn test_rename_trait_const() { | ||
2055 | let res = r" | ||
2056 | trait Foo { | ||
2057 | const FOO: (); | ||
2058 | } | ||
2059 | |||
2060 | impl Foo for () { | ||
2061 | const FOO: (); | ||
2062 | } | ||
2063 | fn f() { <()>::FOO; }"; | ||
2064 | check( | ||
2065 | "FOO", | ||
2066 | r#" | ||
2067 | trait Foo { | ||
2068 | const BAR$0: (); | ||
2069 | } | ||
2070 | |||
2071 | impl Foo for () { | ||
2072 | const BAR: (); | ||
2073 | } | ||
2074 | fn f() { <()>::BAR; }"#, | ||
2075 | res, | ||
2076 | ); | ||
2077 | check( | ||
2078 | "FOO", | ||
2079 | r#" | ||
2080 | trait Foo { | ||
2081 | const BAR: (); | ||
2082 | } | ||
2083 | |||
2084 | impl Foo for () { | ||
2085 | const BAR$0: (); | ||
2086 | } | ||
2087 | fn f() { <()>::BAR; }"#, | ||
2088 | res, | ||
2089 | ); | ||
2090 | check( | ||
2091 | "FOO", | ||
2092 | r#" | ||
2093 | trait Foo { | ||
2094 | const BAR: (); | ||
2095 | } | ||
2096 | |||
2097 | impl Foo for () { | ||
2098 | const BAR: (); | ||
2099 | } | ||
2100 | fn f() { <()>::BAR$0; }"#, | ||
2101 | res, | ||
2102 | ); | ||
2103 | } | ||
1941 | } | 2104 | } |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 9503c936d..84012227d 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -131,6 +131,9 @@ pub(super) fn element( | |||
131 | } | 131 | } |
132 | STRING | BYTE_STRING => HlTag::StringLiteral.into(), | 132 | STRING | BYTE_STRING => HlTag::StringLiteral.into(), |
133 | ATTR => HlTag::Attribute.into(), | 133 | ATTR => HlTag::Attribute.into(), |
134 | INT_NUMBER if element.ancestors().nth(1).map_or(false, |it| it.kind() == FIELD_EXPR) => { | ||
135 | SymbolKind::Field.into() | ||
136 | } | ||
134 | INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), | 137 | INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), |
135 | BYTE => HlTag::ByteLiteral.into(), | 138 | BYTE => HlTag::ByteLiteral.into(), |
136 | CHAR => HlTag::CharLiteral.into(), | 139 | CHAR => HlTag::CharLiteral.into(), |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index a7b5c3b89..59f1e8e4c 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -215,8 +215,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
215 | <span class="keyword">let</span> <span class="variable callable declaration">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span> | 215 | <span class="keyword">let</span> <span class="variable callable declaration">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span> |
216 | <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span> | 216 | <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span> |
217 | 217 | ||
218 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> | 218 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="comma">,</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
219 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> | 219 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="operator">.</span><span class="field">0</span><span class="semicolon">;</span> |
220 | 220 | ||
221 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> | 221 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> |
222 | 222 | ||
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 6ad2a362a..f7d8334a0 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -189,8 +189,8 @@ fn main() { | |||
189 | let a = |x| x; | 189 | let a = |x| x; |
190 | let bar = Foo::baz; | 190 | let bar = Foo::baz; |
191 | 191 | ||
192 | let baz = -42; | 192 | let baz = (-42,); |
193 | let baz = -baz; | 193 | let baz = -baz.0; |
194 | 194 | ||
195 | let _ = !true; | 195 | let _ = !true; |
196 | 196 | ||
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml index a83acb191..0d0d1605e 100644 --- a/crates/ide_assists/Cargo.toml +++ b/crates/ide_assists/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | itertools = "0.10.0" | 15 | itertools = "0.10.0" |
16 | either = "1.6.1" | 16 | either = "1.6.1" |
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs index d7e39b2ae..ed936667f 100644 --- a/crates/ide_assists/src/handlers/change_visibility.rs +++ b/crates/ide_assists/src/handlers/change_visibility.rs | |||
@@ -1,7 +1,9 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{self, NameOwner, VisibilityOwner}, | 2 | ast::{self, NameOwner, VisibilityOwner}, |
3 | AstNode, | 3 | AstNode, |
4 | SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, | 4 | SyntaxKind::{ |
5 | CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY, | ||
6 | }, | ||
5 | T, | 7 | T, |
6 | }; | 8 | }; |
7 | 9 | ||
@@ -37,12 +39,15 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
37 | | T![enum] | 39 | | T![enum] |
38 | | T![trait] | 40 | | T![trait] |
39 | | T![type] | 41 | | T![type] |
42 | | T![use] | ||
43 | | T![macro] | ||
40 | ) | 44 | ) |
41 | }); | 45 | }); |
42 | 46 | ||
43 | let (offset, target) = if let Some(keyword) = item_keyword { | 47 | let (offset, target) = if let Some(keyword) = item_keyword { |
44 | let parent = keyword.parent()?; | 48 | let parent = keyword.parent()?; |
45 | let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT]; | 49 | let def_kws = |
50 | vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF]; | ||
46 | // Parent is not a definition, can't add visibility | 51 | // Parent is not a definition, can't add visibility |
47 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { | 52 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { |
48 | return None; | 53 | return None; |
@@ -122,6 +127,8 @@ mod tests { | |||
122 | check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); | 127 | check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); |
123 | check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); | 128 | check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); |
124 | check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); | 129 | check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); |
130 | check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}"); | ||
131 | check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;"); | ||
125 | } | 132 | } |
126 | 133 | ||
127 | #[test] | 134 | #[test] |
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml index ba81c9e04..3c45fe1cb 100644 --- a/crates/ide_completion/Cargo.toml +++ b/crates/ide_completion/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | log = "0.4.8" | 15 | log = "0.4.8" |
16 | rustc-hash = "1.1.0" | 16 | rustc-hash = "1.1.0" |
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index fbd499900..bd90cefb2 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -29,7 +29,7 @@ use crate::{ | |||
29 | macro_::render_macro, | 29 | macro_::render_macro, |
30 | pattern::{render_struct_pat, render_variant_pat}, | 30 | pattern::{render_struct_pat, render_variant_pat}, |
31 | render_field, render_resolution, render_tuple_field, | 31 | render_field, render_resolution, render_tuple_field, |
32 | type_alias::render_type_alias, | 32 | type_alias::{render_type_alias, render_type_alias_with_eq}, |
33 | RenderContext, | 33 | RenderContext, |
34 | }, | 34 | }, |
35 | CompletionContext, CompletionItem, CompletionItemKind, | 35 | CompletionContext, CompletionItem, CompletionItemKind, |
@@ -188,6 +188,14 @@ impl Completions { | |||
188 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); | 188 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); |
189 | } | 189 | } |
190 | 190 | ||
191 | pub(crate) fn add_type_alias_with_eq( | ||
192 | &mut self, | ||
193 | ctx: &CompletionContext, | ||
194 | type_alias: hir::TypeAlias, | ||
195 | ) { | ||
196 | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); | ||
197 | } | ||
198 | |||
191 | pub(crate) fn add_qualified_enum_variant( | 199 | pub(crate) fn add_qualified_enum_variant( |
192 | &mut self, | 200 | &mut self, |
193 | ctx: &CompletionContext, | 201 | ctx: &CompletionContext, |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index c010cbbca..30b8d44bd 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! Feature: completion with imports-on-the-fly | 1 | //! Feature: completion with imports-on-the-fly |
2 | //! | 2 | //! |
3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, | 3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, |
4 | //! if they can be qualified in the scope and their name contains all symbols from the completion input. | 4 | //! if they can be qualified in the scope, and their name contains all symbols from the completion input. |
5 | //! | 5 | //! |
6 | //! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. | 6 | //! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. |
7 | //! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively. | 7 | //! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively. |
8 | //! | 8 | //! |
9 | //! ``` | 9 | //! ``` |
10 | //! fn main() { | 10 | //! fn main() { |
@@ -23,8 +23,8 @@ | |||
23 | //! ``` | 23 | //! ``` |
24 | //! | 24 | //! |
25 | //! Also completes associated items, that require trait imports. | 25 | //! Also completes associated items, that require trait imports. |
26 | //! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account. | 26 | //! If any unresolved and/or partially-qualified path precedes the input, it will be taken into account. |
27 | //! Currently, only the imports with their import path ending with the whole qialifier will be proposed | 27 | //! Currently, only the imports with their import path ending with the whole qualifier will be proposed |
28 | //! (no fuzzy matching for qualifier). | 28 | //! (no fuzzy matching for qualifier). |
29 | //! | 29 | //! |
30 | //! ``` | 30 | //! ``` |
@@ -61,14 +61,14 @@ | |||
61 | //! } | 61 | //! } |
62 | //! ``` | 62 | //! ``` |
63 | //! | 63 | //! |
64 | //! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path, | 64 | //! NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path, |
65 | //! no imports will be proposed. | 65 | //! no imports will be proposed. |
66 | //! | 66 | //! |
67 | //! .Fuzzy search details | 67 | //! .Fuzzy search details |
68 | //! | 68 | //! |
69 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | 69 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only |
70 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). | 70 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). |
71 | //! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols | 71 | //! For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols |
72 | //! (but shows all associated items for any input length). | 72 | //! (but shows all associated items for any input length). |
73 | //! | 73 | //! |
74 | //! .Import configuration | 74 | //! .Import configuration |
@@ -79,15 +79,15 @@ | |||
79 | //! .LSP and performance implications | 79 | //! .LSP and performance implications |
80 | //! | 80 | //! |
81 | //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | 81 | //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` |
82 | //! (case sensitive) resolve client capability in its client capabilities. | 82 | //! (case-sensitive) resolve client capability in its client capabilities. |
83 | //! This way the server is able to defer the costly computations, doing them for a selected completion item only. | 83 | //! This way the server is able to defer the costly computations, doing them for a selected completion item only. |
84 | //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | 84 | //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, |
85 | //! which might be slow ergo the feature is automatically disabled. | 85 | //! which might be slow ergo the feature is automatically disabled. |
86 | //! | 86 | //! |
87 | //! .Feature toggle | 87 | //! .Feature toggle |
88 | //! | 88 | //! |
89 | //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | 89 | //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag. |
90 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 90 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding |
91 | //! capability enabled. | 91 | //! capability enabled. |
92 | 92 | ||
93 | use ide_db::helpers::{ | 93 | use ide_db::helpers::{ |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index b1e6b2b77..952f052a1 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use hir::ScopeDef; | 3 | use hir::ScopeDef; |
4 | use syntax::{ast, AstNode}; | ||
4 | 5 | ||
5 | use crate::{CompletionContext, Completions}; | 6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; |
6 | 7 | ||
7 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
8 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() { | 9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() { |
@@ -43,6 +44,20 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
43 | }); | 44 | }); |
44 | } | 45 | } |
45 | 46 | ||
47 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { | ||
48 | if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) { | ||
49 | if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) = | ||
50 | ctx.sema.resolve_path(&path_seg.parent_path()) | ||
51 | { | ||
52 | trait_.items(ctx.sema.db).into_iter().for_each(|it| { | ||
53 | if let hir::AssocItem::TypeAlias(alias) = it { | ||
54 | acc.add_type_alias_with_eq(ctx, alias) | ||
55 | } | ||
56 | }); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
46 | ctx.scope.process_all_names(&mut |name, res| { | 61 | ctx.scope.process_all_names(&mut |name, res| { |
47 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 62 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { |
48 | cov_mark::hit!(skip_lifetime_completion); | 63 | cov_mark::hit!(skip_lifetime_completion); |
@@ -777,4 +792,21 @@ $0 | |||
777 | "#]], | 792 | "#]], |
778 | ) | 793 | ) |
779 | } | 794 | } |
795 | |||
796 | #[test] | ||
797 | fn completes_assoc_types_in_dynimpl_trait() { | ||
798 | check( | ||
799 | r#" | ||
800 | trait Foo { | ||
801 | type Bar; | ||
802 | } | ||
803 | |||
804 | fn foo(_: impl Foo<B$0>) {} | ||
805 | "#, | ||
806 | expect![[r#" | ||
807 | ta Bar = type Bar; | ||
808 | tt Foo | ||
809 | "#]], | ||
810 | ); | ||
811 | } | ||
780 | } | 812 | } |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index ee87bf461..81d7a1a1d 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -47,6 +47,9 @@ pub(crate) enum ImmediateLocation { | |||
47 | receiver_is_ambiguous_float_literal: bool, | 47 | receiver_is_ambiguous_float_literal: bool, |
48 | }, | 48 | }, |
49 | // Original file ast node | 49 | // Original file ast node |
50 | // Only set from a type arg | ||
51 | GenericArgList(ast::GenericArgList), | ||
52 | // Original file ast node | ||
50 | /// The record expr of the field name we are completing | 53 | /// The record expr of the field name we are completing |
51 | RecordExpr(ast::RecordExpr), | 54 | RecordExpr(ast::RecordExpr), |
52 | // Original file ast node | 55 | // Original file ast node |
@@ -159,7 +162,6 @@ pub(crate) fn determine_location( | |||
159 | } | 162 | } |
160 | } | 163 | } |
161 | }; | 164 | }; |
162 | |||
163 | let res = match_ast! { | 165 | let res = match_ast! { |
164 | match parent { | 166 | match parent { |
165 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, | 167 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, |
@@ -174,6 +176,9 @@ pub(crate) fn determine_location( | |||
174 | Some(TRAIT) => ImmediateLocation::Trait, | 176 | Some(TRAIT) => ImmediateLocation::Trait, |
175 | _ => return None, | 177 | _ => return None, |
176 | }, | 178 | }, |
179 | ast::GenericArgList(_it) => sema | ||
180 | .find_node_at_offset_with_macros(original_file, offset) | ||
181 | .map(ImmediateLocation::GenericArgList)?, | ||
177 | ast::Module(it) => { | 182 | ast::Module(it) => { |
178 | if it.item_list().is_none() { | 183 | if it.item_list().is_none() { |
179 | ImmediateLocation::ModDeclaration(it) | 184 | ImmediateLocation::ModDeclaration(it) |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 902df46ca..d3db55c35 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -111,7 +111,10 @@ impl<'a> RenderContext<'a> { | |||
111 | hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), | 111 | hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), |
112 | }; | 112 | }; |
113 | is_assoc_deprecated | 113 | is_assoc_deprecated |
114 | || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) | 114 | || assoc |
115 | .containing_trait_or_trait_impl(db) | ||
116 | .map(|trait_| self.is_deprecated(trait_)) | ||
117 | .unwrap_or(false) | ||
115 | } | 118 | } |
116 | 119 | ||
117 | fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { | 120 | fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { |
@@ -132,16 +135,17 @@ fn render_field_( | |||
132 | ctx.source_range(), | 135 | ctx.source_range(), |
133 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), | 136 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), |
134 | ); | 137 | ); |
135 | item.kind(SymbolKind::Field) | ||
136 | .detail(ty.display(ctx.db()).to_string()) | ||
137 | .set_documentation(field.docs(ctx.db())) | ||
138 | .set_deprecated(is_deprecated); | ||
139 | 138 | ||
140 | item.set_relevance(CompletionRelevance { | 139 | item.set_relevance(CompletionRelevance { |
141 | type_match: compute_type_match(ctx.completion, ty), | 140 | type_match: compute_type_match(ctx.completion, ty), |
142 | exact_name_match: compute_exact_name_match(ctx.completion, &name), | 141 | exact_name_match: compute_exact_name_match(ctx.completion, &name), |
143 | ..CompletionRelevance::default() | 142 | ..CompletionRelevance::default() |
144 | }); | 143 | }); |
144 | item.kind(SymbolKind::Field) | ||
145 | .detail(ty.display(ctx.db()).to_string()) | ||
146 | .set_documentation(field.docs(ctx.db())) | ||
147 | .set_deprecated(is_deprecated) | ||
148 | .lookup_by(name); | ||
145 | 149 | ||
146 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { | 150 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { |
147 | // FIXME | 151 | // FIXME |
@@ -164,7 +168,9 @@ fn render_tuple_field_( | |||
164 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), | 168 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), |
165 | ); | 169 | ); |
166 | 170 | ||
167 | item.kind(SymbolKind::Field).detail(ty.display(ctx.db()).to_string()); | 171 | item.kind(SymbolKind::Field) |
172 | .detail(ty.display(ctx.db()).to_string()) | ||
173 | .lookup_by(field.to_string()); | ||
168 | 174 | ||
169 | item.build() | 175 | item.build() |
170 | } | 176 | } |
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 1abeed96d..1357b9f4a 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -58,29 +58,29 @@ impl<'a> FunctionRender<'a> { | |||
58 | Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) | 58 | Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) |
59 | } | 59 | } |
60 | 60 | ||
61 | fn render(mut self, import_to_add: Option<ImportEdit>) -> CompletionItem { | 61 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
62 | let params = self.params(); | 62 | let params = self.params(); |
63 | if let Some(receiver) = &self.receiver { | 63 | let call = if let Some(receiver) = &self.receiver { |
64 | self.name = format!("{}.{}", receiver, &self.name) | 64 | format!("{}.{}", receiver, &self.name) |
65 | } | 65 | } else { |
66 | let mut item = CompletionItem::new( | 66 | self.name.clone() |
67 | CompletionKind::Reference, | 67 | }; |
68 | self.ctx.source_range(), | 68 | let mut item = |
69 | self.name.clone(), | 69 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), call.clone()); |
70 | ); | ||
71 | item.kind(self.kind()) | 70 | item.kind(self.kind()) |
72 | .set_documentation(self.ctx.docs(self.func)) | 71 | .set_documentation(self.ctx.docs(self.func)) |
73 | .set_deprecated( | 72 | .set_deprecated( |
74 | self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), | 73 | self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), |
75 | ) | 74 | ) |
76 | .detail(self.detail()) | 75 | .detail(self.detail()) |
77 | .add_call_parens(self.ctx.completion, self.name.clone(), params) | 76 | .add_call_parens(self.ctx.completion, call.clone(), params) |
78 | .add_import(import_to_add); | 77 | .add_import(import_to_add) |
78 | .lookup_by(self.name); | ||
79 | 79 | ||
80 | let ret_type = self.func.ret_type(self.ctx.db()); | 80 | let ret_type = self.func.ret_type(self.ctx.db()); |
81 | item.set_relevance(CompletionRelevance { | 81 | item.set_relevance(CompletionRelevance { |
82 | type_match: compute_type_match(self.ctx.completion, &ret_type), | 82 | type_match: compute_type_match(self.ctx.completion, &ret_type), |
83 | exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name), | 83 | exact_name_match: compute_exact_name_match(self.ctx.completion, &call), |
84 | ..CompletionRelevance::default() | 84 | ..CompletionRelevance::default() |
85 | }); | 85 | }); |
86 | 86 | ||
@@ -263,7 +263,7 @@ fn bar(s: &S) { | |||
263 | ); | 263 | ); |
264 | 264 | ||
265 | check_edit( | 265 | check_edit( |
266 | "self.foo", | 266 | "foo", |
267 | r#" | 267 | r#" |
268 | struct S {} | 268 | struct S {} |
269 | impl S { | 269 | impl S { |
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs index e47b4c745..e0234171a 100644 --- a/crates/ide_completion/src/render/type_alias.rs +++ b/crates/ide_completion/src/render/type_alias.rs | |||
@@ -16,7 +16,14 @@ pub(crate) fn render_type_alias<'a>( | |||
16 | ctx: RenderContext<'a>, | 16 | ctx: RenderContext<'a>, |
17 | type_alias: hir::TypeAlias, | 17 | type_alias: hir::TypeAlias, |
18 | ) -> Option<CompletionItem> { | 18 | ) -> Option<CompletionItem> { |
19 | TypeAliasRender::new(ctx, type_alias)?.render() | 19 | TypeAliasRender::new(ctx, type_alias)?.render(false) |
20 | } | ||
21 | |||
22 | pub(crate) fn render_type_alias_with_eq<'a>( | ||
23 | ctx: RenderContext<'a>, | ||
24 | type_alias: hir::TypeAlias, | ||
25 | ) -> Option<CompletionItem> { | ||
26 | TypeAliasRender::new(ctx, type_alias)?.render(true) | ||
20 | } | 27 | } |
21 | 28 | ||
22 | #[derive(Debug)] | 29 | #[derive(Debug)] |
@@ -32,8 +39,14 @@ impl<'a> TypeAliasRender<'a> { | |||
32 | Some(TypeAliasRender { ctx, type_alias, ast_node }) | 39 | Some(TypeAliasRender { ctx, type_alias, ast_node }) |
33 | } | 40 | } |
34 | 41 | ||
35 | fn render(self) -> Option<CompletionItem> { | 42 | fn render(self, with_eq: bool) -> Option<CompletionItem> { |
36 | let name = self.name()?; | 43 | let name = self.ast_node.name().map(|name| { |
44 | if with_eq { | ||
45 | format!("{} = ", name.text()) | ||
46 | } else { | ||
47 | name.text().to_string() | ||
48 | } | ||
49 | })?; | ||
37 | let detail = self.detail(); | 50 | let detail = self.detail(); |
38 | 51 | ||
39 | let mut item = | 52 | let mut item = |
@@ -49,10 +62,6 @@ impl<'a> TypeAliasRender<'a> { | |||
49 | Some(item.build()) | 62 | Some(item.build()) |
50 | } | 63 | } |
51 | 64 | ||
52 | fn name(&self) -> Option<String> { | ||
53 | self.ast_node.name().map(|name| name.text().to_string()) | ||
54 | } | ||
55 | |||
56 | fn detail(&self) -> String { | 65 | fn detail(&self) -> String { |
57 | type_label(&self.ast_node) | 66 | type_label(&self.ast_node) |
58 | } | 67 | } |
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml index 6229996ec..e219c577a 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | rayon = "1.5.0" | 15 | rayon = "1.5.0" |
16 | fst = { version = "0.4", default-features = false } | 16 | fst = { version = "0.4", default-features = false } |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 1b69d72f9..a54f2c323 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -369,7 +369,7 @@ impl NameRefClass { | |||
369 | } | 369 | } |
370 | 370 | ||
371 | if let Some(resolved) = sema.resolve_path(&path) { | 371 | if let Some(resolved) = sema.resolve_path(&path) { |
372 | if path.syntax().parent().and_then(ast::Attr::cast).is_some() { | 372 | if path.syntax().ancestors().find_map(ast::Attr::cast).is_some() { |
373 | if let PathResolution::Def(ModuleDef::Function(func)) = resolved { | 373 | if let PathResolution::Def(ModuleDef::Function(func)) = resolved { |
374 | if func.attrs(sema.db).by_key("proc_macro_attribute").exists() { | 374 | if func.attrs(sema.db).by_key("proc_macro_attribute").exists() { |
375 | return Some(NameRefClass::Definition(resolved.into())); | 375 | return Some(NameRefClass::Definition(resolved.into())); |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 67840602b..8152630f5 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -8,7 +8,8 @@ use std::{convert::TryInto, mem}; | |||
8 | 8 | ||
9 | use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; | 9 | use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; |
10 | use hir::{ | 10 | use hir::{ |
11 | DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics, Visibility, | 11 | AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics, |
12 | Visibility, | ||
12 | }; | 13 | }; |
13 | use once_cell::unsync::Lazy; | 14 | use once_cell::unsync::Lazy; |
14 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
@@ -303,13 +304,13 @@ impl Definition { | |||
303 | } | 304 | } |
304 | } | 305 | } |
305 | 306 | ||
306 | pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { | 307 | pub fn usages<'a>(self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { |
307 | FindUsages { def: self, sema, scope: None, include_self_kw_refs: None } | 308 | FindUsages { def: self, sema, scope: None, include_self_kw_refs: None } |
308 | } | 309 | } |
309 | } | 310 | } |
310 | 311 | ||
311 | pub struct FindUsages<'a> { | 312 | pub struct FindUsages<'a> { |
312 | def: &'a Definition, | 313 | def: Definition, |
313 | sema: &'a Semantics<'a, RootDatabase>, | 314 | sema: &'a Semantics<'a, RootDatabase>, |
314 | scope: Option<SearchScope>, | 315 | scope: Option<SearchScope>, |
315 | include_self_kw_refs: Option<hir::Type>, | 316 | include_self_kw_refs: Option<hir::Type>, |
@@ -318,7 +319,7 @@ pub struct FindUsages<'a> { | |||
318 | impl<'a> FindUsages<'a> { | 319 | impl<'a> FindUsages<'a> { |
319 | /// Enable searching for `Self` when the definition is a type. | 320 | /// Enable searching for `Self` when the definition is a type. |
320 | pub fn include_self_refs(mut self) -> FindUsages<'a> { | 321 | pub fn include_self_refs(mut self) -> FindUsages<'a> { |
321 | self.include_self_kw_refs = def_to_ty(self.sema, self.def); | 322 | self.include_self_kw_refs = def_to_ty(self.sema, &self.def); |
322 | self | 323 | self |
323 | } | 324 | } |
324 | 325 | ||
@@ -445,7 +446,7 @@ impl<'a> FindUsages<'a> { | |||
445 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, | 446 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, |
446 | ) -> bool { | 447 | ) -> bool { |
447 | match NameRefClass::classify_lifetime(self.sema, lifetime) { | 448 | match NameRefClass::classify_lifetime(self.sema, lifetime) { |
448 | Some(NameRefClass::Definition(def)) if &def == self.def => { | 449 | Some(NameRefClass::Definition(def)) if def == self.def => { |
449 | let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); | 450 | let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); |
450 | let reference = FileReference { | 451 | let reference = FileReference { |
451 | range, | 452 | range, |
@@ -464,7 +465,7 @@ impl<'a> FindUsages<'a> { | |||
464 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, | 465 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, |
465 | ) -> bool { | 466 | ) -> bool { |
466 | match NameRefClass::classify(self.sema, &name_ref) { | 467 | match NameRefClass::classify(self.sema, &name_ref) { |
467 | Some(NameRefClass::Definition(def)) if &def == self.def => { | 468 | Some(NameRefClass::Definition(def)) if def == self.def => { |
468 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); | 469 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); |
469 | let reference = FileReference { | 470 | let reference = FileReference { |
470 | range, | 471 | range, |
@@ -489,10 +490,10 @@ impl<'a> FindUsages<'a> { | |||
489 | Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { | 490 | Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { |
490 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); | 491 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); |
491 | let access = match self.def { | 492 | let access = match self.def { |
492 | Definition::Field(_) if &field == self.def => { | 493 | Definition::Field(_) if field == self.def => { |
493 | reference_access(&field, &name_ref) | 494 | reference_access(&field, &name_ref) |
494 | } | 495 | } |
495 | Definition::Local(l) if &local == l => { | 496 | Definition::Local(l) if local == l => { |
496 | reference_access(&Definition::Local(local), &name_ref) | 497 | reference_access(&Definition::Local(local), &name_ref) |
497 | } | 498 | } |
498 | _ => return false, | 499 | _ => return false, |
@@ -513,7 +514,7 @@ impl<'a> FindUsages<'a> { | |||
513 | match NameClass::classify(self.sema, name) { | 514 | match NameClass::classify(self.sema, name) { |
514 | Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) | 515 | Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) |
515 | if matches!( | 516 | if matches!( |
516 | self.def, Definition::Field(_) if &field_ref == self.def | 517 | self.def, Definition::Field(_) if field_ref == self.def |
517 | ) => | 518 | ) => |
518 | { | 519 | { |
519 | let FileRange { file_id, range } = self.sema.original_range(name.syntax()); | 520 | let FileRange { file_id, range } = self.sema.original_range(name.syntax()); |
@@ -525,12 +526,38 @@ impl<'a> FindUsages<'a> { | |||
525 | }; | 526 | }; |
526 | sink(file_id, reference) | 527 | sink(file_id, reference) |
527 | } | 528 | } |
528 | Some(NameClass::ConstReference(def)) if *self.def == def => { | 529 | Some(NameClass::ConstReference(def)) if self.def == def => { |
529 | let FileRange { file_id, range } = self.sema.original_range(name.syntax()); | 530 | let FileRange { file_id, range } = self.sema.original_range(name.syntax()); |
530 | let reference = | 531 | let reference = |
531 | FileReference { range, name: ast::NameLike::Name(name.clone()), access: None }; | 532 | FileReference { range, name: ast::NameLike::Name(name.clone()), access: None }; |
532 | sink(file_id, reference) | 533 | sink(file_id, reference) |
533 | } | 534 | } |
535 | // Resolve trait impl function definitions to the trait definition's version if self.def is the trait definition's | ||
536 | Some(NameClass::Definition(Definition::ModuleDef(mod_def))) => { | ||
537 | /* poor man's try block */ | ||
538 | (|| { | ||
539 | let this = match self.def { | ||
540 | Definition::ModuleDef(this) if this != mod_def => this, | ||
541 | _ => return None, | ||
542 | }; | ||
543 | let this_trait = this | ||
544 | .as_assoc_item(self.sema.db)? | ||
545 | .containing_trait_or_trait_impl(self.sema.db)?; | ||
546 | let trait_ = mod_def | ||
547 | .as_assoc_item(self.sema.db)? | ||
548 | .containing_trait_or_trait_impl(self.sema.db)?; | ||
549 | (trait_ == this_trait).then(|| { | ||
550 | let FileRange { file_id, range } = self.sema.original_range(name.syntax()); | ||
551 | let reference = FileReference { | ||
552 | range, | ||
553 | name: ast::NameLike::Name(name.clone()), | ||
554 | access: None, | ||
555 | }; | ||
556 | sink(file_id, reference) | ||
557 | }) | ||
558 | })() | ||
559 | .unwrap_or(false) | ||
560 | } | ||
534 | _ => false, | 561 | _ => false, |
535 | } | 562 | } |
536 | } | 563 | } |
diff --git a/crates/ide_ssr/Cargo.toml b/crates/ide_ssr/Cargo.toml index 5d2221ebc..727d17bac 100644 --- a/crates/ide_ssr/Cargo.toml +++ b/crates/ide_ssr/Cargo.toml | |||
@@ -11,7 +11,7 @@ edition = "2018" | |||
11 | doctest = false | 11 | doctest = false |
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | cov-mark = { version = "1.1", features = ["thread-local"] } | 14 | cov-mark = "2.0.0-pre.1" |
15 | rustc-hash = "1.1.0" | 15 | rustc-hash = "1.1.0" |
16 | itertools = "0.10.0" | 16 | itertools = "0.10.0" |
17 | 17 | ||
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml index 8856787c0..f3092d9aa 100644 --- a/crates/mbe/Cargo.toml +++ b/crates/mbe/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | smallvec = "1.2.0" | 15 | smallvec = "1.2.0" |
16 | log = "0.4.8" | 16 | log = "0.4.8" |
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs index 5f173f513..75c88687c 100644 --- a/crates/mbe/src/tests/expand.rs +++ b/crates/mbe/src/tests/expand.rs | |||
@@ -1846,16 +1846,17 @@ fn test_no_space_after_semi_colon() { | |||
1846 | [email protected] | 1846 | [email protected] |
1847 | [email protected] "#" | 1847 | [email protected] "#" |
1848 | [email protected] "[" | 1848 | [email protected] "[" |
1849 | [email protected] | 1849 | [email protected] |
1850 | [email protected] | 1850 | [email protected] |
1851 | [email protected] | 1851 | [email protected] |
1852 | [email protected] "cfg" | 1852 | [email protected] |
1853 | [email protected] | 1853 | [email protected] "cfg" |
1854 | [email protected] "(" | 1854 | [email protected] |
1855 | [email protected] "feature" | 1855 | [email protected] "(" |
1856 | [email protected] "=" | 1856 | [email protected] "feature" |
1857 | [email protected] "\"std\"" | 1857 | [email protected] "=" |
1858 | [email protected] ")" | 1858 | [email protected] "\"std\"" |
1859 | [email protected] ")" | ||
1859 | [email protected] "]" | 1860 | [email protected] "]" |
1860 | [email protected] "mod" | 1861 | [email protected] "mod" |
1861 | [email protected] | 1862 | [email protected] |
@@ -1865,16 +1866,17 @@ fn test_no_space_after_semi_colon() { | |||
1865 | [email protected] | 1866 | [email protected] |
1866 | [email protected] "#" | 1867 | [email protected] "#" |
1867 | [email protected] "[" | 1868 | [email protected] "[" |
1868 | [email protected] | 1869 | [email protected] |
1869 | [email protected] | 1870 | [email protected] |
1870 | [email protected] | 1871 | [email protected] |
1871 | [email protected] "cfg" | 1872 | [email protected] |
1872 | [email protected] | 1873 | [email protected] "cfg" |
1873 | [email protected] "(" | 1874 | [email protected] |
1874 | [email protected] "feature" | 1875 | [email protected] "(" |
1875 | [email protected] "=" | 1876 | [email protected] "feature" |
1876 | [email protected] "\"std\"" | 1877 | [email protected] "=" |
1877 | [email protected] ")" | 1878 | [email protected] "\"std\"" |
1879 | [email protected] ")" | ||
1878 | [email protected] "]" | 1880 | [email protected] "]" |
1879 | [email protected] "mod" | 1881 | [email protected] "mod" |
1880 | [email protected] | 1882 | [email protected] |
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs index b8242cd2f..a44c5e484 100644 --- a/crates/parser/src/grammar/attributes.rs +++ b/crates/parser/src/grammar/attributes.rs | |||
@@ -13,6 +13,7 @@ pub(super) fn outer_attrs(p: &mut Parser) { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | pub(super) fn meta(p: &mut Parser) { | 15 | pub(super) fn meta(p: &mut Parser) { |
16 | let meta = p.start(); | ||
16 | paths::use_path(p); | 17 | paths::use_path(p); |
17 | 18 | ||
18 | match p.current() { | 19 | match p.current() { |
@@ -25,6 +26,8 @@ pub(super) fn meta(p: &mut Parser) { | |||
25 | T!['('] | T!['['] | T!['{'] => items::token_tree(p), | 26 | T!['('] | T!['['] | T!['{'] => items::token_tree(p), |
26 | _ => {} | 27 | _ => {} |
27 | } | 28 | } |
29 | |||
30 | meta.complete(p, META); | ||
28 | } | 31 | } |
29 | 32 | ||
30 | fn attr(p: &mut Parser, inner: bool) { | 33 | fn attr(p: &mut Parser, inner: bool) { |
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index bcefd183a..5f10b82de 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs | |||
@@ -220,7 +220,7 @@ pub enum SyntaxKind { | |||
220 | ITEM_LIST, | 220 | ITEM_LIST, |
221 | ASSOC_ITEM_LIST, | 221 | ASSOC_ITEM_LIST, |
222 | ATTR, | 222 | ATTR, |
223 | META_ITEM, | 223 | META, |
224 | USE_TREE, | 224 | USE_TREE, |
225 | USE_TREE_LIST, | 225 | USE_TREE_LIST, |
226 | PATH, | 226 | PATH, |
diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs index 6ef58c9c1..fbcb9e3c2 100644 --- a/crates/profile/src/memory_usage.rs +++ b/crates/profile/src/memory_usage.rs | |||
@@ -32,9 +32,7 @@ impl MemoryUsage { | |||
32 | allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize), | 32 | allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize), |
33 | } | 33 | } |
34 | } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] { | 34 | } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] { |
35 | // Note: This is incredibly slow. | 35 | memusage_linux() |
36 | let alloc = unsafe { libc::mallinfo() }.uordblks as isize; | ||
37 | MemoryUsage { allocated: Bytes(alloc) } | ||
38 | } else if #[cfg(windows)] { | 36 | } else if #[cfg(windows)] { |
39 | // There doesn't seem to be an API for determining heap usage, so we try to | 37 | // There doesn't seem to be an API for determining heap usage, so we try to |
40 | // approximate that by using the Commit Charge value. | 38 | // approximate that by using the Commit Charge value. |
@@ -58,6 +56,37 @@ impl MemoryUsage { | |||
58 | } | 56 | } |
59 | } | 57 | } |
60 | 58 | ||
59 | #[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "jemalloc")))] | ||
60 | fn memusage_linux() -> MemoryUsage { | ||
61 | // Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2. | ||
62 | // mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB. | ||
63 | // mallinfo2 is very recent, so its presence needs to be detected at runtime. | ||
64 | // Both are abysmally slow. | ||
65 | |||
66 | use std::ffi::CStr; | ||
67 | use std::sync::atomic::{AtomicUsize, Ordering}; | ||
68 | |||
69 | static MALLINFO2: AtomicUsize = AtomicUsize::new(1); | ||
70 | |||
71 | let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed); | ||
72 | if mallinfo2 == 1 { | ||
73 | let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap(); | ||
74 | mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize; | ||
75 | // NB: races don't matter here, since they'll always store the same value | ||
76 | MALLINFO2.store(mallinfo2, Ordering::Relaxed); | ||
77 | } | ||
78 | |||
79 | if mallinfo2 == 0 { | ||
80 | // mallinfo2 does not exist, use mallinfo. | ||
81 | let alloc = unsafe { libc::mallinfo() }.uordblks as isize; | ||
82 | MemoryUsage { allocated: Bytes(alloc) } | ||
83 | } else { | ||
84 | let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) }; | ||
85 | let alloc = mallinfo2().uordblks as isize; | ||
86 | MemoryUsage { allocated: Bytes(alloc) } | ||
87 | } | ||
88 | } | ||
89 | |||
61 | #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] | 90 | #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] |
62 | pub struct Bytes(isize); | 91 | pub struct Bytes(isize); |
63 | 92 | ||
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 2106732cd..f1525a649 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -11,7 +11,7 @@ edition = "2018" | |||
11 | doctest = false | 11 | doctest = false |
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | cov-mark = { version = "1.1", features = ["thread-local"] } | 14 | cov-mark = "2.0.0-pre.1" |
15 | itertools = "0.10.0" | 15 | itertools = "0.10.0" |
16 | rowan = "=0.13.0-pre.6" | 16 | rowan = "=0.13.0-pre.6" |
17 | rustc_lexer = { version = "721.0.0", package = "rustc-ap-rustc_lexer" } | 17 | rustc_lexer = { version = "721.0.0", package = "rustc-ap-rustc_lexer" } |
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 9a88fdb56..702de59a9 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs | |||
@@ -150,10 +150,7 @@ impl Attr { | |||
150 | pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } | 150 | pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } |
151 | pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } | 151 | pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } |
152 | pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } | 152 | pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } |
153 | pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } | 153 | pub fn meta(&self) -> Option<Meta> { support::child(&self.syntax) } |
154 | pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } | ||
155 | pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } | ||
156 | pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) } | ||
157 | pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } | 154 | pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } |
158 | } | 155 | } |
159 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -632,6 +629,16 @@ impl WherePred { | |||
632 | pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } | 629 | pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } |
633 | } | 630 | } |
634 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 631 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
632 | pub struct Meta { | ||
633 | pub(crate) syntax: SyntaxNode, | ||
634 | } | ||
635 | impl Meta { | ||
636 | pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } | ||
637 | pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } | ||
638 | pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } | ||
639 | pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) } | ||
640 | } | ||
641 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
635 | pub struct ExprStmt { | 642 | pub struct ExprStmt { |
636 | pub(crate) syntax: SyntaxNode, | 643 | pub(crate) syntax: SyntaxNode, |
637 | } | 644 | } |
@@ -2072,6 +2079,17 @@ impl AstNode for WherePred { | |||
2072 | } | 2079 | } |
2073 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | 2080 | fn syntax(&self) -> &SyntaxNode { &self.syntax } |
2074 | } | 2081 | } |
2082 | impl AstNode for Meta { | ||
2083 | fn can_cast(kind: SyntaxKind) -> bool { kind == META } | ||
2084 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
2085 | if Self::can_cast(syntax.kind()) { | ||
2086 | Some(Self { syntax }) | ||
2087 | } else { | ||
2088 | None | ||
2089 | } | ||
2090 | } | ||
2091 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
2092 | } | ||
2075 | impl AstNode for ExprStmt { | 2093 | impl AstNode for ExprStmt { |
2076 | fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT } | 2094 | fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT } |
2077 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 2095 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
@@ -3887,6 +3905,11 @@ impl std::fmt::Display for WherePred { | |||
3887 | std::fmt::Display::fmt(self.syntax(), f) | 3905 | std::fmt::Display::fmt(self.syntax(), f) |
3888 | } | 3906 | } |
3889 | } | 3907 | } |
3908 | impl std::fmt::Display for Meta { | ||
3909 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
3910 | std::fmt::Display::fmt(self.syntax(), f) | ||
3911 | } | ||
3912 | } | ||
3890 | impl std::fmt::Display for ExprStmt { | 3913 | impl std::fmt::Display for ExprStmt { |
3891 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 3914 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
3892 | std::fmt::Display::fmt(self.syntax(), f) | 3915 | std::fmt::Display::fmt(self.syntax(), f) |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index a60bc5ad9..3d27d2c1a 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -144,19 +144,20 @@ impl AttrKind { | |||
144 | 144 | ||
145 | impl ast::Attr { | 145 | impl ast::Attr { |
146 | pub fn as_simple_atom(&self) -> Option<SmolStr> { | 146 | pub fn as_simple_atom(&self) -> Option<SmolStr> { |
147 | if self.eq_token().is_some() || self.token_tree().is_some() { | 147 | let meta = self.meta()?; |
148 | if meta.eq_token().is_some() || meta.token_tree().is_some() { | ||
148 | return None; | 149 | return None; |
149 | } | 150 | } |
150 | self.simple_name() | 151 | self.simple_name() |
151 | } | 152 | } |
152 | 153 | ||
153 | pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> { | 154 | pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> { |
154 | let tt = self.token_tree()?; | 155 | let tt = self.meta()?.token_tree()?; |
155 | Some((self.simple_name()?, tt)) | 156 | Some((self.simple_name()?, tt)) |
156 | } | 157 | } |
157 | 158 | ||
158 | pub fn simple_name(&self) -> Option<SmolStr> { | 159 | pub fn simple_name(&self) -> Option<SmolStr> { |
159 | let path = self.path()?; | 160 | let path = self.meta()?.path()?; |
160 | match (path.segment(), path.qualifier()) { | 161 | match (path.segment(), path.qualifier()) { |
161 | (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()), | 162 | (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()), |
162 | _ => None, | 163 | _ => None, |
@@ -174,6 +175,18 @@ impl ast::Attr { | |||
174 | _ => AttrKind::Outer, | 175 | _ => AttrKind::Outer, |
175 | } | 176 | } |
176 | } | 177 | } |
178 | |||
179 | pub fn path(&self) -> Option<ast::Path> { | ||
180 | self.meta()?.path() | ||
181 | } | ||
182 | |||
183 | pub fn expr(&self) -> Option<ast::Expr> { | ||
184 | self.meta()?.expr() | ||
185 | } | ||
186 | |||
187 | pub fn token_tree(&self) -> Option<ast::TokenTree> { | ||
188 | self.meta()?.token_tree() | ||
189 | } | ||
177 | } | 190 | } |
178 | 191 | ||
179 | #[derive(Debug, Clone, PartialEq, Eq)] | 192 | #[derive(Debug, Clone, PartialEq, Eq)] |
diff --git a/crates/syntax/test_data/parser/err/0005_attribute_recover.rast b/crates/syntax/test_data/parser/err/0005_attribute_recover.rast index 4845a6563..6202c8bfe 100644 --- a/crates/syntax/test_data/parser/err/0005_attribute_recover.rast +++ b/crates/syntax/test_data/parser/err/0005_attribute_recover.rast | |||
@@ -3,20 +3,21 @@ [email protected] | |||
3 | [email protected] | 3 | [email protected] |
4 | [email protected] "#" | 4 | [email protected] "#" |
5 | [email protected] "[" | 5 | [email protected] "[" |
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "foo" | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] "foo" |
11 | [email protected] "(" | 11 | [email protected] |
12 | [email protected] "foo" | 12 | [email protected] "(" |
13 | [email protected] "," | 13 | [email protected] "foo" |
14 | [email protected] " " | 14 | [email protected] "," |
15 | [email protected] "+" | 15 | [email protected] " " |
16 | [email protected] "," | 16 | [email protected] "+" |
17 | [email protected] " " | 17 | [email protected] "," |
18 | [email protected] "92" | 18 | [email protected] " " |
19 | [email protected] ")" | 19 | [email protected] "92" |
20 | [email protected] ")" | ||
20 | [email protected] "]" | 21 | [email protected] "]" |
21 | [email protected] "\n" | 22 | [email protected] "\n" |
22 | [email protected] "fn" | 23 | [email protected] "fn" |
@@ -35,24 +36,25 @@ [email protected] | |||
35 | [email protected] | 36 | [email protected] |
36 | [email protected] "#" | 37 | [email protected] "#" |
37 | [email protected] "[" | 38 | [email protected] "[" |
38 | [email protected] | 39 | [email protected] |
39 | [email protected] | 40 | [email protected] |
40 | [email protected] | 41 | [email protected] |
41 | [email protected] "foo" | 42 | [email protected] |
42 | [email protected] | 43 | [email protected] "foo" |
43 | [email protected] "(" | 44 | [email protected] |
44 | [email protected] "\n" | 45 | [email protected] "(" |
45 | [email protected] "fn" | 46 | [email protected] "\n" |
46 | [email protected] " " | 47 | [email protected] "fn" |
47 | [email protected] "foo" | 48 | [email protected] " " |
48 | [email protected] | 49 | [email protected] "foo" |
49 | [email protected] "(" | 50 | [email protected] |
50 | [email protected] ")" | 51 | [email protected] "(" |
51 | [email protected] " " | 52 | [email protected] ")" |
52 | [email protected] | 53 | [email protected] " " |
53 | [email protected] "{" | 54 | [email protected] |
54 | [email protected] "\n" | 55 | [email protected] "{" |
55 | [email protected] "}" | 56 | [email protected] "\n" |
57 | [email protected] "}" | ||
56 | [email protected] "\n" | 58 | [email protected] "\n" |
57 | error 53..53: expected R_PAREN | 59 | error 53..53: expected R_PAREN |
58 | error 53..53: expected `]` | 60 | error 53..53: expected `]` |
diff --git a/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast b/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast index a443b37db..846279748 100644 --- a/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast +++ b/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast | |||
@@ -27,14 +27,15 @@ [email protected] | |||
27 | [email protected] "#" | 27 | [email protected] "#" |
28 | [email protected] "!" | 28 | [email protected] "!" |
29 | [email protected] "[" | 29 | [email protected] "[" |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] | 31 | [email protected] |
32 | [email protected] | 32 | [email protected] |
33 | [email protected] "doc" | 33 | [email protected] |
34 | [email protected] | 34 | [email protected] "doc" |
35 | [email protected] "(" | 35 | [email protected] |
36 | [email protected] "\"Inner attributes not ..." | 36 | [email protected] "(" |
37 | [email protected] ")" | 37 | [email protected] "\"Inner attributes not ..." |
38 | [email protected] ")" | ||
38 | [email protected] "]" | 39 | [email protected] "]" |
39 | [email protected] "\n " | 40 | [email protected] "\n " |
40 | [email protected] "//! Nor are ModuleDoc ..." | 41 | [email protected] "//! Nor are ModuleDoc ..." |
@@ -57,28 +58,30 @@ [email protected] | |||
57 | [email protected] "#" | 58 | [email protected] "#" |
58 | [email protected] "!" | 59 | [email protected] "!" |
59 | [email protected] "[" | 60 | [email protected] "[" |
60 | [email protected] | 61 | [email protected] |
61 | [email protected] | 62 | [email protected] |
62 | [email protected] | 63 | [email protected] |
63 | [email protected] "doc" | 64 | [email protected] |
64 | [email protected] | 65 | [email protected] "doc" |
65 | [email protected] "(" | 66 | [email protected] |
66 | [email protected] "\"Nor here\"" | 67 | [email protected] "(" |
67 | [email protected] ")" | 68 | [email protected] "\"Nor here\"" |
69 | [email protected] ")" | ||
68 | [email protected] "]" | 70 | [email protected] "]" |
69 | [email protected] "\n " | 71 | [email protected] "\n " |
70 | [email protected] | 72 | [email protected] |
71 | [email protected] "#" | 73 | [email protected] "#" |
72 | [email protected] "!" | 74 | [email protected] "!" |
73 | [email protected] "[" | 75 | [email protected] "[" |
74 | [email protected] | 76 | [email protected] |
75 | [email protected] | 77 | [email protected] |
76 | [email protected] | 78 | [email protected] |
77 | [email protected] "doc" | 79 | [email protected] |
78 | [email protected] | 80 | [email protected] "doc" |
79 | [email protected] "(" | 81 | [email protected] |
80 | [email protected] "\"We error on each attr\"" | 82 | [email protected] "(" |
81 | [email protected] ")" | 83 | [email protected] "\"We error on each attr\"" |
84 | [email protected] ")" | ||
82 | [email protected] "]" | 85 | [email protected] "]" |
83 | [email protected] "\n " | 86 | [email protected] "\n " |
84 | [email protected] "//! Nor are ModuleDoc ..." | 87 | [email protected] "//! Nor are ModuleDoc ..." |
@@ -99,14 +102,15 @@ [email protected] | |||
99 | [email protected] "#" | 102 | [email protected] "#" |
100 | [email protected] "!" | 103 | [email protected] "!" |
101 | [email protected] "[" | 104 | [email protected] "[" |
102 | [email protected] | 105 | [email protected] |
103 | [email protected] | 106 | [email protected] |
104 | [email protected] | 107 | [email protected] |
105 | [email protected] "doc" | 108 | [email protected] |
106 | [email protected] | 109 | [email protected] "doc" |
107 | [email protected] "(" | 110 | [email protected] |
108 | [email protected] "\"Nor here\"" | 111 | [email protected] "(" |
109 | [email protected] ")" | 112 | [email protected] "\"Nor here\"" |
113 | [email protected] ")" | ||
110 | [email protected] "]" | 114 | [email protected] "]" |
111 | [email protected] "\n " | 115 | [email protected] "\n " |
112 | [email protected] "//! Nor are ModuleDoc ..." | 116 | [email protected] "//! Nor are ModuleDoc ..." |
diff --git a/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast b/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast index 672dd054a..b6209639d 100644 --- a/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast +++ b/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast | |||
@@ -135,14 +135,15 @@ [email protected] | |||
135 | [email protected] | 135 | [email protected] |
136 | [email protected] "#" | 136 | [email protected] "#" |
137 | [email protected] "[" | 137 | [email protected] "[" |
138 | [email protected] | 138 | [email protected] |
139 | [email protected] | 139 | [email protected] |
140 | [email protected] | 140 | [email protected] |
141 | [email protected] "cfg" | 141 | [email protected] |
142 | [email protected] | 142 | [email protected] "cfg" |
143 | [email protected] "(" | 143 | [email protected] |
144 | [email protected] "test" | 144 | [email protected] "(" |
145 | [email protected] ")" | 145 | [email protected] "test" |
146 | [email protected] ")" | ||
146 | [email protected] "]" | 147 | [email protected] "]" |
147 | [email protected] "\n " | 148 | [email protected] "\n " |
148 | [email protected] | 149 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast b/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast index 33bb085e9..84c8e9ee7 100644 --- a/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast +++ b/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast | |||
@@ -47,14 +47,15 @@ [email protected] | |||
47 | [email protected] | 47 | [email protected] |
48 | [email protected] "#" | 48 | [email protected] "#" |
49 | [email protected] "[" | 49 | [email protected] "[" |
50 | [email protected] | 50 | [email protected] |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] | 52 | [email protected] |
53 | [email protected] "cfg" | 53 | [email protected] |
54 | [email protected] | 54 | [email protected] "cfg" |
55 | [email protected] "(" | 55 | [email protected] |
56 | [email protected] "test" | 56 | [email protected] "(" |
57 | [email protected] ")" | 57 | [email protected] "test" |
58 | [email protected] ")" | ||
58 | [email protected] "]" | 59 | [email protected] "]" |
59 | [email protected] "\n " | 60 | [email protected] "\n " |
60 | [email protected] "}" | 61 | [email protected] "}" |
diff --git a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast b/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast index 8fd8d5e59..7b8b7284f 100644 --- a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast +++ b/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast | |||
@@ -15,10 +15,11 @@ [email protected] | |||
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "#" | 16 | [email protected] "#" |
17 | [email protected] "[" | 17 | [email protected] "[" |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] | 20 | [email protected] |
21 | [email protected] "A" | 21 | [email protected] |
22 | [email protected] "A" | ||
22 | [email protected] "]" | 23 | [email protected] "]" |
23 | [email protected] " " | 24 | [email protected] " " |
24 | [email protected] | 25 | [email protected] |
@@ -35,10 +36,11 @@ [email protected] | |||
35 | [email protected] | 36 | [email protected] |
36 | [email protected] "#" | 37 | [email protected] "#" |
37 | [email protected] "[" | 38 | [email protected] "[" |
38 | [email protected] | 39 | [email protected] |
39 | [email protected] | 40 | [email protected] |
40 | [email protected] | 41 | [email protected] |
41 | [email protected] "B" | 42 | [email protected] |
43 | [email protected] "B" | ||
42 | [email protected] "]" | 44 | [email protected] "]" |
43 | [email protected] " " | 45 | [email protected] " " |
44 | [email protected] | 46 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast index 9ae271817..402950bcc 100644 --- a/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast +++ b/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast | |||
@@ -12,18 +12,19 @@ [email protected] | |||
12 | [email protected] | 12 | [email protected] |
13 | [email protected] "#" | 13 | [email protected] "#" |
14 | [email protected] "[" | 14 | [email protected] "[" |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "serde" | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] "serde" |
20 | [email protected] "(" | 20 | [email protected] |
21 | [email protected] "with" | 21 | [email protected] "(" |
22 | [email protected] " " | 22 | [email protected] "with" |
23 | [email protected] "=" | 23 | [email protected] " " |
24 | [email protected] " " | 24 | [email protected] "=" |
25 | [email protected] "\"url_serde\"" | 25 | [email protected] " " |
26 | [email protected] ")" | 26 | [email protected] "\"url_serde\"" |
27 | [email protected] ")" | ||
27 | [email protected] "]" | 28 | [email protected] "]" |
28 | [email protected] "\n " | 29 | [email protected] "\n " |
29 | [email protected] | 30 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast index 4d09c9f50..db2b645b0 100644 --- a/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast +++ b/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast | |||
@@ -12,18 +12,19 @@ [email protected] | |||
12 | [email protected] | 12 | [email protected] |
13 | [email protected] "#" | 13 | [email protected] "#" |
14 | [email protected] "[" | 14 | [email protected] "[" |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "serde" | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] "serde" |
20 | [email protected] "(" | 20 | [email protected] |
21 | [email protected] "with" | 21 | [email protected] "(" |
22 | [email protected] " " | 22 | [email protected] "with" |
23 | [email protected] "=" | 23 | [email protected] " " |
24 | [email protected] " " | 24 | [email protected] "=" |
25 | [email protected] "\"url_serde\"" | 25 | [email protected] " " |
26 | [email protected] ")" | 26 | [email protected] "\"url_serde\"" |
27 | [email protected] ")" | ||
27 | [email protected] "]" | 28 | [email protected] "]" |
28 | [email protected] "\n " | 29 | [email protected] "\n " |
29 | [email protected] | 30 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast b/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast index 141a7b203..24ac1d66a 100644 --- a/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast +++ b/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast | |||
@@ -26,14 +26,15 @@ [email protected] | |||
26 | [email protected] "#" | 26 | [email protected] "#" |
27 | [email protected] "!" | 27 | [email protected] "!" |
28 | [email protected] "[" | 28 | [email protected] "[" |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] | 31 | [email protected] |
32 | [email protected] "doc" | 32 | [email protected] |
33 | [email protected] | 33 | [email protected] "doc" |
34 | [email protected] "(" | 34 | [email protected] |
35 | [email protected] "\"This is also a doc c ..." | 35 | [email protected] "(" |
36 | [email protected] ")" | 36 | [email protected] "\"This is also a doc c ..." |
37 | [email protected] ")" | ||
37 | [email protected] "]" | 38 | [email protected] "]" |
38 | [email protected] "\n" | 39 | [email protected] "\n" |
39 | [email protected] "}" | 40 | [email protected] "}" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast b/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast index ec7a00f1d..7fbeee203 100644 --- a/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast +++ b/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast | |||
@@ -25,42 +25,45 @@ [email protected] | |||
25 | [email protected] "#" | 25 | [email protected] "#" |
26 | [email protected] "!" | 26 | [email protected] "!" |
27 | [email protected] "[" | 27 | [email protected] "[" |
28 | [email protected] | 28 | [email protected] |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "doc" | 31 | [email protected] |
32 | [email protected] | 32 | [email protected] "doc" |
33 | [email protected] "(" | 33 | [email protected] |
34 | [email protected] "\"Inner attribute\"" | 34 | [email protected] "(" |
35 | [email protected] ")" | 35 | [email protected] "\"Inner attribute\"" |
36 | [email protected] ")" | ||
36 | [email protected] "]" | 37 | [email protected] "]" |
37 | [email protected] "\n " | 38 | [email protected] "\n " |
38 | [email protected] | 39 | [email protected] |
39 | [email protected] "#" | 40 | [email protected] "#" |
40 | [email protected] "!" | 41 | [email protected] "!" |
41 | [email protected] "[" | 42 | [email protected] "[" |
42 | [email protected] | 43 | [email protected] |
43 | [email protected] | 44 | [email protected] |
44 | [email protected] | 45 | [email protected] |
45 | [email protected] "doc" | 46 | [email protected] |
46 | [email protected] | 47 | [email protected] "doc" |
47 | [email protected] "(" | 48 | [email protected] |
48 | [email protected] "\"Can be\"" | 49 | [email protected] "(" |
49 | [email protected] ")" | 50 | [email protected] "\"Can be\"" |
51 | [email protected] ")" | ||
50 | [email protected] "]" | 52 | [email protected] "]" |
51 | [email protected] "\n " | 53 | [email protected] "\n " |
52 | [email protected] | 54 | [email protected] |
53 | [email protected] "#" | 55 | [email protected] "#" |
54 | [email protected] "!" | 56 | [email protected] "!" |
55 | [email protected] "[" | 57 | [email protected] "[" |
56 | [email protected] | 58 | [email protected] |
57 | [email protected] | 59 | [email protected] |
58 | [email protected] | 60 | [email protected] |
59 | [email protected] "doc" | 61 | [email protected] |
60 | [email protected] | 62 | [email protected] "doc" |
61 | [email protected] "(" | 63 | [email protected] |
62 | [email protected] "\"Stacked\"" | 64 | [email protected] "(" |
63 | [email protected] ")" | 65 | [email protected] "\"Stacked\"" |
66 | [email protected] ")" | ||
64 | [email protected] "]" | 67 | [email protected] "]" |
65 | [email protected] "\n " | 68 | [email protected] "\n " |
66 | [email protected] | 69 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast b/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast index 97924da05..40852f514 100644 --- a/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast +++ b/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast | |||
@@ -25,18 +25,19 @@ [email protected] | |||
25 | [email protected] | 25 | [email protected] |
26 | [email protected] "#" | 26 | [email protected] "#" |
27 | [email protected] "[" | 27 | [email protected] "[" |
28 | [email protected] | 28 | [email protected] |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "cfg" | 31 | [email protected] |
32 | [email protected] | 32 | [email protected] "cfg" |
33 | [email protected] "(" | 33 | [email protected] |
34 | [email protected] "feature" | 34 | [email protected] "(" |
35 | [email protected] " " | 35 | [email protected] "feature" |
36 | [email protected] "=" | 36 | [email protected] " " |
37 | [email protected] " " | 37 | [email protected] "=" |
38 | [email protected] "\"some\"" | 38 | [email protected] " " |
39 | [email protected] ")" | 39 | [email protected] "\"some\"" |
40 | [email protected] ")" | ||
40 | [email protected] "]" | 41 | [email protected] "]" |
41 | [email protected] "\n " | 42 | [email protected] "\n " |
42 | [email protected] | 43 | [email protected] |
@@ -53,18 +54,19 @@ [email protected] | |||
53 | [email protected] | 54 | [email protected] |
54 | [email protected] "#" | 55 | [email protected] "#" |
55 | [email protected] "[" | 56 | [email protected] "[" |
56 | [email protected] | 57 | [email protected] |
57 | [email protected] | 58 | [email protected] |
58 | [email protected] | 59 | [email protected] |
59 | [email protected] "cfg" | 60 | [email protected] |
60 | [email protected] | 61 | [email protected] "cfg" |
61 | [email protected] "(" | 62 | [email protected] |
62 | [email protected] "feature" | 63 | [email protected] "(" |
63 | [email protected] " " | 64 | [email protected] "feature" |
64 | [email protected] "=" | 65 | [email protected] " " |
65 | [email protected] " " | 66 | [email protected] "=" |
66 | [email protected] "\"other\"" | 67 | [email protected] " " |
67 | [email protected] ")" | 68 | [email protected] "\"other\"" |
69 | [email protected] ")" | ||
68 | [email protected] "]" | 70 | [email protected] "]" |
69 | [email protected] "\n " | 71 | [email protected] "\n " |
70 | [email protected] | 72 | [email protected] |
@@ -81,52 +83,55 @@ [email protected] | |||
81 | [email protected] | 83 | [email protected] |
82 | [email protected] "#" | 84 | [email protected] "#" |
83 | [email protected] "[" | 85 | [email protected] "[" |
84 | [email protected] | 86 | [email protected] |
85 | [email protected] | 87 | [email protected] |
86 | [email protected] | 88 | [email protected] |
87 | [email protected] "cfg" | 89 | [email protected] |
88 | [email protected] | 90 | [email protected] "cfg" |
89 | [email protected] "(" | 91 | [email protected] |
90 | [email protected] "feature" | 92 | [email protected] "(" |
91 | [email protected] " " | 93 | [email protected] "feature" |
92 | [email protected] "=" | 94 | [email protected] " " |
93 | [email protected] " " | 95 | [email protected] "=" |
94 | [email protected] "\"many\"" | 96 | [email protected] " " |
95 | [email protected] ")" | 97 | [email protected] "\"many\"" |
98 | [email protected] ")" | ||
96 | [email protected] "]" | 99 | [email protected] "]" |
97 | [email protected] "\n " | 100 | [email protected] "\n " |
98 | [email protected] | 101 | [email protected] |
99 | [email protected] "#" | 102 | [email protected] "#" |
100 | [email protected] "[" | 103 | [email protected] "[" |
101 | [email protected] | 104 | [email protected] |
102 | [email protected] | 105 | [email protected] |
103 | [email protected] | 106 | [email protected] |
104 | [email protected] "cfg" | 107 | [email protected] |
105 | [email protected] | 108 | [email protected] "cfg" |
106 | [email protected] "(" | 109 | [email protected] |
107 | [email protected] "feature" | 110 | [email protected] "(" |
108 | [email protected] " " | 111 | [email protected] "feature" |
109 | [email protected] "=" | 112 | [email protected] " " |
110 | [email protected] " " | 113 | [email protected] "=" |
111 | [email protected] "\"attributes\"" | 114 | [email protected] " " |
112 | [email protected] ")" | 115 | [email protected] "\"attributes\"" |
116 | [email protected] ")" | ||
113 | [email protected] "]" | 117 | [email protected] "]" |
114 | [email protected] "\n " | 118 | [email protected] "\n " |
115 | [email protected] | 119 | [email protected] |
116 | [email protected] "#" | 120 | [email protected] "#" |
117 | [email protected] "[" | 121 | [email protected] "[" |
118 | [email protected] | 122 | [email protected] |
119 | [email protected] | 123 | [email protected] |
120 | [email protected] | 124 | [email protected] |
121 | [email protected] "cfg" | 125 | [email protected] |
122 | [email protected] | 126 | [email protected] "cfg" |
123 | [email protected] "(" | 127 | [email protected] |
124 | [email protected] "feature" | 128 | [email protected] "(" |
125 | [email protected] " " | 129 | [email protected] "feature" |
126 | [email protected] "=" | 130 | [email protected] " " |
127 | [email protected] " " | 131 | [email protected] "=" |
128 | [email protected] "\"before\"" | 132 | [email protected] " " |
129 | [email protected] ")" | 133 | [email protected] "\"before\"" |
134 | [email protected] ")" | ||
130 | [email protected] "]" | 135 | [email protected] "]" |
131 | [email protected] "\n " | 136 | [email protected] "\n " |
132 | [email protected] | 137 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast index 616aa984e..840181383 100644 --- a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast +++ b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast | |||
@@ -10,14 +10,15 @@ [email protected] | |||
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "#" | 11 | [email protected] "#" |
12 | [email protected] "[" | 12 | [email protected] "[" |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "derive" | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] "derive" |
18 | [email protected] "(" | 18 | [email protected] |
19 | [email protected] "Lifetime" | 19 | [email protected] "(" |
20 | [email protected] ")" | 20 | [email protected] "Lifetime" |
21 | [email protected] ")" | ||
21 | [email protected] "]" | 22 | [email protected] "]" |
22 | [email protected] " " | 23 | [email protected] " " |
23 | [email protected] | 24 | [email protected] |
@@ -28,14 +29,15 @@ [email protected] | |||
28 | [email protected] | 29 | [email protected] |
29 | [email protected] "#" | 30 | [email protected] "#" |
30 | [email protected] "[" | 31 | [email protected] "[" |
31 | [email protected] | 32 | [email protected] |
32 | [email protected] | 33 | [email protected] |
33 | [email protected] | 34 | [email protected] |
34 | [email protected] "derive" | 35 | [email protected] |
35 | [email protected] | 36 | [email protected] "derive" |
36 | [email protected] "(" | 37 | [email protected] |
37 | [email protected] "Type" | 38 | [email protected] "(" |
38 | [email protected] ")" | 39 | [email protected] "Type" |
40 | [email protected] ")" | ||
39 | [email protected] "]" | 41 | [email protected] "]" |
40 | [email protected] " " | 42 | [email protected] " " |
41 | [email protected] | 43 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast b/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast index 54ea2c7c6..5e82214c0 100644 --- a/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast | |||
@@ -24,14 +24,15 @@ [email protected] | |||
24 | [email protected] | 24 | [email protected] |
25 | [email protected] "#" | 25 | [email protected] "#" |
26 | [email protected] "[" | 26 | [email protected] "[" |
27 | [email protected] | 27 | [email protected] |
28 | [email protected] | 28 | [email protected] |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] "cfg" | 30 | [email protected] |
31 | [email protected] | 31 | [email protected] "cfg" |
32 | [email protected] "(" | 32 | [email protected] |
33 | [email protected] "test" | 33 | [email protected] "(" |
34 | [email protected] ")" | 34 | [email protected] "test" |
35 | [email protected] ")" | ||
35 | [email protected] "]" | 36 | [email protected] "]" |
36 | [email protected] " " | 37 | [email protected] " " |
37 | [email protected] | 38 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast b/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast index 0342e64f3..178204fec 100644 --- a/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast +++ b/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast | |||
@@ -15,10 +15,11 @@ [email protected] | |||
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "#" | 16 | [email protected] "#" |
17 | [email protected] "[" | 17 | [email protected] "[" |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] | 20 | [email protected] |
21 | [email protected] "A" | 21 | [email protected] |
22 | [email protected] "A" | ||
22 | [email protected] "]" | 23 | [email protected] "]" |
23 | [email protected] " " | 24 | [email protected] " " |
24 | [email protected] | 25 | [email protected] |
@@ -36,10 +37,11 @@ [email protected] | |||
36 | [email protected] | 37 | [email protected] |
37 | [email protected] "#" | 38 | [email protected] "#" |
38 | [email protected] "[" | 39 | [email protected] "[" |
39 | [email protected] | 40 | [email protected] |
40 | [email protected] | 41 | [email protected] |
41 | [email protected] | 42 | [email protected] |
42 | [email protected] "B" | 43 | [email protected] |
44 | [email protected] "B" | ||
43 | [email protected] "]" | 45 | [email protected] "]" |
44 | [email protected] " " | 46 | [email protected] " " |
45 | [email protected] | 47 | [email protected] |
@@ -56,19 +58,21 @@ [email protected] | |||
56 | [email protected] | 58 | [email protected] |
57 | [email protected] "#" | 59 | [email protected] "#" |
58 | [email protected] "[" | 60 | [email protected] "[" |
59 | [email protected] | 61 | [email protected] |
60 | [email protected] | 62 | [email protected] |
61 | [email protected] | 63 | [email protected] |
62 | [email protected] "C" | 64 | [email protected] |
65 | [email protected] "C" | ||
63 | [email protected] "]" | 66 | [email protected] "]" |
64 | [email protected] " " | 67 | [email protected] " " |
65 | [email protected] | 68 | [email protected] |
66 | [email protected] "#" | 69 | [email protected] "#" |
67 | [email protected] "[" | 70 | [email protected] "[" |
68 | [email protected] | 71 | [email protected] |
69 | [email protected] | 72 | [email protected] |
70 | [email protected] | 73 | [email protected] |
71 | [email protected] "D" | 74 | [email protected] |
75 | [email protected] "D" | ||
72 | [email protected] "]" | 76 | [email protected] "]" |
73 | [email protected] " " | 77 | [email protected] " " |
74 | [email protected] | 78 | [email protected] |
@@ -79,10 +83,11 @@ [email protected] | |||
79 | [email protected] | 83 | [email protected] |
80 | [email protected] "#" | 84 | [email protected] "#" |
81 | [email protected] "[" | 85 | [email protected] "[" |
82 | [email protected] | 86 | [email protected] |
83 | [email protected] | 87 | [email protected] |
84 | [email protected] | 88 | [email protected] |
85 | [email protected] "D" | 89 | [email protected] |
90 | [email protected] "D" | ||
86 | [email protected] "]" | 91 | [email protected] "]" |
87 | [email protected] " " | 92 | [email protected] " " |
88 | [email protected] | 93 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast b/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast index 3b46e5b47..9daac234a 100644 --- a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast +++ b/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast | |||
@@ -19,10 +19,11 @@ [email protected] | |||
19 | [email protected] | 19 | [email protected] |
20 | [email protected] "#" | 20 | [email protected] "#" |
21 | [email protected] "[" | 21 | [email protected] "[" |
22 | [email protected] | 22 | [email protected] |
23 | [email protected] | 23 | [email protected] |
24 | [email protected] | 24 | [email protected] |
25 | [email protected] "A" | 25 | [email protected] |
26 | [email protected] "A" | ||
26 | [email protected] "]" | 27 | [email protected] "]" |
27 | [email protected] " " | 28 | [email protected] " " |
28 | [email protected] | 29 | [email protected] |
@@ -42,10 +43,11 @@ [email protected] | |||
42 | [email protected] | 43 | [email protected] |
43 | [email protected] "#" | 44 | [email protected] "#" |
44 | [email protected] "[" | 45 | [email protected] "[" |
45 | [email protected] | 46 | [email protected] |
46 | [email protected] | 47 | [email protected] |
47 | [email protected] | 48 | [email protected] |
48 | [email protected] "B" | 49 | [email protected] |
50 | [email protected] "B" | ||
49 | [email protected] "]" | 51 | [email protected] "]" |
50 | [email protected] " " | 52 | [email protected] " " |
51 | [email protected] "&" | 53 | [email protected] "&" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast b/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast index 4c07cefa6..c3a79836a 100644 --- a/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast +++ b/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast | |||
@@ -109,10 +109,11 @@ [email protected] | |||
109 | [email protected] | 109 | [email protected] |
110 | [email protected] "#" | 110 | [email protected] "#" |
111 | [email protected] "[" | 111 | [email protected] "[" |
112 | [email protected] | 112 | [email protected] |
113 | [email protected] | 113 | [email protected] |
114 | [email protected] | 114 | [email protected] |
115 | [email protected] "attr" | 115 | [email protected] |
116 | [email protected] "attr" | ||
116 | [email protected] "]" | 117 | [email protected] "]" |
117 | [email protected] | 118 | [email protected] |
118 | [email protected] "|" | 119 | [email protected] "|" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast index c54e64e3f..891eace59 100644 --- a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast | |||
@@ -10,10 +10,11 @@ [email protected] | |||
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "#" | 11 | [email protected] "#" |
12 | [email protected] "[" | 12 | [email protected] "[" |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "must_use" | 16 | [email protected] |
17 | [email protected] "must_use" | ||
17 | [email protected] "]" | 18 | [email protected] "]" |
18 | [email protected] " " | 19 | [email protected] " " |
19 | [email protected] | 20 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast b/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast index a84088bf3..a363e592b 100644 --- a/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast +++ b/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast | |||
@@ -10,10 +10,11 @@ [email protected] | |||
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "#" | 11 | [email protected] "#" |
12 | [email protected] "[" | 12 | [email protected] "[" |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "attr1" | 16 | [email protected] |
17 | [email protected] "attr1" | ||
17 | [email protected] "]" | 18 | [email protected] "]" |
18 | [email protected] " " | 19 | [email protected] " " |
19 | [email protected] | 20 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast index e9202a612..c606a7c9b 100644 --- a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast +++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast | |||
@@ -87,17 +87,18 @@ [email protected] | |||
87 | [email protected] | 87 | [email protected] |
88 | [email protected] "#" | 88 | [email protected] "#" |
89 | [email protected] "[" | 89 | [email protected] "[" |
90 | [email protected] | 90 | [email protected] |
91 | [email protected] | 91 | [email protected] |
92 | [email protected] | 92 | [email protected] |
93 | [email protected] "cfg" | 93 | [email protected] |
94 | [email protected] | 94 | [email protected] "cfg" |
95 | [email protected] "(" | 95 | [email protected] |
96 | [email protected] "any" | 96 | [email protected] "(" |
97 | [email protected] | 97 | [email protected] "any" |
98 | [email protected] "(" | 98 | [email protected] |
99 | [email protected] ")" | 99 | [email protected] "(" |
100 | [email protected] ")" | 100 | [email protected] ")" |
101 | [email protected] ")" | ||
101 | [email protected] "]" | 102 | [email protected] "]" |
102 | [email protected] " " | 103 | [email protected] " " |
103 | [email protected] | 104 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast index f284aafcd..26cdc2945 100644 --- a/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast +++ b/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast | |||
@@ -31,14 +31,15 @@ [email protected] | |||
31 | [email protected] | 31 | [email protected] |
32 | [email protected] "#" | 32 | [email protected] "#" |
33 | [email protected] "[" | 33 | [email protected] "[" |
34 | [email protected] | 34 | [email protected] |
35 | [email protected] | 35 | [email protected] |
36 | [email protected] | 36 | [email protected] |
37 | [email protected] "cfg" | 37 | [email protected] |
38 | [email protected] | 38 | [email protected] "cfg" |
39 | [email protected] "(" | 39 | [email protected] |
40 | [email protected] "test" | 40 | [email protected] "(" |
41 | [email protected] ")" | 41 | [email protected] "test" |
42 | [email protected] ")" | ||
42 | [email protected] "]" | 43 | [email protected] "]" |
43 | [email protected] " " | 44 | [email protected] " " |
44 | [email protected] "2" | 45 | [email protected] "2" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast b/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast index 2905c5f1a..1d20765b0 100644 --- a/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast | |||
@@ -23,10 +23,11 @@ [email protected] | |||
23 | [email protected] | 23 | [email protected] |
24 | [email protected] "#" | 24 | [email protected] "#" |
25 | [email protected] "[" | 25 | [email protected] "[" |
26 | [email protected] | 26 | [email protected] |
27 | [email protected] | 27 | [email protected] |
28 | [email protected] | 28 | [email protected] |
29 | [email protected] "attr" | 29 | [email protected] |
30 | [email protected] "attr" | ||
30 | [email protected] "]" | 31 | [email protected] "]" |
31 | [email protected] " " | 32 | [email protected] " " |
32 | [email protected] "92" | 33 | [email protected] "92" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast index d34b21abe..3b6612677 100644 --- a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast | |||
@@ -34,14 +34,15 @@ [email protected] | |||
34 | [email protected] | 34 | [email protected] |
35 | [email protected] "#" | 35 | [email protected] "#" |
36 | [email protected] "[" | 36 | [email protected] "[" |
37 | [email protected] | 37 | [email protected] |
38 | [email protected] | 38 | [email protected] |
39 | [email protected] | 39 | [email protected] |
40 | [email protected] "cfg" | 40 | [email protected] |
41 | [email protected] | 41 | [email protected] "cfg" |
42 | [email protected] "(" | 42 | [email protected] |
43 | [email protected] "test" | 43 | [email protected] "(" |
44 | [email protected] ")" | 44 | [email protected] "test" |
45 | [email protected] ")" | ||
45 | [email protected] "]" | 46 | [email protected] "]" |
46 | [email protected] " " | 47 | [email protected] " " |
47 | [email protected] "2" | 48 | [email protected] "2" |
diff --git a/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast b/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast index 42587243a..be2d1dc12 100644 --- a/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast +++ b/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast | |||
@@ -3,182 +3,192 @@ [email protected] | |||
3 | [email protected] "#" | 3 | [email protected] "#" |
4 | [email protected] "!" | 4 | [email protected] "!" |
5 | [email protected] "[" | 5 | [email protected] "[" |
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "attr" | 9 | [email protected] |
10 | [email protected] "attr" | ||
10 | [email protected] "]" | 11 | [email protected] "]" |
11 | [email protected] "\n" | 12 | [email protected] "\n" |
12 | [email protected] | 13 | [email protected] |
13 | [email protected] "#" | 14 | [email protected] "#" |
14 | [email protected] "!" | 15 | [email protected] "!" |
15 | [email protected] "[" | 16 | [email protected] "[" |
16 | [email protected] | 17 | [email protected] |
17 | [email protected] | 18 | [email protected] |
18 | [email protected] | 19 | [email protected] |
19 | [email protected] "attr" | 20 | [email protected] |
20 | [email protected] | 21 | [email protected] "attr" |
21 | [email protected] "(" | 22 | [email protected] |
22 | [email protected] "true" | 23 | [email protected] "(" |
23 | [email protected] ")" | 24 | [email protected] "true" |
25 | [email protected] ")" | ||
24 | [email protected] "]" | 26 | [email protected] "]" |
25 | [email protected] "\n" | 27 | [email protected] "\n" |
26 | [email protected] | 28 | [email protected] |
27 | [email protected] "#" | 29 | [email protected] "#" |
28 | [email protected] "!" | 30 | [email protected] "!" |
29 | [email protected] "[" | 31 | [email protected] "[" |
30 | [email protected] | 32 | [email protected] |
31 | [email protected] | 33 | [email protected] |
32 | [email protected] | 34 | [email protected] |
33 | [email protected] "attr" | 35 | [email protected] |
34 | [email protected] | 36 | [email protected] "attr" |
35 | [email protected] "(" | 37 | [email protected] |
36 | [email protected] "ident" | 38 | [email protected] "(" |
37 | [email protected] ")" | 39 | [email protected] "ident" |
40 | [email protected] ")" | ||
38 | [email protected] "]" | 41 | [email protected] "]" |
39 | [email protected] "\n" | 42 | [email protected] "\n" |
40 | [email protected] | 43 | [email protected] |
41 | [email protected] "#" | 44 | [email protected] "#" |
42 | [email protected] "!" | 45 | [email protected] "!" |
43 | [email protected] "[" | 46 | [email protected] "[" |
44 | [email protected] | 47 | [email protected] |
45 | [email protected] | 48 | [email protected] |
46 | [email protected] | 49 | [email protected] |
47 | [email protected] "attr" | 50 | [email protected] |
48 | [email protected] | 51 | [email protected] "attr" |
49 | [email protected] "(" | 52 | [email protected] |
50 | [email protected] "ident" | 53 | [email protected] "(" |
51 | [email protected] "," | 54 | [email protected] "ident" |
52 | [email protected] " " | 55 | [email protected] "," |
53 | [email protected] "100" | 56 | [email protected] " " |
54 | [email protected] "," | 57 | [email protected] "100" |
55 | [email protected] " " | 58 | [email protected] "," |
56 | [email protected] "true" | 59 | [email protected] " " |
57 | [email protected] "," | 60 | [email protected] "true" |
58 | [email protected] " " | 61 | [email protected] "," |
59 | [email protected] "\"true\"" | 62 | [email protected] " " |
60 | [email protected] "," | 63 | [email protected] "\"true\"" |
61 | [email protected] " " | 64 | [email protected] "," |
62 | [email protected] "ident" | 65 | [email protected] " " |
63 | [email protected] " " | 66 | [email protected] "ident" |
64 | [email protected] "=" | 67 | [email protected] " " |
65 | [email protected] " " | 68 | [email protected] "=" |
66 | [email protected] "100" | 69 | [email protected] " " |
67 | [email protected] "," | 70 | [email protected] "100" |
68 | [email protected] " " | 71 | [email protected] "," |
69 | [email protected] "ident" | 72 | [email protected] " " |
70 | [email protected] " " | 73 | [email protected] "ident" |
71 | [email protected] "=" | 74 | [email protected] " " |
72 | [email protected] " " | 75 | [email protected] "=" |
73 | [email protected] "\"hello\"" | 76 | [email protected] " " |
74 | [email protected] "," | 77 | [email protected] "\"hello\"" |
75 | [email protected] " " | 78 | [email protected] "," |
76 | [email protected] "ident" | 79 | [email protected] " " |
77 | [email protected] | 80 | [email protected] "ident" |
78 | [email protected] "(" | 81 | [email protected] |
79 | [email protected] "100" | 82 | [email protected] "(" |
80 | [email protected] ")" | 83 | [email protected] "100" |
81 | [email protected] ")" | 84 | [email protected] ")" |
85 | [email protected] ")" | ||
82 | [email protected] "]" | 86 | [email protected] "]" |
83 | [email protected] "\n" | 87 | [email protected] "\n" |
84 | [email protected] | 88 | [email protected] |
85 | [email protected] "#" | 89 | [email protected] "#" |
86 | [email protected] "!" | 90 | [email protected] "!" |
87 | [email protected] "[" | 91 | [email protected] "[" |
88 | [email protected] | 92 | [email protected] |
89 | [email protected] | 93 | [email protected] |
90 | [email protected] | 94 | [email protected] |
91 | [email protected] "attr" | 95 | [email protected] |
92 | [email protected] | 96 | [email protected] "attr" |
93 | [email protected] "(" | 97 | [email protected] |
94 | [email protected] "100" | 98 | [email protected] "(" |
95 | [email protected] ")" | 99 | [email protected] "100" |
100 | [email protected] ")" | ||
96 | [email protected] "]" | 101 | [email protected] "]" |
97 | [email protected] "\n" | 102 | [email protected] "\n" |
98 | [email protected] | 103 | [email protected] |
99 | [email protected] "#" | 104 | [email protected] "#" |
100 | [email protected] "!" | 105 | [email protected] "!" |
101 | [email protected] "[" | 106 | [email protected] "[" |
102 | [email protected] | 107 | [email protected] |
103 | [email protected] | 108 | [email protected] |
104 | [email protected] | 109 | [email protected] |
105 | [email protected] "attr" | 110 | [email protected] |
106 | [email protected] | 111 | [email protected] "attr" |
107 | [email protected] "(" | 112 | [email protected] |
108 | [email protected] "enabled" | 113 | [email protected] "(" |
109 | [email protected] " " | 114 | [email protected] "enabled" |
110 | [email protected] "=" | 115 | [email protected] " " |
111 | [email protected] " " | 116 | [email protected] "=" |
112 | [email protected] "true" | 117 | [email protected] " " |
113 | [email protected] ")" | 118 | [email protected] "true" |
119 | [email protected] ")" | ||
114 | [email protected] "]" | 120 | [email protected] "]" |
115 | [email protected] "\n" | 121 | [email protected] "\n" |
116 | [email protected] | 122 | [email protected] |
117 | [email protected] "#" | 123 | [email protected] "#" |
118 | [email protected] "!" | 124 | [email protected] "!" |
119 | [email protected] "[" | 125 | [email protected] "[" |
120 | [email protected] | 126 | [email protected] |
121 | [email protected] | 127 | [email protected] |
122 | [email protected] | 128 | [email protected] |
123 | [email protected] "enabled" | 129 | [email protected] |
124 | [email protected] | 130 | [email protected] "enabled" |
125 | [email protected] "(" | 131 | [email protected] |
126 | [email protected] "true" | 132 | [email protected] "(" |
127 | [email protected] ")" | 133 | [email protected] "true" |
134 | [email protected] ")" | ||
128 | [email protected] "]" | 135 | [email protected] "]" |
129 | [email protected] "\n" | 136 | [email protected] "\n" |
130 | [email protected] | 137 | [email protected] |
131 | [email protected] "#" | 138 | [email protected] "#" |
132 | [email protected] "!" | 139 | [email protected] "!" |
133 | [email protected] "[" | 140 | [email protected] "[" |
134 | [email protected] | 141 | [email protected] |
135 | [email protected] | 142 | [email protected] |
136 | [email protected] | 143 | [email protected] |
137 | [email protected] "attr" | 144 | [email protected] |
138 | [email protected] | 145 | [email protected] "attr" |
139 | [email protected] "(" | 146 | [email protected] |
140 | [email protected] "\"hello\"" | 147 | [email protected] "(" |
141 | [email protected] ")" | 148 | [email protected] "\"hello\"" |
149 | [email protected] ")" | ||
142 | [email protected] "]" | 150 | [email protected] "]" |
143 | [email protected] "\n" | 151 | [email protected] "\n" |
144 | [email protected] | 152 | [email protected] |
145 | [email protected] "#" | 153 | [email protected] "#" |
146 | [email protected] "!" | 154 | [email protected] "!" |
147 | [email protected] "[" | 155 | [email protected] "[" |
148 | [email protected] | 156 | [email protected] |
149 | [email protected] | 157 | [email protected] |
150 | [email protected] | 158 | [email protected] |
151 | [email protected] "repr" | 159 | [email protected] |
152 | [email protected] | 160 | [email protected] "repr" |
153 | [email protected] "(" | 161 | [email protected] |
154 | [email protected] "C" | 162 | [email protected] "(" |
155 | [email protected] "," | 163 | [email protected] "C" |
156 | [email protected] " " | 164 | [email protected] "," |
157 | [email protected] "align" | 165 | [email protected] " " |
158 | [email protected] " " | 166 | [email protected] "align" |
159 | [email protected] "=" | 167 | [email protected] " " |
160 | [email protected] " " | 168 | [email protected] "=" |
161 | [email protected] "4" | 169 | [email protected] " " |
162 | [email protected] ")" | 170 | [email protected] "4" |
171 | [email protected] ")" | ||
163 | [email protected] "]" | 172 | [email protected] "]" |
164 | [email protected] "\n" | 173 | [email protected] "\n" |
165 | [email protected] | 174 | [email protected] |
166 | [email protected] "#" | 175 | [email protected] "#" |
167 | [email protected] "!" | 176 | [email protected] "!" |
168 | [email protected] "[" | 177 | [email protected] "[" |
169 | [email protected] | 178 | [email protected] |
170 | [email protected] | 179 | [email protected] |
171 | [email protected] | 180 | [email protected] |
172 | [email protected] "repr" | 181 | [email protected] |
173 | [email protected] | 182 | [email protected] "repr" |
174 | [email protected] "(" | 183 | [email protected] |
175 | [email protected] "C" | 184 | [email protected] "(" |
176 | [email protected] "," | 185 | [email protected] "C" |
177 | [email protected] " " | 186 | [email protected] "," |
178 | [email protected] "align" | 187 | [email protected] " " |
179 | [email protected] | 188 | [email protected] "align" |
180 | [email protected] "(" | 189 | [email protected] |
181 | [email protected] "4" | 190 | [email protected] "(" |
182 | [email protected] ")" | 191 | [email protected] "4" |
183 | [email protected] ")" | 192 | [email protected] ")" |
193 | [email protected] ")" | ||
184 | [email protected] "]" | 194 | [email protected] "]" |
diff --git a/crates/syntax/test_data/parser/ok/0008_mod_item.rast b/crates/syntax/test_data/parser/ok/0008_mod_item.rast index b2c1d791f..8b1e0a52d 100644 --- a/crates/syntax/test_data/parser/ok/0008_mod_item.rast +++ b/crates/syntax/test_data/parser/ok/0008_mod_item.rast | |||
@@ -65,10 +65,11 @@ [email protected] | |||
65 | [email protected] "#" | 65 | [email protected] "#" |
66 | [email protected] "!" | 66 | [email protected] "!" |
67 | [email protected] "[" | 67 | [email protected] "[" |
68 | [email protected] | 68 | [email protected] |
69 | [email protected] | 69 | [email protected] |
70 | [email protected] | 70 | [email protected] |
71 | [email protected] "attr" | 71 | [email protected] |
72 | [email protected] "attr" | ||
72 | [email protected] "]" | 73 | [email protected] "]" |
73 | [email protected] "\n " | 74 | [email protected] "\n " |
74 | [email protected] | 75 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast index 478fdba75..ff5877a7b 100644 --- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast +++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast | |||
@@ -3,23 +3,25 @@ [email protected] | |||
3 | [email protected] | 3 | [email protected] |
4 | [email protected] "#" | 4 | [email protected] "#" |
5 | [email protected] "[" | 5 | [email protected] "[" |
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "cfg" | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] "cfg" |
11 | [email protected] "(" | 11 | [email protected] |
12 | [email protected] "test" | 12 | [email protected] "(" |
13 | [email protected] ")" | 13 | [email protected] "test" |
14 | [email protected] ")" | ||
14 | [email protected] "]" | 15 | [email protected] "]" |
15 | [email protected] "\n" | 16 | [email protected] "\n" |
16 | [email protected] | 17 | [email protected] |
17 | [email protected] "#" | 18 | [email protected] "#" |
18 | [email protected] "[" | 19 | [email protected] "[" |
19 | [email protected] | 20 | [email protected] |
20 | [email protected] | 21 | [email protected] |
21 | [email protected] | 22 | [email protected] |
22 | [email protected] "ignore" | 23 | [email protected] |
24 | [email protected] "ignore" | ||
23 | [email protected] "]" | 25 | [email protected] "]" |
24 | [email protected] "\n" | 26 | [email protected] "\n" |
25 | [email protected] "fn" | 27 | [email protected] "fn" |
@@ -38,15 +40,16 @@ [email protected] | |||
38 | [email protected] | 40 | [email protected] |
39 | [email protected] "#" | 41 | [email protected] "#" |
40 | [email protected] "[" | 42 | [email protected] "[" |
41 | [email protected] | 43 | [email protected] |
42 | [email protected] | 44 | [email protected] |
43 | [email protected] | 45 | [email protected] |
44 | [email protected] "path" | 46 | [email protected] |
45 | [email protected] " " | 47 | [email protected] "path" |
46 | [email protected] "=" | 48 | [email protected] " " |
47 | [email protected] " " | 49 | [email protected] "=" |
48 | [email protected] | 50 | [email protected] " " |
49 | [email protected] "\"a.rs\"" | 51 | [email protected] |
52 | [email protected] "\"a.rs\"" | ||
50 | [email protected] "]" | 53 | [email protected] "]" |
51 | [email protected] "\n" | 54 | [email protected] "\n" |
52 | [email protected] "mod" | 55 | [email protected] "mod" |
diff --git a/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast b/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast index a3e091ad3..94791f771 100644 --- a/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast +++ b/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast | |||
@@ -3,15 +3,16 @@ [email protected] | |||
3 | [email protected] | 3 | [email protected] |
4 | [email protected] "#" | 4 | [email protected] "#" |
5 | [email protected] "[" | 5 | [email protected] "[" |
6 | [email protected] | 6 | [email protected] |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] "foo" | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] "foo" |
11 | [email protected] "(" | 11 | [email protected] |
12 | [email protected] "a" | 12 | [email protected] "(" |
13 | [email protected] "," | 13 | [email protected] "a" |
14 | [email protected] ")" | 14 | [email protected] "," |
15 | [email protected] ")" | ||
15 | [email protected] "]" | 16 | [email protected] "]" |
16 | [email protected] "\n" | 17 | [email protected] "\n" |
17 | [email protected] "fn" | 18 | [email protected] "fn" |
diff --git a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast index 46b192dc1..20675dbf5 100644 --- a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast +++ b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast | |||
@@ -11,71 +11,76 @@ [email protected] | |||
11 | [email protected] "#" | 11 | [email protected] "#" |
12 | [email protected] "!" | 12 | [email protected] "!" |
13 | [email protected] "[" | 13 | [email protected] "[" |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] "allow" | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] "allow" |
19 | [email protected] "(" | 19 | [email protected] |
20 | [email protected] "non_camel_case_types" | 20 | [email protected] "(" |
21 | [email protected] ")" | 21 | [email protected] "non_camel_case_types" |
22 | [email protected] ")" | ||
22 | [email protected] "]" | 23 | [email protected] "]" |
23 | [email protected] "\n" | 24 | [email protected] "\n" |
24 | [email protected] | 25 | [email protected] |
25 | [email protected] "#" | 26 | [email protected] "#" |
26 | [email protected] "!" | 27 | [email protected] "!" |
27 | [email protected] "[" | 28 | [email protected] "[" |
28 | [email protected] | 29 | [email protected] |
29 | [email protected] | 30 | [email protected] |
30 | [email protected] | 31 | [email protected] |
31 | [email protected] "allow" | 32 | [email protected] |
32 | [email protected] | 33 | [email protected] "allow" |
33 | [email protected] "(" | 34 | [email protected] |
34 | [email protected] "dead_code" | 35 | [email protected] "(" |
35 | [email protected] ")" | 36 | [email protected] "dead_code" |
37 | [email protected] ")" | ||
36 | [email protected] "]" | 38 | [email protected] "]" |
37 | [email protected] "\n" | 39 | [email protected] "\n" |
38 | [email protected] | 40 | [email protected] |
39 | [email protected] "#" | 41 | [email protected] "#" |
40 | [email protected] "!" | 42 | [email protected] "!" |
41 | [email protected] "[" | 43 | [email protected] "[" |
42 | [email protected] | 44 | [email protected] |
43 | [email protected] | 45 | [email protected] |
44 | [email protected] | 46 | [email protected] |
45 | [email protected] "allow" | 47 | [email protected] |
46 | [email protected] | 48 | [email protected] "allow" |
47 | [email protected] "(" | 49 | [email protected] |
48 | [email protected] "unreachable_code" | 50 | [email protected] "(" |
49 | [email protected] ")" | 51 | [email protected] "unreachable_code" |
52 | [email protected] ")" | ||
50 | [email protected] "]" | 53 | [email protected] "]" |
51 | [email protected] "\n" | 54 | [email protected] "\n" |
52 | [email protected] | 55 | [email protected] |
53 | [email protected] "#" | 56 | [email protected] "#" |
54 | [email protected] "!" | 57 | [email protected] "!" |
55 | [email protected] "[" | 58 | [email protected] "[" |
56 | [email protected] | 59 | [email protected] |
57 | [email protected] | 60 | [email protected] |
58 | [email protected] | 61 | [email protected] |
59 | [email protected] "allow" | 62 | [email protected] |
60 | [email protected] | 63 | [email protected] "allow" |
61 | [email protected] "(" | 64 | [email protected] |
62 | [email protected] "unused_parens" | 65 | [email protected] "(" |
63 | [email protected] ")" | 66 | [email protected] "unused_parens" |
67 | [email protected] ")" | ||
64 | [email protected] "]" | 68 | [email protected] "]" |
65 | [email protected] "\n\n" | 69 | [email protected] "\n\n" |
66 | [email protected] | 70 | [email protected] |
67 | [email protected] "#" | 71 | [email protected] "#" |
68 | [email protected] "!" | 72 | [email protected] "!" |
69 | [email protected] "[" | 73 | [email protected] "[" |
70 | [email protected] | 74 | [email protected] |
71 | [email protected] | 75 | [email protected] |
72 | [email protected] | 76 | [email protected] |
73 | [email protected] "recursion_limit" | 77 | [email protected] |
74 | [email protected] " " | 78 | [email protected] "recursion_limit" |
75 | [email protected] "=" | 79 | [email protected] " " |
76 | [email protected] " " | 80 | [email protected] "=" |
77 | [email protected] | 81 | [email protected] " " |
78 | [email protected] "\"128\"" | 82 | [email protected] |
83 | [email protected] "\"128\"" | ||
79 | [email protected] "]" | 84 | [email protected] "]" |
80 | [email protected] "\n\n" | 85 | [email protected] "\n\n" |
81 | [email protected] | 86 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0044_let_attrs.rast b/crates/syntax/test_data/parser/ok/0044_let_attrs.rast index af44a4dbe..d0e7a1dbe 100644 --- a/crates/syntax/test_data/parser/ok/0044_let_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0044_let_attrs.rast | |||
@@ -17,18 +17,19 @@ [email protected] | |||
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "#" | 18 | [email protected] "#" |
19 | [email protected] "[" | 19 | [email protected] "[" |
20 | [email protected] | 20 | [email protected] |
21 | [email protected] | 21 | [email protected] |
22 | [email protected] | 22 | [email protected] |
23 | [email protected] "cfg" | 23 | [email protected] |
24 | [email protected] | 24 | [email protected] "cfg" |
25 | [email protected] "(" | 25 | [email protected] |
26 | [email protected] "feature" | 26 | [email protected] "(" |
27 | [email protected] " " | 27 | [email protected] "feature" |
28 | [email protected] "=" | 28 | [email protected] " " |
29 | [email protected] " " | 29 | [email protected] "=" |
30 | [email protected] "\"backtrace\"" | 30 | [email protected] " " |
31 | [email protected] ")" | 31 | [email protected] "\"backtrace\"" |
32 | [email protected] ")" | ||
32 | [email protected] "]" | 33 | [email protected] "]" |
33 | [email protected] "\n " | 34 | [email protected] "\n " |
34 | [email protected] "let" | 35 | [email protected] "let" |
diff --git a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast index 5e50b4e0b..7fbd635d0 100644 --- a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast | |||
@@ -15,14 +15,15 @@ [email protected] | |||
15 | [email protected] "#" | 15 | [email protected] "#" |
16 | [email protected] "!" | 16 | [email protected] "!" |
17 | [email protected] "[" | 17 | [email protected] "[" |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] | 20 | [email protected] |
21 | [email protected] "doc" | 21 | [email protected] |
22 | [email protected] | 22 | [email protected] "doc" |
23 | [email protected] "(" | 23 | [email protected] |
24 | [email protected] "\"Inner attributes all ..." | 24 | [email protected] "(" |
25 | [email protected] ")" | 25 | [email protected] "\"Inner attributes all ..." |
26 | [email protected] ")" | ||
26 | [email protected] "]" | 27 | [email protected] "]" |
27 | [email protected] "\n " | 28 | [email protected] "\n " |
28 | [email protected] "//! As are ModuleDoc ..." | 29 | [email protected] "//! As are ModuleDoc ..." |
@@ -35,28 +36,30 @@ [email protected] | |||
35 | [email protected] "#" | 36 | [email protected] "#" |
36 | [email protected] "!" | 37 | [email protected] "!" |
37 | [email protected] "[" | 38 | [email protected] "[" |
38 | [email protected] | 39 | [email protected] |
39 | [email protected] | 40 | [email protected] |
40 | [email protected] | 41 | [email protected] |
41 | [email protected] "doc" | 42 | [email protected] |
42 | [email protected] | 43 | [email protected] "doc" |
43 | [email protected] "(" | 44 | [email protected] |
44 | [email protected] "\"Inner attributes are ..." | 45 | [email protected] "(" |
45 | [email protected] ")" | 46 | [email protected] "\"Inner attributes are ..." |
47 | [email protected] ")" | ||
46 | [email protected] "]" | 48 | [email protected] "]" |
47 | [email protected] "\n " | 49 | [email protected] "\n " |
48 | [email protected] | 50 | [email protected] |
49 | [email protected] "#" | 51 | [email protected] "#" |
50 | [email protected] "!" | 52 | [email protected] "!" |
51 | [email protected] "[" | 53 | [email protected] "[" |
52 | [email protected] | 54 | [email protected] |
53 | [email protected] | 55 | [email protected] |
54 | [email protected] | 56 | [email protected] |
55 | [email protected] "doc" | 57 | [email protected] |
56 | [email protected] | 58 | [email protected] "doc" |
57 | [email protected] "(" | 59 | [email protected] |
58 | [email protected] "\"Being validated is n ..." | 60 | [email protected] "(" |
59 | [email protected] ")" | 61 | [email protected] "\"Being validated is n ..." |
62 | [email protected] ")" | ||
60 | [email protected] "]" | 63 | [email protected] "]" |
61 | [email protected] "\n " | 64 | [email protected] "\n " |
62 | [email protected] "//! As are ModuleDoc ..." | 65 | [email protected] "//! As are ModuleDoc ..." |
@@ -71,14 +74,15 @@ [email protected] | |||
71 | [email protected] "#" | 74 | [email protected] "#" |
72 | [email protected] "!" | 75 | [email protected] "!" |
73 | [email protected] "[" | 76 | [email protected] "[" |
74 | [email protected] | 77 | [email protected] |
75 | [email protected] | 78 | [email protected] |
76 | [email protected] | 79 | [email protected] |
77 | [email protected] "doc" | 80 | [email protected] |
78 | [email protected] | 81 | [email protected] "doc" |
79 | [email protected] "(" | 82 | [email protected] |
80 | [email protected] "\"Inner attributes are ..." | 83 | [email protected] "(" |
81 | [email protected] ")" | 84 | [email protected] "\"Inner attributes are ..." |
85 | [email protected] ")" | ||
82 | [email protected] "]" | 86 | [email protected] "]" |
83 | [email protected] "\n " | 87 | [email protected] "\n " |
84 | [email protected] "//! As are ModuleDoc ..." | 88 | [email protected] "//! As are ModuleDoc ..." |
@@ -111,14 +115,15 @@ [email protected] | |||
111 | [email protected] | 115 | [email protected] |
112 | [email protected] "#" | 116 | [email protected] "#" |
113 | [email protected] "[" | 117 | [email protected] "[" |
114 | [email protected] | 118 | [email protected] |
115 | [email protected] | 119 | [email protected] |
116 | [email protected] | 120 | [email protected] |
117 | [email protected] "doc" | 121 | [email protected] |
118 | [email protected] | 122 | [email protected] "doc" |
119 | [email protected] "(" | 123 | [email protected] |
120 | [email protected] "\"Outer attributes are ..." | 124 | [email protected] "(" |
121 | [email protected] ")" | 125 | [email protected] "\"Outer attributes are ..." |
126 | [email protected] ")" | ||
122 | [email protected] "]" | 127 | [email protected] "]" |
123 | [email protected] " " | 128 | [email protected] " " |
124 | [email protected] "{" | 129 | [email protected] "{" |
@@ -200,14 +205,15 @@ [email protected] | |||
200 | [email protected] "#" | 205 | [email protected] "#" |
201 | [email protected] "!" | 206 | [email protected] "!" |
202 | [email protected] "[" | 207 | [email protected] "[" |
203 | [email protected] | 208 | [email protected] |
204 | [email protected] | 209 | [email protected] |
205 | [email protected] | 210 | [email protected] |
206 | [email protected] "allow" | 211 | [email protected] |
207 | [email protected] | 212 | [email protected] "allow" |
208 | [email protected] "(" | 213 | [email protected] |
209 | [email protected] "unused_variables" | 214 | [email protected] "(" |
210 | [email protected] ")" | 215 | [email protected] "unused_variables" |
216 | [email protected] ")" | ||
211 | [email protected] "]" | 217 | [email protected] "]" |
212 | [email protected] " " | 218 | [email protected] " " |
213 | [email protected] "// this is `inner_at ..." | 219 | [email protected] "// this is `inner_at ..." |
diff --git a/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast b/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast index 37594769a..854ff9d56 100644 --- a/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast +++ b/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast | |||
@@ -14,14 +14,15 @@ [email protected] | |||
14 | [email protected] "#" | 14 | [email protected] "#" |
15 | [email protected] "!" | 15 | [email protected] "!" |
16 | [email protected] "[" | 16 | [email protected] "[" |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] "doc" | 20 | [email protected] |
21 | [email protected] | 21 | [email protected] "doc" |
22 | [email protected] "(" | 22 | [email protected] |
23 | [email protected] "\"This is also a doc c ..." | 23 | [email protected] "(" |
24 | [email protected] ")" | 24 | [email protected] "\"This is also a doc c ..." |
25 | [email protected] ")" | ||
25 | [email protected] "]" | 26 | [email protected] "]" |
26 | [email protected] "\n" | 27 | [email protected] "\n" |
27 | [email protected] "}" | 28 | [email protected] "}" |
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast index 88470c41c..f935a0df5 100644 --- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast | |||
@@ -10,19 +10,21 @@ [email protected] | |||
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "#" | 11 | [email protected] "#" |
12 | [email protected] "[" | 12 | [email protected] "[" |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "attr1" | 16 | [email protected] |
17 | [email protected] "attr1" | ||
17 | [email protected] "]" | 18 | [email protected] "]" |
18 | [email protected] " " | 19 | [email protected] " " |
19 | [email protected] | 20 | [email protected] |
20 | [email protected] "#" | 21 | [email protected] "#" |
21 | [email protected] "[" | 22 | [email protected] "[" |
22 | [email protected] | 23 | [email protected] |
23 | [email protected] | 24 | [email protected] |
24 | [email protected] | 25 | [email protected] |
25 | [email protected] "attr2" | 26 | [email protected] |
27 | [email protected] "attr2" | ||
26 | [email protected] "]" | 28 | [email protected] "]" |
27 | [email protected] " " | 29 | [email protected] " " |
28 | [email protected] | 30 | [email protected] |
@@ -52,10 +54,11 @@ [email protected] | |||
52 | [email protected] | 54 | [email protected] |
53 | [email protected] "#" | 55 | [email protected] "#" |
54 | [email protected] "[" | 56 | [email protected] "[" |
55 | [email protected] | 57 | [email protected] |
56 | [email protected] | 58 | [email protected] |
57 | [email protected] | 59 | [email protected] |
58 | [email protected] "attr1" | 60 | [email protected] |
61 | [email protected] "attr1" | ||
59 | [email protected] "]" | 62 | [email protected] "]" |
60 | [email protected] " " | 63 | [email protected] " " |
61 | [email protected] | 64 | [email protected] |
@@ -111,10 +114,11 @@ [email protected] | |||
111 | [email protected] | 114 | [email protected] |
112 | [email protected] "#" | 115 | [email protected] "#" |
113 | [email protected] "[" | 116 | [email protected] "[" |
114 | [email protected] | 117 | [email protected] |
115 | [email protected] | 118 | [email protected] |
116 | [email protected] | 119 | [email protected] |
117 | [email protected] "attr" | 120 | [email protected] |
121 | [email protected] "attr" | ||
118 | [email protected] "]" | 122 | [email protected] "]" |
119 | [email protected] " " | 123 | [email protected] " " |
120 | [email protected] "..." | 124 | [email protected] "..." |
@@ -157,10 +161,11 @@ [email protected] | |||
157 | [email protected] | 161 | [email protected] |
158 | [email protected] "#" | 162 | [email protected] "#" |
159 | [email protected] "[" | 163 | [email protected] "[" |
160 | [email protected] | 164 | [email protected] |
161 | [email protected] | 165 | [email protected] |
162 | [email protected] | 166 | [email protected] |
163 | [email protected] "attr" | 167 | [email protected] |
168 | [email protected] "attr" | ||
164 | [email protected] "]" | 169 | [email protected] "]" |
165 | [email protected] " " | 170 | [email protected] " " |
166 | [email protected] | 171 | [email protected] |
@@ -207,10 +212,11 @@ [email protected] | |||
207 | [email protected] | 212 | [email protected] |
208 | [email protected] "#" | 213 | [email protected] "#" |
209 | [email protected] "[" | 214 | [email protected] "[" |
210 | [email protected] | 215 | [email protected] |
211 | [email protected] | 216 | [email protected] |
212 | [email protected] | 217 | [email protected] |
213 | [email protected] "attr" | 218 | [email protected] |
219 | [email protected] "attr" | ||
214 | [email protected] "]" | 220 | [email protected] "]" |
215 | [email protected] " " | 221 | [email protected] " " |
216 | [email protected] | 222 | [email protected] |
@@ -229,10 +235,11 @@ [email protected] | |||
229 | [email protected] "#" | 235 | [email protected] "#" |
230 | [email protected] " " | 236 | [email protected] " " |
231 | [email protected] "[" | 237 | [email protected] "[" |
232 | [email protected] | 238 | [email protected] |
233 | [email protected] | 239 | [email protected] |
234 | [email protected] | 240 | [email protected] |
235 | [email protected] "attr" | 241 | [email protected] |
242 | [email protected] "attr" | ||
236 | [email protected] "]" | 243 | [email protected] "]" |
237 | [email protected] " " | 244 | [email protected] " " |
238 | [email protected] | 245 | [email protected] |
@@ -275,10 +282,11 @@ [email protected] | |||
275 | [email protected] | 282 | [email protected] |
276 | [email protected] "#" | 283 | [email protected] "#" |
277 | [email protected] "[" | 284 | [email protected] "[" |
278 | [email protected] | 285 | [email protected] |
279 | [email protected] | 286 | [email protected] |
280 | [email protected] | 287 | [email protected] |
281 | [email protected] "must_use" | 288 | [email protected] |
289 | [email protected] "must_use" | ||
282 | [email protected] "]" | 290 | [email protected] "]" |
283 | [email protected] " " | 291 | [email protected] " " |
284 | [email protected] | 292 | [email protected] |
@@ -300,10 +308,11 @@ [email protected] | |||
300 | [email protected] | 308 | [email protected] |
301 | [email protected] "#" | 309 | [email protected] "#" |
302 | [email protected] "[" | 310 | [email protected] "[" |
303 | [email protected] | 311 | [email protected] |
304 | [email protected] | 312 | [email protected] |
305 | [email protected] | 313 | [email protected] |
306 | [email protected] "attr" | 314 | [email protected] |
315 | [email protected] "attr" | ||
307 | [email protected] "]" | 316 | [email protected] "]" |
308 | [email protected] " " | 317 | [email protected] " " |
309 | [email protected] | 318 | [email protected] |
@@ -325,10 +334,11 @@ [email protected] | |||
325 | [email protected] | 334 | [email protected] |
326 | [email protected] "#" | 335 | [email protected] "#" |
327 | [email protected] "[" | 336 | [email protected] "[" |
328 | [email protected] | 337 | [email protected] |
329 | [email protected] | 338 | [email protected] |
330 | [email protected] | 339 | [email protected] |
331 | [email protected] "attr" | 340 | [email protected] |
341 | [email protected] "attr" | ||
332 | [email protected] "]" | 342 | [email protected] "]" |
333 | [email protected] " " | 343 | [email protected] " " |
334 | [email protected] "&" | 344 | [email protected] "&" |
@@ -357,10 +367,11 @@ [email protected] | |||
357 | [email protected] | 367 | [email protected] |
358 | [email protected] "#" | 368 | [email protected] "#" |
359 | [email protected] "[" | 369 | [email protected] "[" |
360 | [email protected] | 370 | [email protected] |
361 | [email protected] | 371 | [email protected] |
362 | [email protected] | 372 | [email protected] |
363 | [email protected] "attr" | 373 | [email protected] |
374 | [email protected] "attr" | ||
364 | [email protected] "]" | 375 | [email protected] "]" |
365 | [email protected] " " | 376 | [email protected] " " |
366 | [email protected] "&" | 377 | [email protected] "&" |
@@ -391,10 +402,11 @@ [email protected] | |||
391 | [email protected] | 402 | [email protected] |
392 | [email protected] "#" | 403 | [email protected] "#" |
393 | [email protected] "[" | 404 | [email protected] "[" |
394 | [email protected] | 405 | [email protected] |
395 | [email protected] | 406 | [email protected] |
396 | [email protected] | 407 | [email protected] |
397 | [email protected] "attr" | 408 | [email protected] |
409 | [email protected] "attr" | ||
398 | [email protected] "]" | 410 | [email protected] "]" |
399 | [email protected] " " | 411 | [email protected] " " |
400 | [email protected] "&" | 412 | [email protected] "&" |
@@ -426,10 +438,11 @@ [email protected] | |||
426 | [email protected] | 438 | [email protected] |
427 | [email protected] "#" | 439 | [email protected] "#" |
428 | [email protected] "[" | 440 | [email protected] "[" |
429 | [email protected] | 441 | [email protected] |
430 | [email protected] | 442 | [email protected] |
431 | [email protected] | 443 | [email protected] |
432 | [email protected] "attr" | 444 | [email protected] |
445 | [email protected] "attr" | ||
433 | [email protected] "]" | 446 | [email protected] "]" |
434 | [email protected] " " | 447 | [email protected] " " |
435 | [email protected] "&" | 448 | [email protected] "&" |
@@ -457,10 +470,11 @@ [email protected] | |||
457 | [email protected] | 470 | [email protected] |
458 | [email protected] "#" | 471 | [email protected] "#" |
459 | [email protected] "[" | 472 | [email protected] "[" |
460 | [email protected] | 473 | [email protected] |
461 | [email protected] | 474 | [email protected] |
462 | [email protected] | 475 | [email protected] |
463 | [email protected] "attr" | 476 | [email protected] |
477 | [email protected] "attr" | ||
464 | [email protected] "]" | 478 | [email protected] "]" |
465 | [email protected] " " | 479 | [email protected] " " |
466 | [email protected] | 480 | [email protected] |
@@ -489,10 +503,11 @@ [email protected] | |||
489 | [email protected] | 503 | [email protected] |
490 | [email protected] "#" | 504 | [email protected] "#" |
491 | [email protected] "[" | 505 | [email protected] "[" |
492 | [email protected] | 506 | [email protected] |
493 | [email protected] | 507 | [email protected] |
494 | [email protected] | 508 | [email protected] |
495 | [email protected] "attr" | 509 | [email protected] |
510 | [email protected] "attr" | ||
496 | [email protected] "]" | 511 | [email protected] "]" |
497 | [email protected] " " | 512 | [email protected] " " |
498 | [email protected] | 513 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast b/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast index 87d8ebcba..97416f16a 100644 --- a/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast +++ b/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast | |||
@@ -5,10 +5,11 @@ [email protected] | |||
5 | [email protected] | 5 | [email protected] |
6 | [email protected] "#" | 6 | [email protected] "#" |
7 | [email protected] "[" | 7 | [email protected] "[" |
8 | [email protected] | 8 | [email protected] |
9 | [email protected] | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "macro_export" | 11 | [email protected] |
12 | [email protected] "macro_export" | ||
12 | [email protected] "]" | 13 | [email protected] "]" |
13 | [email protected] "\n" | 14 | [email protected] "\n" |
14 | [email protected] "macro_rules" | 15 | [email protected] "macro_rules" |
diff --git a/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast b/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast index 0c22c31a4..e75848f0f 100644 --- a/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast +++ b/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast | |||
@@ -55,10 +55,11 @@ [email protected] | |||
55 | [email protected] | 55 | [email protected] |
56 | [email protected] "#" | 56 | [email protected] "#" |
57 | [email protected] "[" | 57 | [email protected] "[" |
58 | [email protected] | 58 | [email protected] |
59 | [email protected] | 59 | [email protected] |
60 | [email protected] | 60 | [email protected] |
61 | [email protected] "test" | 61 | [email protected] |
62 | [email protected] "test" | ||
62 | [email protected] "]" | 63 | [email protected] "]" |
63 | [email protected] "\n" | 64 | [email protected] "\n" |
64 | [email protected] "fn" | 65 | [email protected] "fn" |
diff --git a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast index f7c094898..dcc4105c9 100644 --- a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast +++ b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast | |||
@@ -96,14 +96,15 @@ [email protected] | |||
96 | [email protected] | 96 | [email protected] |
97 | [email protected] "#" | 97 | [email protected] "#" |
98 | [email protected] "[" | 98 | [email protected] "[" |
99 | [email protected] | 99 | [email protected] |
100 | [email protected] | 100 | [email protected] |
101 | [email protected] | 101 | [email protected] |
102 | [email protected] "cfg" | 102 | [email protected] |
103 | [email protected] | 103 | [email protected] "cfg" |
104 | [email protected] "(" | 104 | [email protected] |
105 | [email protected] "never" | 105 | [email protected] "(" |
106 | [email protected] ")" | 106 | [email protected] "never" |
107 | [email protected] ")" | ||
107 | [email protected] "]" | 108 | [email protected] "]" |
108 | [email protected] " " | 109 | [email protected] " " |
109 | [email protected] | 110 | [email protected] |