Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 16:44:30 +11:00
#![ allow(rustc::diagnostic_outside_of_impl) ]
#![ allow(rustc::untranslatable_diagnostic) ]
2023-12-30 16:13:23 +01:00
use rustc_ast ::util ::unicode ::TEXT_FLOW_CONTROL_CHARS ;
2024-02-23 10:20:45 +11:00
use rustc_errors ::{ add_elided_lifetime_in_path_suggestion , Diag } ;
2023-12-30 16:13:23 +01:00
use rustc_errors ::{ Applicability , SuggestionStyle } ;
use rustc_middle ::middle ::stability ;
use rustc_session ::config ::ExpectedValues ;
2024-02-29 16:40:44 +11:00
use rustc_session ::lint ::BuiltinLintDiag ;
2023-12-30 16:13:23 +01:00
use rustc_session ::Session ;
use rustc_span ::edit_distance ::find_best_match_for_name ;
use rustc_span ::symbol ::{ sym , Symbol } ;
use rustc_span ::BytePos ;
2024-02-16 21:32:53 +01:00
const MAX_CHECK_CFG_NAMES_OR_VALUES : usize = 35 ;
fn check_cfg_expected_note (
sess : & Session ,
possibilities : & [ Symbol ] ,
type_ : & str ,
name : Option < Symbol > ,
suffix : & str ,
) -> String {
use std ::fmt ::Write ;
let n_possibilities = if sess . opts . unstable_opts . check_cfg_all_expected {
possibilities . len ( )
} else {
std ::cmp ::min ( possibilities . len ( ) , MAX_CHECK_CFG_NAMES_OR_VALUES )
} ;
let mut possibilities = possibilities . iter ( ) . map ( Symbol ::as_str ) . collect ::< Vec < _ > > ( ) ;
possibilities . sort ( ) ;
let and_more = possibilities . len ( ) . saturating_sub ( n_possibilities ) ;
let possibilities = possibilities [ .. n_possibilities ] . join ( " `, ` " ) ;
let mut note = String ::with_capacity ( 50 + possibilities . len ( ) ) ;
write! ( & mut note , " expected {type_} " ) . unwrap ( ) ;
if let Some ( name ) = name {
write! ( & mut note , " for `{name}` " ) . unwrap ( ) ;
}
write! ( & mut note , " are: {suffix}`{possibilities}` " ) . unwrap ( ) ;
if and_more > 0 {
write! ( & mut note , " and {and_more} more " ) . unwrap ( ) ;
}
note
}
2024-02-29 16:40:44 +11:00
pub ( super ) fn builtin ( sess : & Session , diagnostic : BuiltinLintDiag , diag : & mut Diag < '_ , ( ) > ) {
2023-12-30 16:13:23 +01:00
match diagnostic {
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnicodeTextFlow ( span , content ) = > {
2023-12-30 16:13:23 +01:00
let spans : Vec < _ > = content
. char_indices ( )
. filter_map ( | ( i , c ) | {
TEXT_FLOW_CONTROL_CHARS . contains ( & c ) . then ( | | {
let lo = span . lo ( ) + BytePos ( 2 + i as u32 ) ;
( c , span . with_lo ( lo ) . with_hi ( lo + BytePos ( c . len_utf8 ( ) as u32 ) ) )
} )
} )
. collect ( ) ;
let ( an , s ) = match spans . len ( ) {
1 = > ( " an " , " " ) ,
_ = > ( " " , " s " ) ,
} ;
2024-02-23 10:20:45 +11:00
diag . span_label (
2023-12-30 16:13:23 +01:00
span ,
format! (
" this comment contains {an}invisible unicode text flow control codepoint{s} " ,
) ,
) ;
for ( c , span ) in & spans {
2024-02-23 10:20:45 +11:00
diag . span_label ( * span , format! ( " {c:?} " ) ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-23 10:20:45 +11:00
diag . note (
2023-12-30 16:13:23 +01:00
" these kind of unicode codepoints change the way text flows on \
applications that support them , but can cause confusion because they \
change the order of characters on the screen " ,
) ;
if ! spans . is_empty ( ) {
2024-02-23 10:20:45 +11:00
diag . multipart_suggestion_with_style (
2023-12-30 16:13:23 +01:00
" if their presence wasn't intentional, you can remove them " ,
spans . into_iter ( ) . map ( | ( _ , span ) | ( span , " " . to_string ( ) ) ) . collect ( ) ,
Applicability ::MachineApplicable ,
SuggestionStyle ::HideCodeAlways ,
) ;
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::Normal = > ( ) ,
BuiltinLintDiag ::AbsPathWithModule ( span ) = > {
2023-12-30 16:13:23 +01:00
let ( sugg , app ) = match sess . source_map ( ) . span_to_snippet ( span ) {
Ok ( ref s ) = > {
// FIXME(Manishearth) ideally the emitting code
// can tell us whether or not this is global
let opt_colon = if s . trim_start ( ) . starts_with ( " :: " ) { " " } else { " :: " } ;
( format! ( " crate {opt_colon} {s} " ) , Applicability ::MachineApplicable )
}
Err ( _ ) = > ( " crate::<path> " . to_string ( ) , Applicability ::HasPlaceholders ) ,
} ;
2024-02-23 10:20:45 +11:00
diag . span_suggestion ( span , " use `crate` " , sugg , app ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::ProcMacroDeriveResolutionFallback ( span ) = > {
2024-02-23 10:20:45 +11:00
diag . span_label (
2023-12-30 16:13:23 +01:00
span ,
" names from parent modules are not accessible without an explicit import " ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::MacroExpandedMacroExportsAccessedByAbsolutePaths ( span_def ) = > {
2024-02-23 10:20:45 +11:00
diag . span_note ( span_def , " the macro is defined here " ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::ElidedLifetimesInPaths ( n , path_span , incl_angl_brckt , insertion_span ) = > {
2023-12-30 16:13:23 +01:00
add_elided_lifetime_in_path_suggestion (
sess . source_map ( ) ,
2024-02-23 10:20:45 +11:00
diag ,
2023-12-30 16:13:23 +01:00
n ,
path_span ,
incl_angl_brckt ,
insertion_span ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnknownCrateTypes ( span , note , sugg ) = > {
2024-02-23 10:20:45 +11:00
diag . span_suggestion ( span , note , sugg , Applicability ::MaybeIncorrect ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnusedImports ( message , replaces , in_test_module ) = > {
2023-12-30 16:13:23 +01:00
if ! replaces . is_empty ( ) {
2024-02-23 10:20:45 +11:00
diag . tool_only_multipart_suggestion (
2023-12-30 16:13:23 +01:00
message ,
replaces ,
Applicability ::MachineApplicable ,
) ;
}
if let Some ( span ) = in_test_module {
2024-02-23 10:20:45 +11:00
diag . span_help (
2023-12-30 16:13:23 +01:00
sess . source_map ( ) . guess_head_span ( span ) ,
2024-02-25 09:37:57 +02:00
" if this is a test module, consider adding a `#[cfg(test)]` to the containing module " ,
2023-12-30 16:13:23 +01:00
) ;
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::RedundantImport ( spans , ident ) = > {
2023-12-30 16:13:23 +01:00
for ( span , is_imported ) in spans {
let introduced = if is_imported { " imported " } else { " defined " } ;
2024-02-23 10:20:45 +11:00
diag . span_label ( span , format! ( " the item ` {ident} ` is already {introduced} here " ) ) ;
2023-12-30 16:13:23 +01:00
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::DeprecatedMacro ( suggestion , span ) = > {
2024-02-23 10:20:45 +11:00
stability ::deprecation_suggestion ( diag , " macro " , suggestion , span )
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnusedDocComment ( span ) = > {
2024-02-23 10:20:45 +11:00
diag . span_label ( span , " rustdoc does not generate documentation for macro invocations " ) ;
diag . help ( " to document an item produced by a macro, \
2023-12-30 16:13:23 +01:00
the macro must produce the documentation as part of its expansion " );
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::PatternsInFnsWithoutBody ( span , ident ) = > {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
span ,
" remove `mut` from the parameter " ,
ident ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::MissingAbi ( span , default_abi ) = > {
2024-02-23 10:20:45 +11:00
diag . span_label ( span , " ABI should be specified here " ) ;
diag . help ( format! ( " the default ABI is {} " , default_abi . name ( ) ) ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::LegacyDeriveHelpers ( span ) = > {
2024-02-23 10:20:45 +11:00
diag . span_label ( span , " the attribute is introduced here " ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::ProcMacroBackCompat ( note ) = > {
2024-02-23 10:20:45 +11:00
diag . note ( note ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::OrPatternsBackCompat ( span , suggestion ) = > {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
span ,
" use pat_param to preserve semantics " ,
suggestion ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::ReservedPrefix ( span ) = > {
2024-02-23 10:20:45 +11:00
diag . span_label ( span , " unknown prefix " ) ;
diag . span_suggestion_verbose (
2023-12-30 16:13:23 +01:00
span . shrink_to_hi ( ) ,
" insert whitespace here to avoid this being parsed as a prefix in Rust 2021 " ,
" " ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnusedBuiltinAttribute { attr_name , macro_name , invoc_span } = > {
2024-02-23 10:20:45 +11:00
diag . span_note (
2023-12-30 16:13:23 +01:00
invoc_span ,
format! ( " the built-in attribute ` {attr_name} ` will be ignored, since it's applied to the macro invocation ` {macro_name} ` " )
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::TrailingMacro ( is_trailing , name ) = > {
2023-12-30 16:13:23 +01:00
if is_trailing {
2024-02-23 10:20:45 +11:00
diag . note ( " macro invocations at the end of a block are treated as expressions " ) ;
diag . note ( format! ( " to ignore the value produced by the macro, add a semicolon after the invocation of ` {name} ` " ) ) ;
2023-12-30 16:13:23 +01:00
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::BreakWithLabelAndLoop ( span ) = > {
2024-02-23 10:20:45 +11:00
diag . multipart_suggestion (
2023-12-30 16:13:23 +01:00
" wrap this expression in parentheses " ,
vec! [
( span . shrink_to_lo ( ) , " ( " . to_string ( ) ) ,
( span . shrink_to_hi ( ) , " ) " . to_string ( ) ) ,
] ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::NamedAsmLabel ( help ) = > {
2024-02-23 10:20:45 +11:00
diag . help ( help ) ;
diag . note ( " see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information " ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnexpectedCfgName ( ( name , name_span ) , value ) = > {
2024-01-30 12:42:29 +08:00
#[ allow(rustc::potential_query_instability) ]
2023-12-30 16:13:23 +01:00
let possibilities : Vec < Symbol > =
2024-03-04 16:31:49 +11:00
sess . psess . check_config . expecteds . keys ( ) . copied ( ) . collect ( ) ;
2024-01-28 11:13:02 +08:00
let mut names_possibilities : Vec < _ > = if value . is_none ( ) {
// We later sort and display all the possibilities, so the order here does not matter.
#[ allow(rustc::potential_query_instability) ]
2024-03-04 16:31:49 +11:00
sess . psess
2024-01-28 11:13:02 +08:00
. check_config
. expecteds
. iter ( )
. filter_map ( | ( k , v ) | match v {
ExpectedValues ::Some ( v ) if v . contains ( & Some ( name ) ) = > Some ( k ) ,
_ = > None ,
} )
. collect ( )
} else {
Vec ::new ( )
} ;
2024-02-17 16:45:59 +01:00
let is_from_cargo = rustc_session ::utils ::was_invoked_from_cargo ( ) ;
2023-12-30 16:13:23 +01:00
let mut is_feature_cfg = name = = sym ::feature ;
if is_feature_cfg & & is_from_cargo {
2024-02-23 10:20:45 +11:00
diag . help ( " consider defining some features in `Cargo.toml` " ) ;
2023-12-30 16:13:23 +01:00
// Suggest the most probable if we found one
} else if let Some ( best_match ) = find_best_match_for_name ( & possibilities , name , None ) {
if let Some ( ExpectedValues ::Some ( best_match_values ) ) =
2024-03-04 16:31:49 +11:00
sess . psess . check_config . expecteds . get ( & best_match )
2023-12-30 16:13:23 +01:00
{
2023-12-23 14:30:54 +01:00
// We will soon sort, so the initial order does not matter.
#[ allow(rustc::potential_query_instability) ]
2023-12-30 16:13:23 +01:00
let mut possibilities =
best_match_values . iter ( ) . flatten ( ) . map ( Symbol ::as_str ) . collect ::< Vec < _ > > ( ) ;
possibilities . sort ( ) ;
let mut should_print_possibilities = true ;
if let Some ( ( value , value_span ) ) = value {
if best_match_values . contains ( & Some ( value ) ) {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span ,
" there is a config with a similar name and value " ,
best_match ,
Applicability ::MaybeIncorrect ,
) ;
should_print_possibilities = false ;
} else if best_match_values . contains ( & None ) {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span . to ( value_span ) ,
" there is a config with a similar name and no value " ,
best_match ,
Applicability ::MaybeIncorrect ,
) ;
should_print_possibilities = false ;
} else if let Some ( first_value ) = possibilities . first ( ) {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span . to ( value_span ) ,
" there is a config with a similar name and different values " ,
format! ( " {best_match} = \" {first_value} \" " ) ,
Applicability ::MaybeIncorrect ,
) ;
} else {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span . to ( value_span ) ,
" there is a config with a similar name and different values " ,
best_match ,
Applicability ::MaybeIncorrect ,
) ;
} ;
} else {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span ,
" there is a config with a similar name " ,
best_match ,
Applicability ::MaybeIncorrect ,
) ;
}
if ! possibilities . is_empty ( ) & & should_print_possibilities {
let possibilities = possibilities . join ( " `, ` " ) ;
2024-02-23 10:20:45 +11:00
diag . help ( format! (
2023-12-30 16:13:23 +01:00
" expected values for `{best_match}` are: `{possibilities}` "
) ) ;
}
} else {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span ,
" there is a config with a similar name " ,
best_match ,
Applicability ::MaybeIncorrect ,
) ;
}
is_feature_cfg | = best_match = = sym ::feature ;
2024-01-28 11:13:02 +08:00
} else {
2024-01-30 10:18:52 +08:00
if ! names_possibilities . is_empty ( ) & & names_possibilities . len ( ) < = 3 {
2024-01-28 11:13:02 +08:00
names_possibilities . sort ( ) ;
for cfg_name in names_possibilities . iter ( ) {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2024-01-28 11:13:02 +08:00
name_span ,
" found config with similar value " ,
format! ( " {cfg_name} = \" {name} \" " ) ,
Applicability ::MaybeIncorrect ,
) ;
}
}
if ! possibilities . is_empty ( ) {
2024-02-16 21:32:53 +01:00
diag . help_once ( check_cfg_expected_note (
sess ,
& possibilities ,
" names " ,
None ,
" " ,
) ) ;
2024-01-28 11:13:02 +08:00
}
2023-12-30 16:13:23 +01:00
}
let inst = if let Some ( ( value , _value_span ) ) = value {
let pre = if is_from_cargo { " \\ " } else { " " } ;
format! ( " cfg( {name} , values( {pre} \" {value} {pre} \" )) " )
} else {
format! ( " cfg( {name} ) " )
} ;
if is_from_cargo {
if ! is_feature_cfg {
2024-02-23 10:20:45 +11:00
diag . help ( format! ( " consider using a Cargo feature instead or adding `println!( \" cargo:rustc-check-cfg= {inst} \" );` to the top of a `build.rs` " ) ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-23 10:20:45 +11:00
diag . note ( " see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration " ) ;
2023-12-30 16:13:23 +01:00
} else {
2024-02-23 10:20:45 +11:00
diag . help ( format! ( " to expect this configuration use `--check-cfg= {inst} ` " ) ) ;
diag . note ( " see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration " ) ;
2023-12-30 16:13:23 +01:00
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnexpectedCfgValue ( ( name , name_span ) , value ) = > {
2024-03-04 16:31:49 +11:00
let Some ( ExpectedValues ::Some ( values ) ) = & sess . psess . check_config . expecteds . get ( & name )
2023-12-30 16:13:23 +01:00
else {
bug! (
" it shouldn't be possible to have a diagnostic on a value whose name is not in values "
) ;
} ;
let mut have_none_possibility = false ;
2023-12-23 14:30:54 +01:00
// We later sort possibilities if it is not empty, so the
// order here does not matter.
#[ allow(rustc::potential_query_instability) ]
2023-12-30 16:13:23 +01:00
let possibilities : Vec < Symbol > = values
. iter ( )
. inspect ( | a | have_none_possibility | = a . is_none ( ) )
. copied ( )
. flatten ( )
. collect ( ) ;
2024-02-17 16:45:59 +01:00
let is_from_cargo = rustc_session ::utils ::was_invoked_from_cargo ( ) ;
2023-12-30 16:13:23 +01:00
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
if ! possibilities . is_empty ( ) {
2024-02-16 21:32:53 +01:00
diag . note ( check_cfg_expected_note (
sess ,
& possibilities ,
" values " ,
Some ( name ) ,
if have_none_possibility { " (none), " } else { " " } ,
) ) ;
2023-12-30 16:13:23 +01:00
if let Some ( ( value , value_span ) ) = value {
// Suggest the most probable if we found one
if let Some ( best_match ) = find_best_match_for_name ( & possibilities , value , None )
{
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
value_span ,
" there is a expected value with a similar name " ,
format! ( " \" {best_match} \" " ) ,
Applicability ::MaybeIncorrect ,
) ;
}
} else if let & [ first_possibility ] = & possibilities [ .. ] {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span . shrink_to_hi ( ) ,
" specify a config value " ,
format! ( " = \" {first_possibility} \" " ) ,
Applicability ::MaybeIncorrect ,
) ;
}
} else if have_none_possibility {
2024-02-23 10:20:45 +11:00
diag . note ( format! ( " no expected value for ` {name} ` " ) ) ;
2023-12-30 16:13:23 +01:00
if let Some ( ( _value , value_span ) ) = value {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
name_span . shrink_to_hi ( ) . to ( value_span ) ,
" remove the value " ,
" " ,
Applicability ::MaybeIncorrect ,
) ;
}
2024-01-13 12:18:51 +01:00
} else {
2024-02-23 10:20:45 +11:00
diag . note ( format! ( " no expected values for ` {name} ` " ) ) ;
2024-01-13 12:18:51 +01:00
let sp = if let Some ( ( _value , value_span ) ) = value {
name_span . to ( value_span )
} else {
name_span
} ;
2024-02-23 10:20:45 +11:00
diag . span_suggestion ( sp , " remove the condition " , " " , Applicability ::MaybeIncorrect ) ;
2023-12-30 16:13:23 +01:00
}
2023-12-13 17:59:33 +01:00
// We don't want to suggest adding values to well known names
// since those are defined by rustc it-self. Users can still
// do it if they want, but should not encourage them.
2024-03-04 16:31:49 +11:00
let is_cfg_a_well_know_name = sess . psess . check_config . well_known_names . contains ( & name ) ;
2023-12-13 17:59:33 +01:00
2023-12-30 16:13:23 +01:00
let inst = if let Some ( ( value , _value_span ) ) = value {
let pre = if is_from_cargo { " \\ " } else { " " } ;
format! ( " cfg( {name} , values( {pre} \" {value} {pre} \" )) " )
} else {
format! ( " cfg( {name} ) " )
} ;
if is_from_cargo {
if name = = sym ::feature {
if let Some ( ( value , _value_span ) ) = value {
2024-02-23 10:20:45 +11:00
diag . help ( format! (
" consider adding `{value}` as a feature in `Cargo.toml` "
) ) ;
2024-01-13 12:18:51 +01:00
} else {
2024-02-23 10:20:45 +11:00
diag . help ( " consider defining some features in `Cargo.toml` " ) ;
2023-12-30 16:13:23 +01:00
}
2023-12-13 17:59:33 +01:00
} else if ! is_cfg_a_well_know_name {
2024-02-23 10:20:45 +11:00
diag . help ( format! ( " consider using a Cargo feature instead or adding `println!( \" cargo:rustc-check-cfg= {inst} \" );` to the top of a `build.rs` " ) ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-23 10:20:45 +11:00
diag . note ( " see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration " ) ;
2023-12-30 16:13:23 +01:00
} else {
2023-12-13 17:59:33 +01:00
if ! is_cfg_a_well_know_name {
2024-02-23 10:20:45 +11:00
diag . help ( format! ( " to expect this configuration use `--check-cfg= {inst} ` " ) ) ;
2023-12-13 17:59:33 +01:00
}
2024-02-23 10:20:45 +11:00
diag . note ( " see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration " ) ;
2023-12-30 16:13:23 +01:00
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::DeprecatedWhereclauseLocation ( sugg ) = > {
2024-02-20 04:41:01 +01:00
let left_sp = diag . span . primary_span ( ) . unwrap ( ) ;
match sugg {
Some ( ( right_sp , sugg ) ) = > diag . multipart_suggestion (
" move it to the end of the type declaration " ,
vec! [ ( left_sp , String ::new ( ) ) , ( right_sp , sugg ) ] ,
Applicability ::MachineApplicable ,
) ,
None = > diag . span_suggestion (
left_sp ,
" remove this `where` " ,
" " ,
Applicability ::MachineApplicable ,
) ,
} ;
diag . note ( " see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information " ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::SingleUseLifetime {
2023-12-30 16:13:23 +01:00
param_span ,
use_span : Some ( ( use_span , elide ) ) ,
deletion_span ,
} = > {
debug! ( ? param_span , ? use_span , ? deletion_span ) ;
2024-02-23 10:20:45 +11:00
diag . span_label ( param_span , " this lifetime... " ) ;
diag . span_label ( use_span , " ...is used only here " ) ;
2023-12-30 16:13:23 +01:00
if let Some ( deletion_span ) = deletion_span {
let msg = " elide the single-use lifetime " ;
let ( use_span , replace_lt ) = if elide {
let use_span = sess
. source_map ( )
. span_extend_while ( use_span , char ::is_whitespace )
. unwrap_or ( use_span ) ;
( use_span , String ::new ( ) )
} else {
( use_span , " '_ " . to_owned ( ) )
} ;
debug! ( ? deletion_span , ? use_span ) ;
// issue 107998 for the case such as a wrong function pointer type
// `deletion_span` is empty and there is no need to report lifetime uses here
let suggestions = if deletion_span . is_empty ( ) {
vec! [ ( use_span , replace_lt ) ]
} else {
vec! [ ( deletion_span , String ::new ( ) ) , ( use_span , replace_lt ) ]
} ;
2024-02-23 10:20:45 +11:00
diag . multipart_suggestion ( msg , suggestions , Applicability ::MachineApplicable ) ;
2023-12-30 16:13:23 +01:00
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::SingleUseLifetime { param_span : _ , use_span : None , deletion_span } = > {
2023-12-30 16:13:23 +01:00
debug! ( ? deletion_span ) ;
if let Some ( deletion_span ) = deletion_span {
2024-02-23 10:20:45 +11:00
diag . span_suggestion (
2023-12-30 16:13:23 +01:00
deletion_span ,
" elide the unused lifetime " ,
" " ,
Applicability ::MachineApplicable ,
) ;
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::NamedArgumentUsedPositionally {
2023-12-30 16:13:23 +01:00
position_sp_to_replace ,
position_sp_for_msg ,
named_arg_sp ,
named_arg_name ,
is_formatting_arg ,
} = > {
2024-02-23 10:20:45 +11:00
diag . span_label (
2023-12-30 16:13:23 +01:00
named_arg_sp ,
" this named argument is referred to by position in formatting string " ,
) ;
if let Some ( positional_arg_for_msg ) = position_sp_for_msg {
let msg = format! (
" this formatting argument uses named argument `{named_arg_name}` by position "
) ;
2024-02-23 10:20:45 +11:00
diag . span_label ( positional_arg_for_msg , msg ) ;
2023-12-30 16:13:23 +01:00
}
if let Some ( positional_arg_to_replace ) = position_sp_to_replace {
let name = if is_formatting_arg { named_arg_name + " $ " } else { named_arg_name } ;
let span_to_replace = if let Ok ( positional_arg_content ) =
sess . source_map ( ) . span_to_snippet ( positional_arg_to_replace )
& & positional_arg_content . starts_with ( ':' )
{
positional_arg_to_replace . shrink_to_lo ( )
} else {
positional_arg_to_replace
} ;
2024-02-23 10:20:45 +11:00
diag . span_suggestion_verbose (
2023-12-30 16:13:23 +01:00
span_to_replace ,
" use the named argument by name to avoid ambiguity " ,
name ,
Applicability ::MaybeIncorrect ,
) ;
}
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::ByteSliceInPackedStructWithDerive = > {
2024-02-23 10:20:45 +11:00
diag . help ( " consider implementing the trait by hand, or remove the `packed` attribute " ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnusedExternCrate { removal_span } = > {
2024-02-23 10:20:45 +11:00
diag . span_suggestion ( removal_span , " remove it " , " " , Applicability ::MachineApplicable ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::ExternCrateNotIdiomatic { vis_span , ident_span } = > {
2023-12-30 16:13:23 +01:00
let suggestion_span = vis_span . between ( ident_span ) ;
2024-02-23 10:20:45 +11:00
diag . span_suggestion_verbose (
2023-12-30 16:13:23 +01:00
suggestion_span ,
" convert it to a `use` " ,
if vis_span . is_empty ( ) { " use " } else { " use " } ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::AmbiguousGlobImports { diag : ambiguity } = > {
2024-02-23 10:20:45 +11:00
rustc_errors ::report_ambiguity_error ( diag , ambiguity ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::AmbiguousGlobReexports {
2023-12-30 16:13:23 +01:00
name ,
namespace ,
first_reexport_span ,
duplicate_reexport_span ,
} = > {
2024-02-23 10:20:45 +11:00
diag . span_label (
2023-12-30 16:13:23 +01:00
first_reexport_span ,
format! ( " the name ` {name} ` in the {namespace} namespace is first re-exported here " ) ,
) ;
2024-02-23 10:20:45 +11:00
diag . span_label (
2023-12-30 16:13:23 +01:00
duplicate_reexport_span ,
format! (
" but the name `{name}` in the {namespace} namespace is also re-exported here "
) ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::HiddenGlobReexports {
2023-12-30 16:13:23 +01:00
name ,
namespace ,
glob_reexport_span ,
private_item_span ,
} = > {
2024-02-23 10:20:45 +11:00
diag . span_note ( glob_reexport_span , format! ( " the name ` {name} ` in the {namespace} namespace is supposed to be publicly re-exported here " ) ) ;
diag . span_note ( private_item_span , " but the private item here shadows it " . to_owned ( ) ) ;
2023-12-30 16:13:23 +01:00
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::UnusedQualifications { removal_span } = > {
2024-02-23 10:20:45 +11:00
diag . span_suggestion_verbose (
2023-12-30 16:13:23 +01:00
removal_span ,
" remove the unnecessary path segments " ,
" " ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::AssociatedConstElidedLifetime { elided , span } = > {
2024-02-23 10:20:45 +11:00
diag . span_suggestion_verbose (
2023-12-30 16:13:23 +01:00
if elided { span . shrink_to_hi ( ) } else { span } ,
" use the `'static` lifetime " ,
if elided { " 'static " } else { " 'static " } ,
Applicability ::MachineApplicable ,
) ;
}
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::RedundantImportVisibility { max_vis , span } = > {
2024-02-23 10:20:45 +11:00
diag . span_note ( span , format! ( " the most public imported item is ` {max_vis} ` " ) ) ;
diag . help (
" reduce the glob import's visibility or increase visibility of imported items " ,
) ;
2023-12-30 16:13:23 +01:00
}
}
}