internal: document diagnostics crate

This commit is contained in:
Aleksey Kladov 2021-06-14 19:32:39 +03:00
parent 94f7b63522
commit 4768e5fb23
20 changed files with 85 additions and 63 deletions

View File

@ -3,7 +3,7 @@ use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: break-outside-of-loop
//
// This diagnostic is triggered if the `break` keyword is used outside of a loop.
pub(super) fn break_outside_of_loop(
pub(crate) fn break_outside_of_loop(
ctx: &DiagnosticsContext<'_>,
d: &hir::BreakOutsideOfLoop,
) -> Diagnostic {

View File

@ -6,7 +6,7 @@ use crate::{Diagnostic, DiagnosticsContext, Severity};
// Diagnostic: inactive-code
//
// This diagnostic is shown for code with inactive `#[cfg]` attributes.
pub(super) fn inactive_code(
pub(crate) fn inactive_code(
ctx: &DiagnosticsContext<'_>,
d: &hir::InactiveCode,
) -> Option<Diagnostic> {

View File

@ -13,7 +13,7 @@ use crate::{
// Diagnostic: incorrect-ident-case
//
// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
Diagnostic::new(
"incorrect-ident-case",
format!(

View File

@ -3,7 +3,7 @@ use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: macro-error
//
// This diagnostic is shown for macro expansion errors.
pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
Diagnostic::new(
"macro-error",
d.message.clone(),

View File

@ -3,7 +3,7 @@ use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: mismatched-arg-count
//
// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
pub(super) fn mismatched_arg_count(
pub(crate) fn mismatched_arg_count(
ctx: &DiagnosticsContext<'_>,
d: &hir::MismatchedArgCount,
) -> Diagnostic {

View File

@ -18,7 +18,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext};
//
// let a = A { a: 10 };
// ```
pub(super) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
let mut message = String::from("Missing structure fields:\n");
for field in &d.missed_fields {
format_to!(message, "- {}\n", field);

View File

@ -5,7 +5,7 @@ use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: missing-match-arm
//
// This diagnostic is triggered if `match` block is missing one or more match arms.
pub(super) fn missing_match_arms(
pub(crate) fn missing_match_arms(
ctx: &DiagnosticsContext<'_>,
d: &hir::MissingMatchArms,
) -> Diagnostic {
@ -17,7 +17,7 @@ pub(super) fn missing_match_arms(
}
#[cfg(test)]
pub(super) mod tests {
mod tests {
use crate::tests::check_diagnostics;
fn check_diagnostics_no_bails(ra_fixture: &str) {

View File

@ -17,7 +17,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext};
// 10
// }
// ```
pub(super) fn missing_ok_or_some_in_tail_expr(
pub(crate) fn missing_ok_or_some_in_tail_expr(
ctx: &DiagnosticsContext<'_>,
d: &hir::MissingOkOrSomeInTailExpr,
) -> Diagnostic {

View File

@ -3,7 +3,7 @@ use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: missing-unsafe
//
// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic {
pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic {
Diagnostic::new(
"missing-unsafe",
"this operation is unsafe and requires an unsafe function or block",

View File

@ -11,7 +11,7 @@ use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
// Diagnostic: no-such-field
//
// This diagnostic is triggered if created structure does not have field provided in record.
pub(super) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic {
pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic {
Diagnostic::new(
"no-such-field",
"no such field",

View File

@ -8,7 +8,7 @@ use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
// Diagnostic: remove-this-semicolon
//
// This diagnostic is triggered when there's an erroneous `;` at the end of the block.
pub(super) fn remove_this_semicolon(
pub(crate) fn remove_this_semicolon(
ctx: &DiagnosticsContext<'_>,
d: &hir::RemoveThisSemicolon,
) -> Diagnostic {

View File

@ -11,7 +11,7 @@ use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity};
// 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(..)`.
pub(super) fn replace_filter_map_next_with_find_map(
pub(crate) fn replace_filter_map_next_with_find_map(
ctx: &DiagnosticsContext<'_>,
d: &hir::ReplaceFilterMapNextWithFindMap,
) -> Diagnostic {

View File

@ -3,7 +3,7 @@ use crate::{Diagnostic, DiagnosticsContext, Severity};
// Diagnostic: unimplemented-builtin-macro
//
// This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer
pub(super) fn unimplemented_builtin_macro(
pub(crate) fn unimplemented_builtin_macro(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnimplementedBuiltinMacro,
) -> Diagnostic {

View File

@ -23,7 +23,7 @@ pub(crate) struct UnlinkedFile {
//
// This diagnostic is shown for files that are not included in any crate, or files that are part of
// crates rust-analyzer failed to discover. The file will not have IDE features available.
pub(super) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic {
pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic {
// Limit diagnostic to the first few characters in the file. This matches how VS Code
// renders it with the full span, but on other editors, and is less invasive.
let range = ctx.sema.db.parse(d.file).syntax_node().text_range();

View File

@ -3,7 +3,7 @@ use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: unresolved-extern-crate
//
// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
pub(super) fn unresolved_extern_crate(
pub(crate) fn unresolved_extern_crate(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedExternCrate,
) -> Diagnostic {

View File

@ -4,7 +4,7 @@ use crate::{Diagnostic, DiagnosticsContext};
//
// This diagnostic is triggered if rust-analyzer is unable to resolve a path in
// a `use` declaration.
pub(super) fn unresolved_import(
pub(crate) fn unresolved_import(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedImport,
) -> Diagnostic {

View File

@ -7,7 +7,7 @@ use crate::{Diagnostic, DiagnosticsContext};
//
// This diagnostic is triggered if rust-analyzer is unable to resolve the path
// to a macro in a macro invocation.
pub(super) fn unresolved_macro_call(
pub(crate) fn unresolved_macro_call(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedMacroCall,
) -> Diagnostic {

View File

@ -7,7 +7,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext};
// Diagnostic: unresolved-module
//
// This diagnostic is triggered if rust-analyzer is unable to discover referred module.
pub(super) fn unresolved_module(
pub(crate) fn unresolved_module(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedModule,
) -> Diagnostic {

View File

@ -9,7 +9,7 @@ use crate::{Diagnostic, DiagnosticsContext, Severity};
// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
pub(super) fn unresolved_proc_macro(
pub(crate) fn unresolved_proc_macro(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedProcMacro,
) -> Diagnostic {

View File

@ -1,28 +1,49 @@
//! Collects diagnostics & fixits for a single file.
//! Diagnostics rendering and fixits.
//!
//! The tricky bit here is that diagnostics are produced by hir in terms of
//! macro-expanded files, but we need to present them to the users in terms of
//! original files. So we need to map the ranges.
//! Most of the diagnostics originate from the dark depth of the compiler, and
//! are originally expressed in term of IR. When we emit the diagnostic, we are
//! usually not in the position to decide how to best "render" it in terms of
//! user-authored source code. We are especially not in the position to offer
//! fixits, as the compiler completely lacks the infrastructure to edit the
//! source code.
//!
//! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate,
//! where we "cook" them so that each diagnostic is formulated in terms of `hir`
//! types. Well, at least that's the aspiration, the "cooking" is somewhat
//! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic
//! structs from hir, and we want to render them to unified serializable
//! representation (span, level, message) here. If we can, we also provide
//! fixits. By the way, that's why we want to keep diagnostics structured
//! internally -- so that we have all the info to make fixes.
//!
//! We have one "handler" module per diagnostic code. Such a module contains
//! rendering, optional fixes and tests. It's OK if some low-level compiler
//! functionality ends up being tested via a diagnostic.
//!
//! There are also a couple of ad-hoc diagnostics implemented directly here, we
//! don't yet have a great pattern for how to do them properly.
mod break_outside_of_loop;
mod inactive_code;
mod incorrect_case;
mod macro_error;
mod mismatched_arg_count;
mod missing_fields;
mod missing_match_arms;
mod missing_ok_or_some_in_tail_expr;
mod missing_unsafe;
mod no_such_field;
mod remove_this_semicolon;
mod replace_filter_map_next_with_find_map;
mod unimplemented_builtin_macro;
mod unlinked_file;
mod unresolved_extern_crate;
mod unresolved_import;
mod unresolved_macro_call;
mod unresolved_module;
mod unresolved_proc_macro;
mod handlers {
pub(crate) mod break_outside_of_loop;
pub(crate) mod inactive_code;
pub(crate) mod incorrect_case;
pub(crate) mod macro_error;
pub(crate) mod mismatched_arg_count;
pub(crate) mod missing_fields;
pub(crate) mod missing_match_arms;
pub(crate) mod missing_ok_or_some_in_tail_expr;
pub(crate) mod missing_unsafe;
pub(crate) mod no_such_field;
pub(crate) mod remove_this_semicolon;
pub(crate) mod replace_filter_map_next_with_find_map;
pub(crate) mod unimplemented_builtin_macro;
pub(crate) mod unlinked_file;
pub(crate) mod unresolved_extern_crate;
pub(crate) mod unresolved_import;
pub(crate) mod unresolved_macro_call;
pub(crate) mod unresolved_module;
pub(crate) mod unresolved_proc_macro;
}
mod field_shorthand;
@ -41,7 +62,8 @@ use syntax::{
SyntaxNode, TextRange,
};
use text_edit::TextEdit;
use unlinked_file::UnlinkedFile;
use crate::handlers::unlinked_file::UnlinkedFile;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DiagnosticCode(pub &'static str);
@ -148,32 +170,32 @@ pub fn diagnostics(
let ctx = DiagnosticsContext { config, sema, resolve };
if module.is_none() {
let d = UnlinkedFile { file: file_id };
let d = unlinked_file::unlinked_file(&ctx, &d);
let d = handlers::unlinked_file::unlinked_file(&ctx, &d);
res.push(d)
}
for diag in diags {
#[rustfmt::skip]
let d = match diag {
AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d),
AnyDiagnostic::IncorrectCase(d) => incorrect_case::incorrect_case(&ctx, &d),
AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d),
AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d),
AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
AnyDiagnostic::MissingMatchArms(d) => missing_match_arms::missing_match_arms(&ctx, &d),
AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d),
AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d),
AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d),
AnyDiagnostic::RemoveThisSemicolon(d) => remove_this_semicolon::remove_this_semicolon(&ctx, &d),
AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d),
AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => handlers::missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d),
AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
AnyDiagnostic::RemoveThisSemicolon(d) => handlers::remove_this_semicolon::remove_this_semicolon(&ctx, &d),
AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) {
AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
Some(it) => it,
None => continue,
}