Skip to content

Commit 85d2cd3

Browse files
bors[bot]matklad
andauthored
9233: Move some hir_ty diagnostics to hir r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents 10ca6b2 + 6940cfe commit 85d2cd3

File tree

7 files changed

+1821
-1781
lines changed

7 files changed

+1821
-1781
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 258 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,12 @@ use std::any::Any;
77

88
use cfg::{CfgExpr, CfgOptions, DnfExpr};
99
use hir_def::path::ModPath;
10-
use hir_expand::{HirFileId, InFile};
10+
use hir_expand::{name::Name, HirFileId, InFile};
1111
use stdx::format_to;
1212
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
1313

1414
pub use hir_ty::{
15-
diagnostics::{
16-
IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms,
17-
MissingOkOrSomeInTailExpr, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
18-
},
15+
diagnostics::IncorrectCase,
1916
diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder},
2017
};
2118

@@ -325,3 +322,259 @@ impl Diagnostic for MissingUnsafe {
325322
self
326323
}
327324
}
325+
326+
// Diagnostic: missing-structure-fields
327+
//
328+
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
329+
//
330+
// Example:
331+
//
332+
// ```rust
333+
// struct A { a: u8, b: u8 }
334+
//
335+
// let a = A { a: 10 };
336+
// ```
337+
#[derive(Debug)]
338+
pub struct MissingFields {
339+
pub file: HirFileId,
340+
pub field_list_parent: AstPtr<ast::RecordExpr>,
341+
pub field_list_parent_path: Option<AstPtr<ast::Path>>,
342+
pub missed_fields: Vec<Name>,
343+
}
344+
345+
impl Diagnostic for MissingFields {
346+
fn code(&self) -> DiagnosticCode {
347+
DiagnosticCode("missing-structure-fields")
348+
}
349+
fn message(&self) -> String {
350+
let mut buf = String::from("Missing structure fields:\n");
351+
for field in &self.missed_fields {
352+
format_to!(buf, "- {}\n", field);
353+
}
354+
buf
355+
}
356+
357+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
358+
InFile {
359+
file_id: self.file,
360+
value: self
361+
.field_list_parent_path
362+
.clone()
363+
.map(SyntaxNodePtr::from)
364+
.unwrap_or_else(|| self.field_list_parent.clone().into()),
365+
}
366+
}
367+
368+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
369+
self
370+
}
371+
}
372+
373+
// Diagnostic: missing-pat-fields
374+
//
375+
// This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure.
376+
//
377+
// Example:
378+
//
379+
// ```rust
380+
// struct A { a: u8, b: u8 }
381+
//
382+
// let a = A { a: 10, b: 20 };
383+
//
384+
// if let A { a } = a {
385+
// // ...
386+
// }
387+
// ```
388+
#[derive(Debug)]
389+
pub struct MissingPatFields {
390+
pub file: HirFileId,
391+
pub field_list_parent: AstPtr<ast::RecordPat>,
392+
pub field_list_parent_path: Option<AstPtr<ast::Path>>,
393+
pub missed_fields: Vec<Name>,
394+
}
395+
396+
impl Diagnostic for MissingPatFields {
397+
fn code(&self) -> DiagnosticCode {
398+
DiagnosticCode("missing-pat-fields")
399+
}
400+
fn message(&self) -> String {
401+
let mut buf = String::from("Missing structure fields:\n");
402+
for field in &self.missed_fields {
403+
format_to!(buf, "- {}\n", field);
404+
}
405+
buf
406+
}
407+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
408+
InFile {
409+
file_id: self.file,
410+
value: self
411+
.field_list_parent_path
412+
.clone()
413+
.map(SyntaxNodePtr::from)
414+
.unwrap_or_else(|| self.field_list_parent.clone().into()),
415+
}
416+
}
417+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
418+
self
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+
// Diagnostic: mismatched-arg-count
448+
//
449+
// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
450+
#[derive(Debug)]
451+
pub struct MismatchedArgCount {
452+
pub file: HirFileId,
453+
pub call_expr: AstPtr<ast::Expr>,
454+
pub expected: usize,
455+
pub found: usize,
456+
}
457+
458+
impl Diagnostic for MismatchedArgCount {
459+
fn code(&self) -> DiagnosticCode {
460+
DiagnosticCode("mismatched-arg-count")
461+
}
462+
fn message(&self) -> String {
463+
let s = if self.expected == 1 { "" } else { "s" };
464+
format!("Expected {} argument{}, found {}", self.expected, s, self.found)
465+
}
466+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
467+
InFile { file_id: self.file, value: self.call_expr.clone().into() }
468+
}
469+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
470+
self
471+
}
472+
fn is_experimental(&self) -> bool {
473+
true
474+
}
475+
}
476+
477+
#[derive(Debug)]
478+
pub struct RemoveThisSemicolon {
479+
pub file: HirFileId,
480+
pub expr: AstPtr<ast::Expr>,
481+
}
482+
483+
impl Diagnostic for RemoveThisSemicolon {
484+
fn code(&self) -> DiagnosticCode {
485+
DiagnosticCode("remove-this-semicolon")
486+
}
487+
488+
fn message(&self) -> String {
489+
"Remove this semicolon".to_string()
490+
}
491+
492+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
493+
InFile { file_id: self.file, value: self.expr.clone().into() }
494+
}
495+
496+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
497+
self
498+
}
499+
}
500+
501+
// Diagnostic: missing-ok-or-some-in-tail-expr
502+
//
503+
// This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`,
504+
// or if a block that should return `Option` returns a value not wrapped in `Some`.
505+
//
506+
// Example:
507+
//
508+
// ```rust
509+
// fn foo() -> Result<u8, ()> {
510+
// 10
511+
// }
512+
// ```
513+
#[derive(Debug)]
514+
pub struct MissingOkOrSomeInTailExpr {
515+
pub file: HirFileId,
516+
pub expr: AstPtr<ast::Expr>,
517+
// `Some` or `Ok` depending on whether the return type is Result or Option
518+
pub required: String,
519+
}
520+
521+
impl Diagnostic for MissingOkOrSomeInTailExpr {
522+
fn code(&self) -> DiagnosticCode {
523+
DiagnosticCode("missing-ok-or-some-in-tail-expr")
524+
}
525+
fn message(&self) -> String {
526+
format!("wrap return expression in {}", self.required)
527+
}
528+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
529+
InFile { file_id: self.file, value: self.expr.clone().into() }
530+
}
531+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
532+
self
533+
}
534+
}
535+
536+
// Diagnostic: missing-match-arm
537+
//
538+
// This diagnostic is triggered if `match` block is missing one or more match arms.
539+
#[derive(Debug)]
540+
pub struct MissingMatchArms {
541+
pub file: HirFileId,
542+
pub match_expr: AstPtr<ast::Expr>,
543+
pub arms: AstPtr<ast::MatchArmList>,
544+
}
545+
546+
impl Diagnostic for MissingMatchArms {
547+
fn code(&self) -> DiagnosticCode {
548+
DiagnosticCode("missing-match-arm")
549+
}
550+
fn message(&self) -> String {
551+
String::from("Missing match arm")
552+
}
553+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
554+
InFile { file_id: self.file, value: self.match_expr.clone().into() }
555+
}
556+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
557+
self
558+
}
559+
}
560+
561+
#[derive(Debug)]
562+
pub struct InternalBailedOut {
563+
pub file: HirFileId,
564+
pub pat_syntax_ptr: SyntaxNodePtr,
565+
}
566+
567+
impl Diagnostic for InternalBailedOut {
568+
fn code(&self) -> DiagnosticCode {
569+
DiagnosticCode("internal:match-check-bailed-out")
570+
}
571+
fn message(&self) -> String {
572+
format!("Internal: match check bailed out")
573+
}
574+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
575+
InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() }
576+
}
577+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
578+
self
579+
}
580+
}

0 commit comments

Comments
 (0)