diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-04-05 09:33:22 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-05 09:33:22 +0200 |
| commit | d4730244d7be72b2c1f0e528bb3c41a91ebdf924 (patch) | |
| tree | f4ab3bdc4e725db3cebbae49d440e4d6762977ec /src | |
| parent | 73eab351093a16637298fc501ded798d26419d73 (diff) | |
| parent | ccd482032672a223ceaa8ab8d7637180a357fdea (diff) | |
| download | rust-d4730244d7be72b2c1f0e528bb3c41a91ebdf924.tar.gz rust-d4730244d7be72b2c1f0e528bb3c41a91ebdf924.zip | |
Rollup merge of #95512 - davidtwco:diagnostic-translation, r=oli-obk
diagnostics: translation infrastructure
An implementation of the infrastructure required to have translatable diagnostic messages.
- Introduces a `DiagnosticMessage` type which can represent both the current non-translatable messages and identifiers for [Fluent](https://projectfluent.org/).
- Modifies current diagnostic API so that existing calls still work but `DiagnosticMessage`s can be provided too.
- Adds support for always loading a "fallback bundle" containing the English diagnostic messages, which are used when a `DiagnosticMessage::FluentIdentifier` is used in a diagnostic being emitted.
- Adds support for loading a "primary bundle" which contains the user's preferred language translation, and is used preferentially when it contains a diagnostic message being emitted. Primary bundles are loaded either from the path provided to `-Ztranslate-alternate-ftl` (for testing), or from the sysroot at `$sysroot/locale/$locale/*.ftl` given a locale with `-Ztranslate-lang` (which is parsed as a language identifier).
- Adds "diagnostic args" which enable normally-interpolated variables to be made available as variables for Fluent messages to use.
- Updates `#[derive(SessionDiagnostic)]` so that it can only be used for translatable diagnostics and update the handful of diagnostics which used the derive to be translatable.
For example, the following diagnostic...
```rust
#[derive(SessionDiagnostic)]
#[error = "E0195"]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"]
#[label = "lifetimes do not match {item_kind} in trait"]
pub span: Span,
#[label = "lifetimes in impl do not match this {item_kind} in trait"]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
```
...becomes...
```rust
#[derive(SessionDiagnostic)]
#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[primary_span]
#[label]
pub span: Span,
#[label = "generics-label"]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
```
```fluent
typeck-lifetimes-or-bounds-mismatch-on-trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait
.generics-label = lifetimes in impl do not match this {$item_kind} in trait
```
r? `@estebank`
cc `@oli-obk` `@Manishearth`
Diffstat (limited to 'src')
20 files changed, 684 insertions, 206 deletions
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index bd64e2b03ce..a32b9caa30f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -143,6 +143,8 @@ crate fn new_handler( source_map: Option<Lrc<source_map::SourceMap>>, debugging_opts: &DebuggingOptions, ) -> rustc_errors::Handler { + let fallback_bundle = + rustc_errors::fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle"); let emitter: Box<dyn Emitter + sync::Send> = match error_format { ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); @@ -150,6 +152,8 @@ crate fn new_handler( EmitterWriter::stderr( color_config, source_map.map(|sm| sm as _), + None, + fallback_bundle, short, debugging_opts.teach, debugging_opts.terminal_width, @@ -166,6 +170,8 @@ crate fn new_handler( JsonEmitter::stderr( None, source_map, + None, + fallback_bundle, pretty, json_rendered, debugging_opts.terminal_width, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c4201e22212..63b744133a2 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -537,12 +537,31 @@ crate fn make_test( // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - supports_color = - EmitterWriter::stderr(ColorConfig::Auto, None, false, false, Some(80), false) - .supports_color(); - - let emitter = - EmitterWriter::new(box io::sink(), None, false, false, false, None, false); + let fallback_bundle = rustc_errors::fallback_fluent_bundle(false) + .expect("failed to load fallback fluent bundle"); + supports_color = EmitterWriter::stderr( + ColorConfig::Auto, + None, + None, + fallback_bundle.clone(), + false, + false, + Some(80), + false, + ) + .supports_color(); + + let emitter = EmitterWriter::new( + box io::sink(), + None, + None, + fallback_bundle, + false, + false, + false, + None, + false, + ); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 8d9b3377a69..465dd523ff4 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -32,7 +32,9 @@ struct SyntaxChecker<'a, 'tcx> { impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { let buffer = Lrc::new(Lock::new(Buffer::default())); - let emitter = BufferEmitter { buffer: Lrc::clone(&buffer) }; + let fallback_bundle = rustc_errors::fallback_fluent_bundle(false) + .expect("failed to load fallback fluent bundle"); + let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle }; let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let handler = Handler::with_emitter(false, None, Box::new(emitter)); @@ -171,12 +173,14 @@ struct Buffer { struct BufferEmitter { buffer: Lrc<Lock<Buffer>>, + fallback_bundle: Lrc<rustc_errors::FluentBundle>, } impl Emitter for BufferEmitter { fn emit_diagnostic(&mut self, diag: &Diagnostic) { let mut buffer = self.buffer.borrow_mut(); - buffer.messages.push(format!("error from rustc: {}", diag.message[0].0)); + // FIXME(davidtwco): need to support translation here eventually + buffer.messages.push(format!("error from rustc: {}", diag.message[0].0.expect_str())); if diag.is_error() { buffer.has_errors = true; } @@ -185,4 +189,12 @@ impl Emitter for BufferEmitter { fn source_map(&self) -> Option<&Lrc<SourceMap>> { None } + + fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + None + } + + fn fallback_fluent_bundle(&self) -> &Lrc<rustc_errors::FluentBundle> { + &self.fallback_bundle + } } diff --git a/src/test/run-make/translation/Makefile b/src/test/run-make/translation/Makefile new file mode 100644 index 00000000000..22a3bf57ecf --- /dev/null +++ b/src/test/run-make/translation/Makefile @@ -0,0 +1,33 @@ +include ../../run-make-fulldeps/tools.mk + +# This test uses `ln -s` rather than copying to save testing time, but its +# usage doesn't work on Windows. +# ignore-windows + +SYSROOT:=$(shell $(RUSTC) --print sysroot) +FAKEROOT=$(TMPDIR)/fakeroot + +all: normal custom sysroot + +normal: basic-translation.rs + $(RUSTC) $< 2>&1 | grep "struct literal body without path" + +custom: basic-translation.rs basic-translation.ftl + $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message" + +# Make a local copy of the sysroot and add the custom locale to it. +sysroot: basic-translation.rs basic-translation.ftl + mkdir $(FAKEROOT) + ln -s $(SYSROOT)/* $(FAKEROOT) + rm -f $(FAKEROOT)/lib + mkdir $(FAKEROOT)/lib + ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib + rm -f $(FAKEROOT)/lib/rustlib + mkdir $(FAKEROOT)/lib/rustlib + ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib + rm -f $(FAKEROOT)/lib/rustlib/src + mkdir $(FAKEROOT)/lib/rustlib/src + ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src + mkdir -p $(FAKEROOT)/share/locale/zh-CN/ + ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl + $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message" diff --git a/src/test/run-make/translation/basic-translation.ftl b/src/test/run-make/translation/basic-translation.ftl new file mode 100644 index 00000000000..4681b879cda --- /dev/null +++ b/src/test/run-make/translation/basic-translation.ftl @@ -0,0 +1,2 @@ +parser-struct-literal-body-without-path = this is a test message + .suggestion = this is a test suggestion diff --git a/src/test/run-make/translation/basic-translation.rs b/src/test/run-make/translation/basic-translation.rs new file mode 100644 index 00000000000..b8f5bff3153 --- /dev/null +++ b/src/test/run-make/translation/basic-translation.rs @@ -0,0 +1,18 @@ +// Exact error being tested isn't relevant, it just needs to be known that it uses Fluent-backed +// diagnostics. + +struct Foo { + val: (), +} + +fn foo() -> Foo { + val: (), +} + +fn main() { + let x = foo(); + x.val == 42; + let x = { + val: (), + }; +} diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs index 140aaad3b38..adec548b390 100644 --- a/src/test/ui-fulldeps/session-derive-errors.rs +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -11,8 +11,8 @@ #![crate_type = "lib"] extern crate rustc_span; -use rustc_span::Span; use rustc_span::symbol::Ident; +use rustc_span::Span; extern crate rustc_macros; use rustc_macros::SessionDiagnostic; @@ -26,12 +26,15 @@ use rustc_errors::Applicability; extern crate rustc_session; #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[error = "E0123"] +#[error(code = "E0123", slug = "hello-world")] struct Hello {} #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[warning(code = "E0123", slug = "hello-world")] +struct HelloWarn {} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] //~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs enum SessionDiagnosticOnEnum { Foo, @@ -39,228 +42,387 @@ enum SessionDiagnosticOnEnum { } #[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] #[error = "E0123"] -#[label = "This is in the wrong place"] -//~^ ERROR `#[label = ...]` is not a valid SessionDiagnostic struct attribute -struct WrongPlace {} +//~^ ERROR `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute +struct WrongStructAttrStyle {} #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[nonsense(code = "E0123", slug = "foo")] +//~^ ERROR `#[nonsense(...)]` is not a valid `SessionDiagnostic` struct attribute +//~^^ ERROR diagnostic kind not specified +//~^^^ ERROR cannot find attribute `nonsense` in this scope +struct InvalidStructAttr {} + +#[derive(SessionDiagnostic)] +#[error("E0123")] +//~^ ERROR `#[error("...")]` is not a valid `SessionDiagnostic` struct attribute +//~^^ ERROR `slug` not specified +struct InvalidLitNestedAttr {} + +#[derive(SessionDiagnostic)] +#[error(nonsense, code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense)]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr {} + +#[derive(SessionDiagnostic)] +#[error(nonsense("foo"), code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense(...))]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr1 {} + +#[derive(SessionDiagnostic)] +#[error(nonsense = "...", code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr2 {} + +#[derive(SessionDiagnostic)] +#[error(nonsense = 4, code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr3 {} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] struct WrongPlaceField { - #[suggestion = "this is the wrong kind of attribute"] -//~^ ERROR `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + #[suggestion = "bar"] + //~^ ERROR `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute sp: Span, } #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[error = "E0123"] -#[error = "E0456"] //~ ERROR `error` specified multiple times +#[error(code = "E0123", slug = "foo")] +#[error(code = "E0456", slug = "bar")] //~ ERROR `error` specified multiple times struct ErrorSpecifiedTwice {} #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[error = "E0123"] -#[lint = "some_useful_lint"] //~ ERROR `lint` specified when `error` was already specified -struct LintSpecifiedAfterError {} +#[error(code = "E0123", slug = "foo")] +#[warning(code = "E0293", slug = "bar")] +//~^ ERROR `warning` specified when `error` was already specified +struct WarnSpecifiedAfterError {} #[derive(SessionDiagnostic)] -#[message = "Some lint message"] -#[error = "E0123"] -struct LintButHasErrorCode {} +#[error(code = "E0456", code = "E0457", slug = "bar")] //~ ERROR `code` specified multiple times +struct CodeSpecifiedTwice {} #[derive(SessionDiagnostic)] -struct ErrorCodeNotProvided {} //~ ERROR `code` not specified +#[error(code = "E0456", slug = "foo", slug = "bar")] //~ ERROR `slug` specified multiple times +struct SlugSpecifiedTwice {} -// FIXME: Uncomment when emitting lints is supported. -/* #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[lint = "clashing_extern_declarations"] -#[lint = "improper_ctypes"] // FIXME: ERROR `lint` specified multiple times -struct LintSpecifiedTwice {} +struct KindNotProvided {} //~ ERROR diagnostic kind not specified #[derive(SessionDiagnostic)] -#[lint = "Some lint message"] -#[message = "Some error message"] -#[error = "E0123"] // ERROR `error` specified when `lint` was already specified -struct ErrorSpecifiedAfterLint {} -*/ +#[error(code = "E0456")] //~ ERROR `slug` not specified +struct SlugNotProvided {} #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(slug = "foo")] +struct CodeNotProvided {} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct MessageWrongType { + #[primary_span] + //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` + foo: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct InvalidPathFieldAttr { + #[nonsense] + //~^ ERROR `#[nonsense]` is not a valid `SessionDiagnostic` field attribute + //~^^ ERROR cannot find attribute `nonsense` in this scope + foo: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] struct ErrorWithField { name: String, - #[message = "This error has a field, and references {name}"] - span: Span + #[label = "bar"] + span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct ErrorWithMessageAppliedToField { - #[message = "this message is applied to a String field"] - //~^ ERROR the `#[message = "..."]` attribute can only be applied to fields of type Span + #[label = "bar"] + //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span` name: String, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "This error has a field, and references {name}"] -//~^ ERROR `name` doesn't refer to a field on this type +#[error(code = "E0123", slug = "foo")] struct ErrorWithNonexistentField { - span: Span + #[suggestion(message = "bar", code = "{name}")] + //~^ ERROR `name` doesn't refer to a field on this type + suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "This is missing a closing brace: {name"] //~^ ERROR invalid format string: expected `'}'` +#[error(code = "E0123", slug = "foo")] struct ErrorMissingClosingBrace { + #[suggestion(message = "bar", code = "{name")] + suggestion: (Span, Applicability), name: String, - span: Span + val: usize, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "This is missing an opening brace: name}"] //~^ ERROR invalid format string: unmatched `}` +#[error(code = "E0123", slug = "foo")] struct ErrorMissingOpeningBrace { + #[suggestion(message = "bar", code = "name}")] + suggestion: (Span, Applicability), name: String, - span: Span + val: usize, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "Something something"] +#[error(code = "E0123", slug = "foo")] struct LabelOnSpan { - #[label = "See here"] - sp: Span + #[label = "bar"] + sp: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "Something something"] +#[error(code = "E0123", slug = "foo")] struct LabelOnNonSpan { - #[label = "See here"] - //~^ ERROR The `#[label = ...]` attribute can only be applied to fields of type Span + #[label = "bar"] + //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span` id: u32, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct Suggest { - #[suggestion(message = "This is a suggestion", code = "This is the suggested code")] - #[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")] - #[suggestion_hidden(message = "This is a suggestion", code = "This is the suggested code")] - #[suggestion_verbose(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion(message = "bar", code = "This is the suggested code")] + #[suggestion_short(message = "qux", code = "This is the suggested code")] + #[suggestion_hidden(message = "foobar", code = "This is the suggested code")] + #[suggestion_verbose(message = "fooqux", code = "This is the suggested code")] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithoutCode { - #[suggestion(message = "This is a suggestion")] + #[suggestion(message = "bar")] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithBadKey { - #[suggestion(nonsense = "This is nonsense")] - //~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]` + #[suggestion(nonsense = "bar")] + //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid `SessionDiagnostic` field attribute suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithShorthandMsg { - #[suggestion(msg = "This is a suggestion")] - //~^ ERROR `msg` is not a valid key for `#[suggestion(...)]` + #[suggestion(msg = "bar")] + //~^ ERROR `#[suggestion(msg = ...)]` is not a valid `SessionDiagnostic` field attribute suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithoutMsg { - #[suggestion(code = "This is suggested code")] - //~^ ERROR missing suggestion message + #[suggestion(code = "bar")] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithTypesSwapped { - #[suggestion(message = "This is a message", code = "This is suggested code")] + #[suggestion(message = "bar", code = "This is suggested code")] suggestion: (Applicability, Span), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithWrongTypeApplicabilityOnly { - #[suggestion(message = "This is a message", code = "This is suggested code")] + #[suggestion(message = "bar", code = "This is suggested code")] //~^ ERROR wrong field type for suggestion suggestion: Applicability, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -struct SuggestWithSpanOnly{ - #[suggestion(message = "This is a message", code = "This is suggested code")] +#[error(code = "E0123", slug = "foo")] +struct SuggestWithSpanOnly { + #[suggestion(message = "bar", code = "This is suggested code")] suggestion: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithDuplicateSpanAndApplicability { - #[suggestion(message = "This is a message", code = "This is suggested code")] - //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one Span + #[suggestion(message = "bar", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span` suggestion: (Span, Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithDuplicateApplicabilityAndSpan { - #[suggestion(message = "This is a message", code = "This is suggested code")] + #[suggestion(message = "bar", code = "This is suggested code")] //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one suggestion: (Applicability, Applicability, Span), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct WrongKindOfAnnotation { - #[label("wrong kind of annotation for label")] - //~^ ERROR invalid annotation list `#[label(...)]` + #[label("bar")] + //~^ ERROR `#[label(...)]` is not a valid `SessionDiagnostic` field attribute z: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "Something something else"] +#[error(code = "E0123", slug = "foo")] struct OptionsInErrors { - #[label = "Label message"] + #[label = "bar"] label: Option<Span>, - #[suggestion(message = "suggestion message")] + #[suggestion(message = "bar")] opt_sugg: Option<(Span, Applicability)>, } #[derive(SessionDiagnostic)] -#[error = "E0456"] +#[error(code = "E0456", slug = "foo")] struct MoveOutOfBorrowError<'tcx> { name: Ident, ty: Ty<'tcx>, - #[message = "cannot move {ty} out of borrow"] - #[label = "cannot move out of borrow"] + #[primary_span] + #[label = "bar"] span: Span, - #[label = "`{ty}` first borrowed here"] + #[label = "qux"] other_span: Span, - #[suggestion(message = "consider cloning here", code = "{name}.clone()")] + #[suggestion(message = "bar", code = "{name}.clone()")] opt_sugg: Option<(Span, Applicability)>, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct ErrorWithLifetime<'a> { - #[message = "Some message that references {name}"] + #[label = "bar"] span: Span, name: &'a str, } + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithDefaultLabelAttr<'a> { + #[label] + span: Span, + name: &'a str, +} + +#[derive(SessionDiagnostic)] +//~^ ERROR no method named `into_diagnostic_arg` found for struct `Hello` in the current scope +#[error(code = "E0123", slug = "foo")] +struct ArgFieldWithoutSkip { + #[primary_span] + span: Span, + other: Hello, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ArgFieldWithSkip { + #[primary_span] + span: Span, + // `Hello` does not implement `IntoDiagnosticArg` so this would result in an error if + // not for `#[skip_arg]`. + #[skip_arg] + other: Hello, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedNote { + #[note] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedNoteCustom { + #[note = "bar"] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[note] +struct ErrorWithNote { + val: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[note = "bar"] +struct ErrorWithNoteCustom { + val: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedHelp { + #[help] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedHelpCustom { + #[help = "bar"] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[help] +struct ErrorWithHelp { + val: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[help = "bar"] +struct ErrorWithHelpCustom { + val: String, +} + +#[derive(SessionDiagnostic)] +#[help] +//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithHelpWrongOrder { + val: String, +} + +#[derive(SessionDiagnostic)] +#[help = "bar"] +//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithHelpCustomWrongOrder { + val: String, +} + +#[derive(SessionDiagnostic)] +#[note] +//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithNoteWrongOrder { + val: String, +} + +#[derive(SessionDiagnostic)] +#[note = "bar"] +//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithNoteCustomWrongOrder { + val: String, +} diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr index c7853f5275e..a528ae1607f 100644 --- a/src/test/ui-fulldeps/session-derive-errors.stderr +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -1,7 +1,7 @@ error: `#[derive(SessionDiagnostic)]` can only be used on structs - --> $DIR/session-derive-errors.rs:34:1 + --> $DIR/session-derive-errors.rs:37:1 | -LL | / #[error = "E0123"] +LL | / #[error(code = "E0123", slug = "foo")] LL | | LL | | enum SessionDiagnosticOnEnum { LL | | Foo, @@ -9,132 +9,285 @@ LL | | Bar, LL | | } | |_^ -error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute - --> $DIR/session-derive-errors.rs:43:1 +error: `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:46:1 | -LL | #[label = "This is in the wrong place"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error = "E0123"] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[nonsense(...)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:51:1 + | +LL | #[nonsense(code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: diagnostic kind not specified + --> $DIR/session-derive-errors.rs:51:1 + | +LL | / #[nonsense(code = "E0123", slug = "foo")] +LL | | +LL | | +LL | | +LL | | struct InvalidStructAttr {} + | |___________________________^ + | + = help: use the `#[error(...)]` attribute to create an error + +error: `#[error("...")]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:58:9 + | +LL | #[error("E0123")] + | ^^^^^^^ + +error: `slug` not specified + --> $DIR/session-derive-errors.rs:58:1 + | +LL | / #[error("E0123")] +LL | | +LL | | +LL | | struct InvalidLitNestedAttr {} + | |______________________________^ + | + = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug + +error: `#[error(nonsense)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:64:9 + | +LL | #[error(nonsense, code = "E0123", slug = "foo")] + | ^^^^^^^^ + +error: `#[error(nonsense(...))]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:69:9 + | +LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^ + +error: `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:74:9 + | +LL | #[error(nonsense = "...", code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^ -error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute - --> $DIR/session-derive-errors.rs:50:5 +error: `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:79:9 | -LL | #[suggestion = "this is the wrong kind of attribute"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(nonsense = 4, code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^ + | + = help: value must be a string + +error: `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute + --> $DIR/session-derive-errors.rs:86:5 + | +LL | #[suggestion = "bar"] + | ^^^^^^^^^^^^^^^^^^^^^ error: `error` specified multiple times - --> $DIR/session-derive-errors.rs:58:11 + --> $DIR/session-derive-errors.rs:93:1 + | +LL | #[error(code = "E0456", slug = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:92:1 + | +LL | #[error(code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `warning` specified when `error` was already specified + --> $DIR/session-derive-errors.rs:98:1 + | +LL | #[warning(code = "E0293", slug = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:97:1 + | +LL | #[error(code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `code` specified multiple times + --> $DIR/session-derive-errors.rs:103:32 | -LL | #[error = "E0456"] - | ^^^^^^^ +LL | #[error(code = "E0456", code = "E0457", slug = "bar")] + | ^^^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:103:16 + | +LL | #[error(code = "E0456", code = "E0457", slug = "bar")] + | ^^^^^^^ -error: `lint` specified when `error` was already specified - --> $DIR/session-derive-errors.rs:64:10 +error: `slug` specified multiple times + --> $DIR/session-derive-errors.rs:107:46 + | +LL | #[error(code = "E0456", slug = "foo", slug = "bar")] + | ^^^^^ | -LL | #[lint = "some_useful_lint"] - | ^^^^^^^^^^^^^^^^^^ +note: previously specified here + --> $DIR/session-derive-errors.rs:107:32 + | +LL | #[error(code = "E0456", slug = "foo", slug = "bar")] + | ^^^^^ -error: `code` not specified - --> $DIR/session-derive-errors.rs:73:1 +error: diagnostic kind not specified + --> $DIR/session-derive-errors.rs:111:1 + | +LL | struct KindNotProvided {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | struct ErrorCodeNotProvided {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use the `#[error(...)]` attribute to create an error + +error: `slug` not specified + --> $DIR/session-derive-errors.rs:114:1 + | +LL | / #[error(code = "E0456")] +LL | | struct SlugNotProvided {} + | |_________________________^ + | + = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug + +error: the `#[primary_span]` attribute can only be applied to fields of type `Span` + --> $DIR/session-derive-errors.rs:124:5 | - = help: use the [code = "..."] attribute to set this diagnostic's error code +LL | #[primary_span] + | ^^^^^^^^^^^^^^^ -error: the `#[message = "..."]` attribute can only be applied to fields of type Span - --> $DIR/session-derive-errors.rs:101:5 +error: `#[nonsense]` is not a valid `SessionDiagnostic` field attribute + --> $DIR/session-derive-errors.rs:132:5 | -LL | #[message = "this message is applied to a String field"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[nonsense] + | ^^^^^^^^^^^ + +error: the `#[label = ...]` attribute can only be applied to fields of type `Span` + --> $DIR/session-derive-errors.rs:149:5 + | +LL | #[label = "bar"] + | ^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/session-derive-errors.rs:108:1 + --> $DIR/session-derive-errors.rs:157:42 | -LL | #[message = "This error has a field, and references {name}"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[suggestion(message = "bar", code = "{name}")] + | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/session-derive-errors.rs:116:1 + --> $DIR/session-derive-errors.rs:162:16 | LL | #[derive(SessionDiagnostic)] - | ----------------- in this derive macro expansion -LL | #[error = "E0123"] - | - because of this opening brace -LL | #[message = "This is missing a closing brace: {name"] - | ^ expected `'}'` in format string + | - ^ expected `'}'` in format string + | | + | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/session-derive-errors.rs:125:1 + --> $DIR/session-derive-errors.rs:172:15 | LL | #[derive(SessionDiagnostic)] - | ----------------- in this derive macro expansion -LL | #[error = "E0123"] -LL | #[message = "This is missing an opening brace: name}"] - | ^ unmatched `}` in format string + | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: The `#[label = ...]` attribute can only be applied to fields of type Span - --> $DIR/session-derive-errors.rs:144:5 +error: the `#[label = ...]` attribute can only be applied to fields of type `Span` + --> $DIR/session-derive-errors.rs:192:5 | -LL | #[label = "See here"] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: `nonsense` is not a valid key for `#[suggestion(...)]` - --> $DIR/session-derive-errors.rs:169:18 - | -LL | #[suggestion(nonsense = "This is nonsense")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[label = "bar"] + | ^^^^^^^^^^^^^^^^ -error: `msg` is not a valid key for `#[suggestion(...)]` - --> $DIR/session-derive-errors.rs:177:18 +error: `#[suggestion(nonsense = ...)]` is not a valid `SessionDiagnostic` field attribute + --> $DIR/session-derive-errors.rs:217:18 | -LL | #[suggestion(msg = "This is a suggestion")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[suggestion(nonsense = "bar")] + | ^^^^^^^^^^^^^^^^ -error: missing suggestion message - --> $DIR/session-derive-errors.rs:185:7 - | -LL | #[suggestion(code = "This is suggested code")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: `#[suggestion(msg = ...)]` is not a valid `SessionDiagnostic` field attribute + --> $DIR/session-derive-errors.rs:225:18 | - = help: provide a suggestion message using #[suggestion(message = "...")] +LL | #[suggestion(msg = "bar")] + | ^^^^^^^^^^^ error: wrong field type for suggestion - --> $DIR/session-derive-errors.rs:200:5 + --> $DIR/session-derive-errors.rs:247:5 | -LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] +LL | / #[suggestion(message = "bar", code = "This is suggested code")] LL | | LL | | suggestion: Applicability, | |_____________________________^ | - = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability) + = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` -error: type of field annotated with `#[suggestion(...)]` contains more than one Span - --> $DIR/session-derive-errors.rs:215:5 +error: type of field annotated with `#[suggestion(...)]` contains more than one `Span` + --> $DIR/session-derive-errors.rs:262:5 | -LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] +LL | / #[suggestion(message = "bar", code = "This is suggested code")] LL | | LL | | suggestion: (Span, Span, Applicability), | |___________________________________________^ error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability - --> $DIR/session-derive-errors.rs:223:5 + --> $DIR/session-derive-errors.rs:270:5 | -LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] +LL | / #[suggestion(message = "bar", code = "This is suggested code")] LL | | LL | | suggestion: (Applicability, Applicability, Span), | |____________________________________________________^ -error: invalid annotation list `#[label(...)]` - --> $DIR/session-derive-errors.rs:231:7 +error: `#[label(...)]` is not a valid `SessionDiagnostic` field attribute + --> $DIR/session-derive-errors.rs:278:5 | -LL | #[label("wrong kind of annotation for label")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[label("bar")] + | ^^^^^^^^^^^^^^^ + +error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:399:1 + | +LL | #[help] + | ^^^^^^^ + +error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:407:1 + | +LL | #[help = "bar"] + | ^^^^^^^^^^^^^^^ + +error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:415:1 + | +LL | #[note] + | ^^^^^^^ + +error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:423:1 + | +LL | #[note = "bar"] + | ^^^^^^^^^^^^^^^ + +error: cannot find attribute `nonsense` in this scope + --> $DIR/session-derive-errors.rs:51:3 + | +LL | #[nonsense(code = "E0123", slug = "foo")] + | ^^^^^^^^ + +error: cannot find attribute `nonsense` in this scope + --> $DIR/session-derive-errors.rs:132:7 + | +LL | #[nonsense] + | ^^^^^^^^ + +error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope + --> $DIR/session-derive-errors.rs:322:10 + | +LL | struct Hello {} + | ------------ method `into_diagnostic_arg` not found for this +... +LL | #[derive(SessionDiagnostic)] + | ^^^^^^^^^^^^^^^^^ method not found in `Hello` + | + = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 18 previous errors +error: aborting due to 37 previous errors +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/error-codes/E0184.stderr b/src/test/ui/error-codes/E0184.stderr index 5bfeaa58bdf..bb3017b6ec2 100644 --- a/src/test/ui/error-codes/E0184.stderr +++ b/src/test/ui/error-codes/E0184.stderr @@ -2,7 +2,7 @@ error[E0184]: the trait `Copy` may not be implemented for this type; the type ha --> $DIR/E0184.rs:1:10 | LL | #[derive(Copy)] - | ^^^^ Copy not allowed on types with destructors + | ^^^^ `Copy` not allowed on types with destructors | = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/exclusive-drop-and-copy.stderr b/src/test/ui/exclusive-drop-and-copy.stderr index 36ee6570e42..8649c8abbfa 100644 --- a/src/test/ui/exclusive-drop-and-copy.stderr +++ b/src/test/ui/exclusive-drop-and-copy.stderr @@ -2,7 +2,7 @@ error[E0184]: the trait `Copy` may not be implemented for this type; the type ha --> $DIR/exclusive-drop-and-copy.rs:3:10 | LL | #[derive(Copy, Clone)] - | ^^^^ Copy not allowed on types with destructors + | ^^^^ `Copy` not allowed on types with destructors | = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -10,7 +10,7 @@ error[E0184]: the trait `Copy` may not be implemented for this type; the type ha --> $DIR/exclusive-drop-and-copy.rs:10:10 | LL | #[derive(Copy, Clone)] - | ^^^^ Copy not allowed on types with destructors + | ^^^^ `Copy` not allowed on types with destructors | = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs index c71e9f10f79..cc354b50afa 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs @@ -3,11 +3,12 @@ use clippy_utils::higher::IfLetOrMatch; use clippy_utils::visitors::is_local_used; use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq}; use if_chain::if_chain; +use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Arm, Expr, Guard, HirId, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{MultiSpan, Span}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -129,8 +130,8 @@ fn check_arm<'tcx>( &msg, |diag| { let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); - help_span.push_span_label(binding_span, "replace this binding".into()); - help_span.push_span_label(inner_then_pat.span, "with this pattern".into()); + help_span.push_span_label(binding_span, "replace this binding"); + help_span.push_span_label(inner_then_pat.span, "with this pattern"); diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern"); }, ); diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 703aa458f44..92cf82bcd6a 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::{Applicability, Handler, SuggestionStyle}; +use rustc_errors::{Applicability, Handler, MultiSpan, SuggestionStyle}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Expr}; @@ -25,7 +25,7 @@ use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; -use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span}; +use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span}; use rustc_span::{sym, FileName, Pos}; use std::io; use std::ops::Range; @@ -621,7 +621,19 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let filename = FileName::anon_source_code(&code); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(Box::new(io::sink()), None, false, false, false, None, false); + let fallback_bundle = rustc_errors::fallback_fluent_bundle(false) + .expect("failed to load fallback fluent bundle"); + let emitter = EmitterWriter::new( + Box::new(io::sink()), + None, + None, + fallback_bundle, + false, + false, + false, + None, + false, + ); let handler = Handler::with_emitter(false, None, Box::new(emitter)); let sess = ParseSess::with_span_handler(handler, sm); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index 06190850bb0..ddaffc75188 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; @@ -14,7 +14,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Ty}; use rustc_span::sym; -use rustc_span::{MultiSpan, Span}; +use rustc_span::Span; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -102,7 +102,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo // Suggest replacing iter_call with iter_replacement, and removing stmt let mut span = MultiSpan::from_span(method_name.ident.span); - span.push_span_label(iter_call.span, "the iterator could be used here instead".into()); + span.push_span_label(iter_call.span, "the iterator could be used here instead"); span_lint_hir_and_then( cx, super::NEEDLESS_COLLECT, diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index ecc9acf4445..06209bfe7b0 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -148,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { - cx.tcx.sess.span_err(span, &err); + cx.tcx.sess.span_err(span, err.as_ref()); } } else { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 5eb7b0f0521..d29d07da7b0 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -235,11 +235,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - &snippet_opt(cx, span) + snippet_opt(cx, span) .map_or( "change the call to".into(), |x| Cow::from(format!("change `{}` to", x)), - ), + ) + .as_ref(), suggestion.into(), Applicability::Unspecified, ); @@ -264,11 +265,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - &snippet_opt(cx, span) + snippet_opt(cx, span) .map_or( "change the call to".into(), |x| Cow::from(format!("change `{}` to", x)) - ), + ) + .as_ref(), suggestion.into(), Applicability::Unspecified, ); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 9d4313827f7..5f453dc1655 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -5,7 +5,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths}; use if_chain::if_chain; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdMap; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -19,8 +19,8 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_span::symbol::Symbol; -use rustc_span::{sym, MultiSpan}; use std::fmt; use std::iter; diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 625a53899df..b142397f71b 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,10 +8,10 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic}; +use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic, MultiSpan}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; -use rustc_span::source_map::{MultiSpan, Span}; +use rustc_span::source_map::Span; use std::env; fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { @@ -155,7 +155,13 @@ where }); } -pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { +pub fn span_lint_hir( + cx: &LateContext<'_>, + lint: &'static Lint, + hir_id: HirId, + sp: Span, + msg: &str, +) { cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { let mut diag = diag.build(msg); docs_link(&mut diag, lint); @@ -272,9 +278,14 @@ pub fn span_lint_and_sugg_for_edges( let sugg_lines_count = sugg.lines().count(); if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES { let sm = cx.sess().source_map(); - if let (Ok(line_upper), Ok(line_bottom)) = (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi())) { + if let (Ok(line_upper), Ok(line_bottom)) = + (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi())) + { let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2; - let span_upper = sm.span_until_char(sp.with_hi(line_upper.sf.lines[line_upper.line + split_idx]), '\n'); + let span_upper = sm.span_until_char( + sp.with_hi(line_upper.sf.lines[line_upper.line + split_idx]), + '\n', + ); let span_bottom = sp.with_lo(line_bottom.sf.lines[line_bottom.line - split_idx]); let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>(); diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 855a6a6ef6a..bc1b0d74575 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -165,9 +165,13 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Separate the output with an empty line eprintln!(); + let fallback_bundle = rustc_errors::fallback_fluent_bundle(false) + .expect("failed to load fallback fluent bundle"); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( rustc_errors::ColorConfig::Auto, None, + None, + fallback_bundle, false, false, None, @@ -191,7 +195,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { ]; for note in &xs { - handler.note_without_error(note); + handler.note_without_error(note.as_ref()); } // If backtraces are enabled, also print the query stack diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 7571e6d078a..7125b2ee685 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -33,6 +33,12 @@ impl Emitter for SilentEmitter { None } fn emit_diagnostic(&mut self, _db: &Diagnostic) {} + fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + None + } + fn fallback_fluent_bundle(&self) -> &Lrc<rustc_errors::FluentBundle> { + panic!("silent emitter attempted to translate a diagnostic"); + } } fn silent_emitter() -> Box<dyn Emitter + Send> { @@ -82,6 +88,14 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } self.handle_non_ignoreable_error(db); } + + fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + self.emitter.fluent_bundle() + } + + fn fallback_fluent_bundle(&self) -> &Lrc<rustc_errors::FluentBundle> { + self.emitter.fallback_fluent_bundle() + } } fn default_handler( @@ -100,9 +114,13 @@ fn default_handler( let emitter = if hide_parse_errors { silent_emitter() } else { + let fallback_bundle = rustc_errors::fallback_fluent_bundle(false) + .expect("failed to load fallback fluent bundle"); Box::new(EmitterWriter::stderr( color_cfg, Some(source_map.clone()), + None, + fallback_bundle, false, false, None, @@ -313,7 +331,8 @@ mod tests { use super::*; use crate::config::IgnoreList; use crate::utils::mk_sp; - use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName}; + use rustc_errors::MultiSpan; + use rustc_span::{FileName as SourceMapFileName, RealFileName}; use std::path::PathBuf; use std::sync::atomic::AtomicU32; @@ -328,6 +347,12 @@ mod tests { fn emit_diagnostic(&mut self, _db: &Diagnostic) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } + fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + None + } + fn fallback_fluent_bundle(&self) -> &Lrc<rustc_errors::FluentBundle> { + panic!("test emitter attempted to translate a diagnostic"); + } } fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> Diagnostic { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index ab4be43e495..ea6e01e577c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -38,6 +38,8 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("bitmaps", "MPL-2.0+"), // cargo via im-rc ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("snap", "BSD-3-Clause"), // rustc + ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) + ("self_cell", "Apache-2.0"), // rustc (fluent translations) // FIXME: this dependency violates the documentation comment above: ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target ]; @@ -113,6 +115,9 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "filetime", "fixedbitset", "flate2", + "fluent-bundle", + "fluent-langneg", + "fluent-syntax", "fortanix-sgx-abi", "generic-array", "getopts", @@ -125,6 +130,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "if_chain", "indexmap", "instant", + "intl-memoizer", + "intl_pluralrules", "itertools", "itoa", "jobserver", @@ -157,6 +164,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "pkg-config", "polonius-engine", "ppv-lite86", + "proc-macro-hack", "proc-macro2", "psm", "punycode", @@ -184,6 +192,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "ryu", "scoped-tls", "scopeguard", + "self_cell", "semver", "serde", "serde_derive", @@ -200,9 +209,12 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "tempfile", "termcolor", "termize", + "thiserror", + "thiserror-impl", "thorin-dwp", "thread_local", "time", + "tinystr", "tinyvec", "tracing", "tracing-attributes", @@ -210,11 +222,16 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "tracing-log", "tracing-subscriber", "tracing-tree", + "type-map", "typenum", "unic-char-property", "unic-char-range", "unic-common", "unic-emoji-char", + "unic-langid", + "unic-langid-impl", + "unic-langid-macros", + "unic-langid-macros-impl", "unic-ucd-version", "unicode-normalization", "unicode-script", @@ -228,7 +245,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "winapi-i686-pc-windows-gnu", "winapi-util", "winapi-x86_64-pc-windows-gnu", - // this is a false-positive: it's only used by rustfmt, but because it's enabled through a feature, tidy thinks it's used by rustc as well. + // this is a false-positive: it's only used by rustfmt, but because it's enabled through a + // feature, tidy thinks it's used by rustc as well. "yansi-term", ]; |
