| use std::any::Any; |
| use std::borrow::Cow; |
| |
| use rustc_data_structures::sync::DynSend; |
| use rustc_errors::{Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level}; |
| use rustc_hir::lints::{AttributeLintKind, FormatWarning}; |
| use rustc_middle::ty::TyCtxt; |
| use rustc_session::Session; |
| |
| use crate::lints; |
| |
| mod check_cfg; |
| |
| pub struct DiagAndSess<'sess> { |
| pub callback: Box< |
| dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static, |
| >, |
| pub sess: &'sess Session, |
| } |
| |
| impl<'a> Diagnostic<'a, ()> for DiagAndSess<'_> { |
| fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { |
| (self.callback)(dcx, level, self.sess) |
| } |
| } |
| |
| /// This is a diagnostic struct that will decorate a `AttributeLintKind` |
| /// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed. |
| pub struct DecorateAttrLint<'a, 'sess, 'tcx> { |
| pub sess: &'sess Session, |
| pub tcx: Option<TyCtxt<'tcx>>, |
| pub diagnostic: &'a AttributeLintKind, |
| } |
| |
| impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { |
| fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { |
| match self.diagnostic { |
| &AttributeLintKind::UnusedDuplicate { this, other, warning } => { |
| lints::UnusedDuplicate { this, other, warning }.into_diag(dcx, level) |
| } |
| AttributeLintKind::IllFormedAttributeInput { suggestions, docs, help } => { |
| lints::IllFormedAttributeInput { |
| num_suggestions: suggestions.len(), |
| suggestions: DiagArgValue::StrListSepByAnd( |
| suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), |
| ), |
| has_docs: docs.is_some(), |
| docs: docs.unwrap_or(""), |
| help: help.clone().map(|h| lints::IllFormedAttributeInputHelp { lint: h }), |
| } |
| .into_diag(dcx, level) |
| } |
| AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { |
| lints::EmptyAttributeList { |
| attr_span: *first_span, |
| attr_path: attr_path.clone(), |
| valid_without_list: *valid_without_list, |
| } |
| .into_diag(dcx, level) |
| } |
| AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { |
| lints::InvalidTargetLint { |
| name: name.clone(), |
| target, |
| applied: DiagArgValue::StrListSepByAnd( |
| applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), |
| ), |
| only, |
| attr_span: *attr_span, |
| } |
| .into_diag(dcx, level) |
| } |
| &AttributeLintKind::InvalidStyle { |
| ref name, |
| is_used_as_inner, |
| target, |
| target_span, |
| } => lints::InvalidAttrStyle { |
| name: name.clone(), |
| is_used_as_inner, |
| target_span: (!is_used_as_inner).then_some(target_span), |
| target, |
| } |
| .into_diag(dcx, level), |
| &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => { |
| lints::UnsafeAttrOutsideUnsafeLint { |
| span: attribute_name_span, |
| suggestion: sugg_spans.map(|(left, right)| { |
| lints::UnsafeAttrOutsideUnsafeSuggestion { left, right } |
| }), |
| } |
| .into_diag(dcx, level) |
| } |
| &AttributeLintKind::UnexpectedCfgName(name, value) => { |
| check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value) |
| .into_diag(dcx, level) |
| } |
| &AttributeLintKind::UnexpectedCfgValue(name, value) => { |
| check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value) |
| .into_diag(dcx, level) |
| } |
| &AttributeLintKind::DuplicateDocAlias { first_definition } => { |
| lints::DocAliasDuplicated { first_defn: first_definition }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { |
| lints::DocAutoCfgExpectsHideOrShow.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::AmbiguousDeriveHelpers => { |
| lints::AmbiguousDeriveHelpers.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { |
| lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { |
| lints::DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocInvalid => lints::DocInvalid.into_diag(dcx, level), |
| |
| &AttributeLintKind::DocUnknownInclude { span, inner, value } => { |
| lints::DocUnknownInclude { |
| inner, |
| value, |
| sugg: (span, Applicability::MaybeIncorrect), |
| } |
| .into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocUnknownSpotlight { span } => { |
| lints::DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocUnknownPasses { name, span } => { |
| lints::DocUnknownPasses { name, note_span: span }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocUnknownPlugins { span } => { |
| lints::DocUnknownPlugins { label_span: span }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocUnknownAny { name } => { |
| lints::DocUnknownAny { name }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocAutoCfgWrongLiteral => { |
| lints::DocAutoCfgWrongLiteral.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.into_diag(dcx, level), |
| |
| &AttributeLintKind::DocTestUnknown { name } => { |
| lints::DocTestUnknown { name }.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.into_diag(dcx, level), |
| |
| &AttributeLintKind::AttrCrateLevelOnly => { |
| lints::AttrCrateLevelOnly.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { |
| lints::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level) |
| } |
| |
| &AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes { |
| sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }), |
| } |
| .into_diag(dcx, level), |
| |
| &AttributeLintKind::MalformedDoc => lints::MalformedDoc.into_diag(dcx, level), |
| |
| &AttributeLintKind::ExpectedNoArgs => lints::ExpectedNoArgs.into_diag(dcx, level), |
| |
| &AttributeLintKind::ExpectedNameValue => lints::ExpectedNameValue.into_diag(dcx, level), |
| &AttributeLintKind::MalformedOnUnimplementedAttr { span } => { |
| lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level) |
| } |
| &AttributeLintKind::MalformedOnConstAttr { span } => { |
| lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level) |
| } |
| AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning { |
| FormatWarning::PositionalArgument { .. } => { |
| lints::DisallowedPositionalArgument.into_diag(dcx, level) |
| } |
| FormatWarning::InvalidSpecifier { .. } => { |
| lints::InvalidFormatSpecifier.into_diag(dcx, level) |
| } |
| }, |
| AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => { |
| lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level) |
| } |
| &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => { |
| lints::IgnoredDiagnosticOption { option_name, first_span, later_span } |
| .into_diag(dcx, level) |
| } |
| &AttributeLintKind::MissingOptionsForOnUnimplemented => { |
| lints::MissingOptionsForOnUnimplementedAttr.into_diag(dcx, level) |
| } |
| &AttributeLintKind::MissingOptionsForOnConst => { |
| lints::MissingOptionsForOnConstAttr.into_diag(dcx, level) |
| } |
| &AttributeLintKind::MalformedOnMoveAttr { span } => { |
| lints::MalformedOnMoveAttrLint { span }.into_diag(dcx, level) |
| } |
| &AttributeLintKind::OnMoveMalformedFormatLiterals { name } => { |
| lints::OnMoveMalformedFormatLiterals { name }.into_diag(dcx, level) |
| } |
| &AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter => { |
| lints::OnMoveMalformedAttrExpectedLiteralOrDelimiter.into_diag(dcx, level) |
| } |
| &AttributeLintKind::MissingOptionsForOnMove => { |
| lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level) |
| } |
| &AttributeLintKind::RenamedLint { name, replace, suggestion } => lints::RenamedLint { |
| name, |
| replace, |
| suggestion: lints::RenamedLintSuggestion::WithSpan { suggestion, replace }, |
| } |
| .into_diag(dcx, level), |
| &AttributeLintKind::DeprecatedLintName { name, suggestion, replace } => { |
| lints::DeprecatedLintName { name, suggestion, replace }.into_diag(dcx, level) |
| } |
| &AttributeLintKind::RemovedLint { name, ref reason } => { |
| lints::RemovedLint { name, reason }.into_diag(dcx, level) |
| } |
| &AttributeLintKind::UnknownLint { name, span, suggestion } => lints::UnknownLint { |
| name, |
| suggestion: suggestion.map(|(replace, from_rustc)| { |
| lints::UnknownLintSuggestion::WithSpan { suggestion: span, replace, from_rustc } |
| }), |
| } |
| .into_diag(dcx, level), |
| &AttributeLintKind::IgnoredUnlessCrateSpecified { level: attr_level, name } => { |
| lints::IgnoredUnlessCrateSpecified { level: attr_level, name }.into_diag(dcx, level) |
| } |
| } |
| } |
| } |