rust/crates/hir/src/diagnostics.rs

243 lines
6.1 KiB
Rust
Raw Normal View History

2021-05-22 08:53:47 -05:00
//! Re-export diagnostics such that clients of `hir` don't have to depend on
//! low-level crates.
//!
//! This probably isn't the best way to do this -- ideally, diagnistics should
//! be expressed in terms of hir types themselves.
use std::any::Any;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_def::path::ModPath;
2021-06-12 11:28:19 -05:00
use hir_expand::{name::Name, HirFileId, InFile};
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
pub use crate::diagnostics_sink::{
Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
2020-07-08 12:58:45 -05:00
};
macro_rules! diagnostics {
($($diag:ident,)*) => {
pub enum AnyDiagnostic {$(
$diag(Box<$diag>),
)*}
$(
impl From<$diag> for AnyDiagnostic {
fn from(d: $diag) -> AnyDiagnostic {
AnyDiagnostic::$diag(Box::new(d))
}
}
)*
};
}
diagnostics![
BreakOutsideOfLoop,
InactiveCode,
MacroError,
MismatchedArgCount,
MissingFields,
MissingOkOrSomeInTailExpr,
MissingUnsafe,
NoSuchField,
RemoveThisSemicolon,
UnimplementedBuiltinMacro,
UnresolvedExternCrate,
UnresolvedImport,
UnresolvedMacroCall,
UnresolvedModule,
UnresolvedProcMacro,
];
#[derive(Debug)]
pub struct UnresolvedModule {
pub decl: InFile<AstPtr<ast::Module>>,
pub candidate: String,
}
#[derive(Debug)]
pub struct UnresolvedExternCrate {
pub decl: InFile<AstPtr<ast::ExternCrate>>,
}
#[derive(Debug)]
pub struct UnresolvedImport {
pub decl: InFile<AstPtr<ast::UseTree>>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedMacroCall {
pub macro_call: InFile<AstPtr<ast::MacroCall>>,
pub path: ModPath,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InactiveCode {
pub node: InFile<SyntaxNodePtr>,
pub cfg: CfgExpr,
pub opts: CfgOptions,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedProcMacro {
pub node: InFile<SyntaxNodePtr>,
/// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
/// to use instead.
pub precise_location: Option<TextRange>,
pub macro_name: Option<String>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroError {
2021-06-13 10:41:04 -05:00
pub node: InFile<SyntaxNodePtr>,
pub message: String,
}
2021-05-29 21:19:47 -05:00
#[derive(Debug)]
pub struct UnimplementedBuiltinMacro {
pub node: InFile<SyntaxNodePtr>,
2021-05-29 21:19:47 -05:00
}
#[derive(Debug)]
pub struct NoSuchField {
pub field: InFile<AstPtr<ast::RecordExprField>>,
}
#[derive(Debug)]
pub struct BreakOutsideOfLoop {
pub expr: InFile<AstPtr<ast::Expr>>,
}
#[derive(Debug)]
pub struct MissingUnsafe {
pub expr: InFile<AstPtr<ast::Expr>>,
}
2021-06-12 11:28:19 -05:00
#[derive(Debug)]
pub struct MissingFields {
pub file: HirFileId,
pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
2021-06-12 11:28:19 -05:00
pub field_list_parent_path: Option<AstPtr<ast::Path>>,
pub missed_fields: Vec<Name>,
}
// Diagnostic: replace-filter-map-next-with-find-map
//
// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
#[derive(Debug)]
pub struct ReplaceFilterMapNextWithFindMap {
pub file: HirFileId,
/// This expression is the whole method chain up to and including `.filter_map(..).next()`.
pub next_expr: AstPtr<ast::Expr>,
}
impl Diagnostic for ReplaceFilterMapNextWithFindMap {
fn code(&self) -> DiagnosticCode {
DiagnosticCode("replace-filter-map-next-with-find-map")
}
fn message(&self) -> String {
"replace filter_map(..).next() with find_map(..)".to_string()
}
fn display_source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.next_expr.clone().into() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
#[derive(Debug)]
pub struct MismatchedArgCount {
pub call_expr: InFile<AstPtr<ast::Expr>>,
2021-06-12 11:28:19 -05:00
pub expected: usize,
pub found: usize,
}
#[derive(Debug)]
pub struct RemoveThisSemicolon {
pub expr: InFile<AstPtr<ast::Expr>>,
2021-06-12 11:28:19 -05:00
}
#[derive(Debug)]
pub struct MissingOkOrSomeInTailExpr {
pub expr: InFile<AstPtr<ast::Expr>>,
2021-06-12 11:28:19 -05:00
// `Some` or `Ok` depending on whether the return type is Result or Option
pub required: String,
}
// Diagnostic: missing-match-arm
//
// This diagnostic is triggered if `match` block is missing one or more match arms.
#[derive(Debug)]
pub struct MissingMatchArms {
pub file: HirFileId,
pub match_expr: AstPtr<ast::Expr>,
pub arms: AstPtr<ast::MatchArmList>,
}
impl Diagnostic for MissingMatchArms {
fn code(&self) -> DiagnosticCode {
DiagnosticCode("missing-match-arm")
}
fn message(&self) -> String {
String::from("Missing match arm")
}
fn display_source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.match_expr.clone().into() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
#[derive(Debug)]
pub struct InternalBailedOut {
pub file: HirFileId,
pub pat_syntax_ptr: SyntaxNodePtr,
}
impl Diagnostic for InternalBailedOut {
fn code(&self) -> DiagnosticCode {
DiagnosticCode("internal:match-check-bailed-out")
}
fn message(&self) -> String {
format!("Internal: match check bailed out")
}
fn display_source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
pub use hir_ty::diagnostics::IncorrectCase;
impl Diagnostic for IncorrectCase {
fn code(&self) -> DiagnosticCode {
DiagnosticCode("incorrect-ident-case")
}
fn message(&self) -> String {
format!(
"{} `{}` should have {} name, e.g. `{}`",
self.ident_type,
self.ident_text,
self.expected_case.to_string(),
self.suggested_text
)
}
fn display_source(&self) -> InFile<SyntaxNodePtr> {
InFile::new(self.file, self.ident.clone().into())
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
fn is_experimental(&self) -> bool {
true
}
}