mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #101138 - Rejyr:diagnostic-migration-rustc-lint-pt2, r=davidtwco
Migrate `rustc_lint` lint diagnostics Part 2 of [Migrate `rustc_lint` errors to `SessionDiagnostic`](https://github.com/rust-lang/rust/pull/100776) r? `@davidtwco` # TODO - [x] Refactor some lints manually implementing `DecorateLint` to use `Option<Subdiagnostic>`. - [x] Add `#[rustc_lint_diagnostics]` to lint functions in `context.rs`. - [x] Migrate `hidden_unicode_codepoints.rs`. - [x] Migrate `UnsafeCode` in `builtin.rs`. - [x] Migrate the rest of `builtin.rs`.
This commit is contained in:
@@ -15,6 +15,43 @@ lint_enum_intrinsics_mem_variant =
|
||||
|
||||
lint_expectation = this lint expectation is unfulfilled
|
||||
.note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
|
||||
.rationale = {$rationale}
|
||||
|
||||
lint_for_loops_over_fallibles =
|
||||
for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
|
||||
.suggestion = consider using `if let` to clear intent
|
||||
.remove_next = to iterate over `{$recv_snip}` remove the call to `next`
|
||||
.use_while_let = to check pattern in a loop use `while let`
|
||||
.use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
|
||||
|
||||
lint_non_binding_let_on_sync_lock =
|
||||
non-binding let on a synchronization lock
|
||||
|
||||
lint_non_binding_let_on_drop_type =
|
||||
non-binding let on a type that implements `Drop`
|
||||
|
||||
lint_non_binding_let_suggestion =
|
||||
consider binding to an unused variable to avoid immediately dropping the value
|
||||
|
||||
lint_non_binding_let_multi_suggestion =
|
||||
consider immediately dropping the value
|
||||
|
||||
lint_deprecated_lint_name =
|
||||
lint name `{$name}` is deprecated and may not have an effect in the future.
|
||||
.suggestion = change it to
|
||||
|
||||
lint_renamed_or_removed_lint = {$msg}
|
||||
.suggestion = use the new name
|
||||
|
||||
lint_unknown_lint =
|
||||
unknown lint: `{$name}`
|
||||
.suggestion = did you mean
|
||||
|
||||
lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
|
||||
|
||||
lint_unknown_gated_lint =
|
||||
unknown lint: `{$name}`
|
||||
.note = the `{$name}` lint is unstable
|
||||
|
||||
lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
|
||||
.label = this {$label} contains {$count ->
|
||||
@@ -55,6 +92,8 @@ lint_diag_out_of_impl =
|
||||
|
||||
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
||||
|
||||
lint_bad_opt_access = {$msg}
|
||||
|
||||
lint_cstring_ptr = getting the inner pointer of a temporary `CString`
|
||||
.as_ptr_label = this pointer will be invalid
|
||||
.unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||
@@ -331,6 +370,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be
|
||||
.suggestion = try naming the parameter or explicitly ignoring it
|
||||
|
||||
lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
|
||||
.msg_suggestion = {$msg}
|
||||
.default_suggestion = remove this attribute
|
||||
lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
|
||||
lint_builtin_deprecated_attr_default_suggestion = remove this attribute
|
||||
|
||||
@@ -391,10 +432,16 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n
|
||||
.note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
|
||||
.help = consider using `min_{$name}` instead, which is more stable and complete
|
||||
|
||||
lint_builtin_clashing_extern_same_name = `{$this_fi}` redeclared with a different signature
|
||||
lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
|
||||
lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized
|
||||
|
||||
lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
|
||||
lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
||||
|
||||
lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature
|
||||
.previous_decl_label = `{$orig}` previously declared here
|
||||
.mismatch_label = this signature doesn't match the previous declaration
|
||||
lint_builtin_clashing_extern_diff_name = `{$this_fi}` redeclares `{$orig}` with a different signature
|
||||
lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
|
||||
.previous_decl_label = `{$orig}` previously declared here
|
||||
.mismatch_label = this signature doesn't match the previous declaration
|
||||
|
||||
@@ -403,6 +450,16 @@ lint_builtin_deref_nullptr = dereferencing a null pointer
|
||||
|
||||
lint_builtin_asm_labels = avoid using named labels in inline assembly
|
||||
|
||||
lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
|
||||
.note = lib.rs is the root of this crate's library target
|
||||
.help = to refer to it from other targets, use the library's name as the path
|
||||
|
||||
lint_builtin_special_module_name_used_main = found module declaration for main.rs
|
||||
.note = a binary crate cannot be used as library
|
||||
|
||||
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
|
||||
.label = target type is set here
|
||||
|
||||
lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
|
||||
.label = overruled by previous forbid
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||
@@ -118,41 +118,23 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
// to an array or to a slice.
|
||||
_ => bug!("array type coerced to something other than array or slice"),
|
||||
};
|
||||
cx.struct_span_lint(
|
||||
let sub = if self.for_expr_span == expr.span {
|
||||
Some(ArrayIntoIterDiagSub::RemoveIntoIter {
|
||||
span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
})
|
||||
} else if receiver_ty.is_array() {
|
||||
Some(ArrayIntoIterDiagSub::UseExplicitIntoIter {
|
||||
start_span: expr.span.shrink_to_lo(),
|
||||
end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
ARRAY_INTO_ITER,
|
||||
call.ident.span,
|
||||
fluent::lint_array_into_iter,
|
||||
|diag| {
|
||||
diag.set_arg("target", target);
|
||||
diag.span_suggestion(
|
||||
call.ident.span,
|
||||
fluent::use_iter_suggestion,
|
||||
"iter",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if self.for_expr_span == expr.span {
|
||||
diag.span_suggestion(
|
||||
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
fluent::remove_into_iter_suggestion,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if receiver_ty.is_array() {
|
||||
diag.multipart_suggestion(
|
||||
fluent::use_explicit_into_iter_suggestion,
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
|
||||
(
|
||||
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
")".into(),
|
||||
),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag
|
||||
},
|
||||
)
|
||||
ArrayIntoIterDiag { target, suggestion: call.ident.span, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+252
-477
@@ -22,6 +22,23 @@
|
||||
|
||||
use crate::{
|
||||
errors::BuiltinEllpisisInclusiveRangePatterns,
|
||||
lints::{
|
||||
BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern,
|
||||
BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
|
||||
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
|
||||
BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
|
||||
BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures,
|
||||
BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents,
|
||||
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
|
||||
BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
|
||||
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
|
||||
BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
|
||||
BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue,
|
||||
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit,
|
||||
BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
|
||||
BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
|
||||
BuiltinWhileTrue, SuggestChangingAssocTypes,
|
||||
},
|
||||
types::{transparent_newtype_field, CItemKind},
|
||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
@@ -33,10 +50,7 @@
|
||||
use rustc_ast_pretty::pprust::{self, expr_to_string};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{
|
||||
fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
|
||||
DiagnosticStyledString, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{fluent, Applicability, DecorateLint, MultiSpan};
|
||||
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
@@ -110,25 +124,17 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
&& !cond.span.from_expansion()
|
||||
{
|
||||
let condition_span = e.span.with_hi(cond.span.hi());
|
||||
cx.struct_span_lint(
|
||||
WHILE_TRUE,
|
||||
condition_span,
|
||||
fluent::lint_builtin_while_true,
|
||||
|lint| {
|
||||
lint.span_suggestion_short(
|
||||
condition_span,
|
||||
fluent::suggestion,
|
||||
format!(
|
||||
let replace = format!(
|
||||
"{}loop",
|
||||
label.map_or_else(String::new, |label| format!(
|
||||
"{}: ",
|
||||
label.ident,
|
||||
))
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
},
|
||||
)
|
||||
);
|
||||
cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue {
|
||||
suggestion: condition_span,
|
||||
replace,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,12 +170,7 @@ fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
|
||||
for leaf in ty.walk() {
|
||||
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
|
||||
if leaf_ty.is_box() {
|
||||
cx.struct_span_lint(
|
||||
BOX_POINTERS,
|
||||
span,
|
||||
fluent::lint_builtin_box_pointers,
|
||||
|lint| lint.set_arg("ty", ty),
|
||||
);
|
||||
cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,19 +268,13 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
|
||||
if cx.tcx.find_field_index(ident, &variant)
|
||||
== Some(cx.typeck_results().field_index(fieldpat.hir_id))
|
||||
{
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
NON_SHORTHAND_FIELD_PATTERNS,
|
||||
fieldpat.span,
|
||||
fluent::lint_builtin_non_shorthand_field_patterns,
|
||||
|lint| {
|
||||
let suggested_ident =
|
||||
format!("{}{}", binding_annot.prefix_str(), ident);
|
||||
lint.set_arg("ident", ident).span_suggestion(
|
||||
fieldpat.span,
|
||||
fluent::suggestion,
|
||||
suggested_ident,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
BuiltinNonShorthandFieldPatterns {
|
||||
ident,
|
||||
suggestion: fieldpat.span,
|
||||
prefix: binding_annot.prefix_str(),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -321,48 +316,21 @@ fn report_unsafe(
|
||||
&self,
|
||||
cx: &EarlyContext<'_>,
|
||||
span: Span,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
decorate: impl for<'a, 'b> FnOnce(
|
||||
&'b mut DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut DiagnosticBuilder<'a, ()>,
|
||||
decorate: impl for<'a> DecorateLint<'a, ()>,
|
||||
) {
|
||||
// This comes from a macro that has `#[allow_internal_unsafe]`.
|
||||
if span.allows_unsafe() {
|
||||
return;
|
||||
}
|
||||
|
||||
cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate);
|
||||
}
|
||||
|
||||
fn report_overridden_symbol_name(
|
||||
&self,
|
||||
cx: &EarlyContext<'_>,
|
||||
span: Span,
|
||||
msg: DiagnosticMessage,
|
||||
) {
|
||||
self.report_unsafe(cx, span, msg, |lint| {
|
||||
lint.note(fluent::lint_builtin_overridden_symbol_name)
|
||||
})
|
||||
}
|
||||
|
||||
fn report_overridden_symbol_section(
|
||||
&self,
|
||||
cx: &EarlyContext<'_>,
|
||||
span: Span,
|
||||
msg: DiagnosticMessage,
|
||||
) {
|
||||
self.report_unsafe(cx, span, msg, |lint| {
|
||||
lint.note(fluent::lint_builtin_overridden_symbol_section)
|
||||
})
|
||||
cx.emit_spanned_lint(UNSAFE_CODE, span, decorate);
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for UnsafeCode {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
if attr.has_name(sym::allow_internal_unsafe) {
|
||||
self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| {
|
||||
lint
|
||||
});
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +339,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
if let ast::ExprKind::Block(ref blk, _) = e.kind {
|
||||
// Don't warn about generated blocks; that'll just pollute the output.
|
||||
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
|
||||
self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint);
|
||||
self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,62 +347,38 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
|
||||
match it.kind {
|
||||
ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
|
||||
self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint)
|
||||
self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
|
||||
self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint)
|
||||
self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
|
||||
}
|
||||
|
||||
ast::ItemKind::Fn(..) => {
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
|
||||
self.report_overridden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_no_mangle_fn,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
|
||||
}
|
||||
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
|
||||
self.report_overridden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_export_name_fn,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
|
||||
}
|
||||
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
|
||||
self.report_overridden_symbol_section(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_link_section_fn,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Static(..) => {
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
|
||||
self.report_overridden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_no_mangle_static,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
|
||||
}
|
||||
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
|
||||
self.report_overridden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_export_name_static,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
|
||||
}
|
||||
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
|
||||
self.report_overridden_symbol_section(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_link_section_static,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,18 +389,10 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
|
||||
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
|
||||
if let ast::AssocItemKind::Fn(..) = it.kind {
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
|
||||
self.report_overridden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_no_mangle_method,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
|
||||
}
|
||||
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
|
||||
self.report_overridden_symbol_name(
|
||||
cx,
|
||||
attr.span,
|
||||
fluent::lint_builtin_export_name_method,
|
||||
);
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,13 +407,13 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast
|
||||
body,
|
||||
) = fk
|
||||
{
|
||||
let msg = match ctxt {
|
||||
let decorator = match ctxt {
|
||||
FnCtxt::Foreign => return,
|
||||
FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn,
|
||||
FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method,
|
||||
FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method,
|
||||
FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn,
|
||||
FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod,
|
||||
FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod,
|
||||
};
|
||||
self.report_unsafe(cx, span, msg, |lint| lint);
|
||||
self.report_unsafe(cx, span, decorator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,11 +514,10 @@ fn check_missing_docs_attrs(
|
||||
let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
|
||||
let has_doc = attrs.iter().any(has_doc);
|
||||
if !has_doc {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
MISSING_DOCS,
|
||||
cx.tcx.def_span(def_id),
|
||||
fluent::lint_builtin_missing_doc,
|
||||
|lint| lint.set_arg("article", article).set_arg("desc", desc),
|
||||
BuiltinMissingDoc { article, desc },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -799,12 +734,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
cx.struct_span_lint(
|
||||
MISSING_COPY_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
fluent::lint_builtin_missing_copy_impl,
|
||||
|lint| lint,
|
||||
)
|
||||
cx.emit_spanned_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -878,11 +808,10 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
}
|
||||
|
||||
if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
fluent::lint_builtin_missing_debug_impl,
|
||||
|lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
|
||||
BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -958,19 +887,11 @@ fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
|
||||
} else {
|
||||
("<type>", Applicability::HasPlaceholders)
|
||||
};
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
ANONYMOUS_PARAMETERS,
|
||||
arg.pat.span,
|
||||
fluent::lint_builtin_anonymous_params,
|
||||
|lint| {
|
||||
lint.span_suggestion(
|
||||
arg.pat.span,
|
||||
fluent::suggestion,
|
||||
format!("_: {}", ty_snip),
|
||||
appl,
|
||||
)
|
||||
},
|
||||
)
|
||||
BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1005,42 +926,30 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
_,
|
||||
) = gate
|
||||
{
|
||||
// FIXME(davidtwco) translatable deprecated attr
|
||||
cx.struct_span_lint(
|
||||
let suggestion = match suggestion {
|
||||
Some(msg) => {
|
||||
BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
|
||||
}
|
||||
None => {
|
||||
BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
|
||||
}
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
DEPRECATED,
|
||||
attr.span,
|
||||
fluent::lint_builtin_deprecated_attr_link,
|
||||
|lint| {
|
||||
lint.set_arg("name", name)
|
||||
.set_arg("reason", reason)
|
||||
.set_arg("link", link)
|
||||
.span_suggestion_short(
|
||||
attr.span,
|
||||
suggestion.map(|s| s.into()).unwrap_or(
|
||||
fluent::lint_builtin_deprecated_attr_default_suggestion,
|
||||
),
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
},
|
||||
BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
DEPRECATED,
|
||||
attr.span,
|
||||
fluent::lint_builtin_deprecated_attr_used,
|
||||
|lint| {
|
||||
lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
|
||||
.span_suggestion_short(
|
||||
attr.span,
|
||||
fluent::lint_builtin_deprecated_attr_default_suggestion,
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
BuiltinDeprecatedAttrUsed {
|
||||
name: pprust::path_to_string(&attr.get_normal_item().path),
|
||||
suggestion: attr.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1069,20 +978,18 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
|
||||
let span = sugared_span.take().unwrap_or(attr.span);
|
||||
|
||||
if is_doc_comment || attr.has_name(sym::doc) {
|
||||
cx.struct_span_lint(
|
||||
let sub = match attr.kind {
|
||||
AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
|
||||
BuiltinUnusedDocCommentSub::PlainHelp
|
||||
}
|
||||
AttrKind::DocComment(CommentKind::Block, _) => {
|
||||
BuiltinUnusedDocCommentSub::BlockHelp
|
||||
}
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
UNUSED_DOC_COMMENTS,
|
||||
span,
|
||||
fluent::lint_builtin_unused_doc_comment,
|
||||
|lint| {
|
||||
lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help(
|
||||
match attr.kind {
|
||||
AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
|
||||
fluent::plain_help
|
||||
}
|
||||
AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help,
|
||||
},
|
||||
)
|
||||
},
|
||||
BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1197,20 +1104,10 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
NO_MANGLE_GENERIC_ITEMS,
|
||||
span,
|
||||
fluent::lint_builtin_no_mangle_generic,
|
||||
|lint| {
|
||||
lint.span_suggestion_short(
|
||||
no_mangle_attr.span,
|
||||
fluent::suggestion,
|
||||
"",
|
||||
// Use of `#[no_mangle]` suggests FFI intent; correct
|
||||
// fix may be to monomorphize source by hand
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
},
|
||||
BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span },
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -1225,30 +1122,23 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
}
|
||||
hir::ItemKind::Const(..) => {
|
||||
if cx.sess().contains_name(attrs, sym::no_mangle) {
|
||||
// account for "pub const" (#45562)
|
||||
let start = cx
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(it.span)
|
||||
.map(|snippet| snippet.find("const").unwrap_or(0))
|
||||
.unwrap_or(0) as u32;
|
||||
// `const` is 5 chars
|
||||
let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
|
||||
|
||||
// Const items do not refer to a particular location in memory, and therefore
|
||||
// don't have anything to attach a symbol to
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
NO_MANGLE_CONST_ITEMS,
|
||||
it.span,
|
||||
fluent::lint_builtin_const_no_mangle,
|
||||
|lint| {
|
||||
// account for "pub const" (#45562)
|
||||
let start = cx
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(it.span)
|
||||
.map(|snippet| snippet.find("const").unwrap_or(0))
|
||||
.unwrap_or(0) as u32;
|
||||
// `const` is 5 chars
|
||||
let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
|
||||
lint.span_suggestion(
|
||||
const_span,
|
||||
fluent::suggestion,
|
||||
"pub static",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
},
|
||||
BuiltinConstNoMangle { suggestion },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1309,12 +1199,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
|
||||
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
|
||||
{
|
||||
if from_mutbl < to_mutbl {
|
||||
cx.struct_span_lint(
|
||||
MUTABLE_TRANSMUTES,
|
||||
expr.span,
|
||||
fluent::lint_builtin_mutable_transmutes,
|
||||
|lint| lint,
|
||||
);
|
||||
cx.emit_spanned_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1362,12 +1247,7 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
if attr.has_name(sym::feature) {
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
cx.struct_span_lint(
|
||||
UNSTABLE_FEATURES,
|
||||
item.span(),
|
||||
fluent::lint_builtin_unstable_features,
|
||||
|lint| lint,
|
||||
);
|
||||
cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1422,20 +1302,10 @@ fn check_fn(
|
||||
// Now, check if the function has the `#[track_caller]` attribute
|
||||
&& let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller))
|
||||
{
|
||||
cx.struct_span_lint(
|
||||
UNGATED_ASYNC_FN_TRACK_CALLER,
|
||||
attr.span,
|
||||
fluent::lint_ungated_async_fn_track_caller,
|
||||
|lint| {
|
||||
lint.span_label(span, fluent::label);
|
||||
rustc_session::parse::add_feature_diagnostics(
|
||||
lint,
|
||||
&cx.tcx.sess.parse_sess,
|
||||
sym::closure_track_caller,
|
||||
);
|
||||
lint
|
||||
},
|
||||
);
|
||||
cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
|
||||
label: span,
|
||||
parse_sess: &cx.tcx.sess.parse_sess,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1493,18 +1363,13 @@ fn perform_lint(
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
}
|
||||
let def_span = cx.tcx.def_span(def_id);
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
UNREACHABLE_PUB,
|
||||
def_span,
|
||||
fluent::lint_builtin_unreachable_pub,
|
||||
|lint| {
|
||||
lint.set_arg("what", what);
|
||||
|
||||
lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability);
|
||||
if exportable {
|
||||
lint.help(fluent::help);
|
||||
}
|
||||
lint
|
||||
BuiltinUnreachablePub {
|
||||
what,
|
||||
suggestion: (vis_span, applicability),
|
||||
help: exportable.then_some(()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1569,7 +1434,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
|
||||
);
|
||||
|
||||
impl TypeAliasBounds {
|
||||
fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
|
||||
pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
|
||||
match *qpath {
|
||||
hir::QPath::TypeRelative(ref ty, _) => {
|
||||
// If this is a type variable, we found a `T::Assoc`.
|
||||
@@ -1583,29 +1448,6 @@ fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
|
||||
hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) {
|
||||
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
|
||||
// bound. Let's see if this type does that.
|
||||
|
||||
// We use a HIR visitor to walk the type.
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
struct WalkAssocTypes<'a> {
|
||||
err: &'a mut Diagnostic,
|
||||
}
|
||||
impl Visitor<'_> for WalkAssocTypes<'_> {
|
||||
fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
|
||||
if TypeAliasBounds::is_type_variable_assoc(qpath) {
|
||||
self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
|
||||
}
|
||||
intravisit::walk_qpath(self, qpath, id)
|
||||
}
|
||||
}
|
||||
|
||||
// Let's go for a walk!
|
||||
let mut visitor = WalkAssocTypes { err };
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||
@@ -1639,35 +1481,31 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
|
||||
let mut suggested_changing_assoc_types = false;
|
||||
if !where_spans.is_empty() {
|
||||
cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| {
|
||||
lint.set_span(where_spans);
|
||||
lint.span_suggestion(
|
||||
type_alias_generics.where_clause_span,
|
||||
fluent::suggestion,
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if !suggested_changing_assoc_types {
|
||||
TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
|
||||
suggested_changing_assoc_types = true;
|
||||
}
|
||||
lint
|
||||
let sub = (!suggested_changing_assoc_types).then(|| {
|
||||
suggested_changing_assoc_types = true;
|
||||
SuggestChangingAssocTypes { ty }
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
where_spans,
|
||||
BuiltinTypeAliasWhereClause {
|
||||
suggestion: type_alias_generics.where_clause_span,
|
||||
sub,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if !inline_spans.is_empty() {
|
||||
cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| {
|
||||
lint.set_span(inline_spans);
|
||||
lint.multipart_suggestion(
|
||||
fluent::suggestion,
|
||||
inline_sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if !suggested_changing_assoc_types {
|
||||
TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
|
||||
}
|
||||
lint
|
||||
let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg };
|
||||
let sub = (!suggested_changing_assoc_types).then(|| {
|
||||
suggested_changing_assoc_types = true;
|
||||
SuggestChangingAssocTypes { ty }
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
inline_spans,
|
||||
BuiltinTypeAliasGenericBounds { suggestion, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1767,14 +1605,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
TypeWellFormedFromEnv(..) => continue,
|
||||
};
|
||||
if predicate.is_global() {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
TRIVIAL_BOUNDS,
|
||||
span,
|
||||
fluent::lint_builtin_trivial_bounds,
|
||||
|lint| {
|
||||
lint.set_arg("predicate_kind_name", predicate_kind_name)
|
||||
.set_arg("predicate", predicate)
|
||||
},
|
||||
BuiltinTrivialBounds { predicate_kind_name, predicate },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1875,8 +1709,6 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)>
|
||||
};
|
||||
|
||||
if let Some((start, end, join)) = endpoints {
|
||||
let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns;
|
||||
let suggestion = fluent::suggestion;
|
||||
if parenthesise {
|
||||
self.node_id = Some(pat.id);
|
||||
let end = expr_to_string(&end);
|
||||
@@ -1891,14 +1723,14 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)>
|
||||
replace,
|
||||
});
|
||||
} else {
|
||||
cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| {
|
||||
lint.span_suggestion(
|
||||
pat.span,
|
||||
suggestion,
|
||||
cx.emit_spanned_lint(
|
||||
ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
|
||||
pat.span,
|
||||
BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise {
|
||||
suggestion: pat.span,
|
||||
replace,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let replace = "..=";
|
||||
@@ -1909,14 +1741,13 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)>
|
||||
replace: replace.to_string(),
|
||||
});
|
||||
} else {
|
||||
cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| {
|
||||
lint.span_suggestion_short(
|
||||
join,
|
||||
suggestion,
|
||||
replace,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
|
||||
join,
|
||||
BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise {
|
||||
suggestion: join,
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1996,12 +1827,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
|
||||
let attrs = cx.tcx.hir().attrs(it.hir_id());
|
||||
if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
|
||||
cx.struct_span_lint(
|
||||
UNNAMEABLE_TEST_ITEMS,
|
||||
attr.span,
|
||||
fluent::lint_builtin_unnameable_test_items,
|
||||
|lint| lint,
|
||||
);
|
||||
cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2117,18 +1943,10 @@ fn check_ident_token(
|
||||
return;
|
||||
}
|
||||
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
KEYWORD_IDENTS,
|
||||
ident.span,
|
||||
fluent::lint_builtin_keyword_idents,
|
||||
|lint| {
|
||||
lint.set_arg("kw", ident).set_arg("next", next_edition).span_suggestion(
|
||||
ident.span,
|
||||
fluent::suggestion,
|
||||
format!("r#{}", ident),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
},
|
||||
BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2405,16 +2223,15 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
lint_spans.clone(),
|
||||
fluent::lint_builtin_explicit_outlives,
|
||||
|lint| {
|
||||
lint.set_arg("count", bound_count).multipart_suggestion(
|
||||
fluent::suggestion,
|
||||
lint_spans.into_iter().map(|span| (span, String::new())).collect(),
|
||||
BuiltinExplicitOutlives {
|
||||
count: bound_count,
|
||||
suggestion: BuiltinExplicitOutlivesSuggestion {
|
||||
spans: lint_spans,
|
||||
applicability,
|
||||
)
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -2463,24 +2280,18 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
|
||||
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
|
||||
.filter(|(&name, _)| features.incomplete(name))
|
||||
.for_each(|(&name, &span)| {
|
||||
cx.struct_span_lint(
|
||||
let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
|
||||
.map(|n| BuiltinIncompleteFeaturesNote { n });
|
||||
let help = if HAS_MIN_FEATURES.contains(&name) {
|
||||
Some(BuiltinIncompleteFeaturesHelp)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
INCOMPLETE_FEATURES,
|
||||
span,
|
||||
fluent::lint_builtin_incomplete_features,
|
||||
|lint| {
|
||||
lint.set_arg("name", name);
|
||||
if let Some(n) =
|
||||
rustc_feature::find_feature_issue(name, GateIssue::Language)
|
||||
{
|
||||
lint.set_arg("n", n);
|
||||
lint.note(fluent::note);
|
||||
}
|
||||
if HAS_MIN_FEATURES.contains(&name) {
|
||||
lint.help(fluent::help);
|
||||
}
|
||||
lint
|
||||
},
|
||||
)
|
||||
BuiltinIncompleteFeatures { name, note, help },
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2525,6 +2336,36 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
|
||||
|
||||
declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
|
||||
|
||||
/// Information about why a type cannot be initialized this way.
|
||||
pub struct InitError {
|
||||
pub(crate) message: String,
|
||||
/// Spans from struct fields and similar that can be obtained from just the type.
|
||||
pub(crate) span: Option<Span>,
|
||||
/// Used to report a trace through adts.
|
||||
pub(crate) nested: Option<Box<InitError>>,
|
||||
}
|
||||
impl InitError {
|
||||
fn spanned(self, span: Span) -> InitError {
|
||||
Self { span: Some(span), ..self }
|
||||
}
|
||||
|
||||
fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
|
||||
assert!(self.nested.is_none());
|
||||
Self { nested: nested.into().map(Box::new), ..self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for InitError {
|
||||
fn from(s: &'a str) -> Self {
|
||||
s.to_owned().into()
|
||||
}
|
||||
}
|
||||
impl From<String> for InitError {
|
||||
fn from(message: String) -> Self {
|
||||
Self { message, span: None, nested: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@@ -2533,36 +2374,6 @@ enum InitKind {
|
||||
Uninit,
|
||||
}
|
||||
|
||||
/// Information about why a type cannot be initialized this way.
|
||||
struct InitError {
|
||||
message: String,
|
||||
/// Spans from struct fields and similar that can be obtained from just the type.
|
||||
span: Option<Span>,
|
||||
/// Used to report a trace through adts.
|
||||
nested: Option<Box<InitError>>,
|
||||
}
|
||||
impl InitError {
|
||||
fn spanned(self, span: Span) -> InitError {
|
||||
Self { span: Some(span), ..self }
|
||||
}
|
||||
|
||||
fn nested(self, nested: impl Into<Option<InitError>>) -> InitError {
|
||||
assert!(self.nested.is_none());
|
||||
Self { nested: nested.into().map(Box::new), ..self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for InitError {
|
||||
fn from(s: &'a str) -> Self {
|
||||
s.to_owned().into()
|
||||
}
|
||||
}
|
||||
impl From<String> for InitError {
|
||||
fn from(message: String) -> Self {
|
||||
Self { message, span: None, nested: None }
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if this constant is all-0.
|
||||
fn is_zero(expr: &hir::Expr<'_>) -> bool {
|
||||
use hir::ExprKind::*;
|
||||
@@ -2786,46 +2597,16 @@ fn ty_find_init_error<'tcx>(
|
||||
// using zeroed or uninitialized memory.
|
||||
// We are extremely conservative with what we warn about.
|
||||
let conjured_ty = cx.typeck_results().expr_ty(expr);
|
||||
if let Some(mut err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
|
||||
{
|
||||
// FIXME(davidtwco): make translatable
|
||||
cx.struct_span_lint(
|
||||
if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
|
||||
let msg = match init {
|
||||
InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
|
||||
InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint,
|
||||
};
|
||||
let sub = BuiltinUnpermittedTypeInitSub { err };
|
||||
cx.emit_spanned_lint(
|
||||
INVALID_VALUE,
|
||||
expr.span,
|
||||
DelayDm(|| {
|
||||
format!(
|
||||
"the type `{}` does not permit {}",
|
||||
conjured_ty,
|
||||
match init {
|
||||
InitKind::Zeroed => "zero-initialization",
|
||||
InitKind::Uninit => "being left uninitialized",
|
||||
},
|
||||
)
|
||||
}),
|
||||
|lint| {
|
||||
lint.span_label(
|
||||
expr.span,
|
||||
"this code causes undefined behavior when executed",
|
||||
);
|
||||
lint.span_label(
|
||||
expr.span,
|
||||
"help: use `MaybeUninit<T>` instead, \
|
||||
and only call `assume_init` after initialization is done",
|
||||
);
|
||||
loop {
|
||||
if let Some(span) = err.span {
|
||||
lint.span_note(span, &err.message);
|
||||
} else {
|
||||
lint.note(&err.message);
|
||||
}
|
||||
if let Some(e) = err.nested {
|
||||
err = *e;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lint
|
||||
},
|
||||
BuiltinUnpermittedTypeInit { msg, ty: conjured_ty, label: expr.span, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3171,31 +2952,39 @@ fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignI
|
||||
SymbolName::Normal(_) => fi.span,
|
||||
SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
|
||||
};
|
||||
// Finally, emit the diagnostic.
|
||||
|
||||
let msg = if orig.get_name() == this_fi.ident.name {
|
||||
fluent::lint_builtin_clashing_extern_same_name
|
||||
} else {
|
||||
fluent::lint_builtin_clashing_extern_diff_name
|
||||
// Finally, emit the diagnostic.
|
||||
let this = this_fi.ident.name;
|
||||
let orig = orig.get_name();
|
||||
let previous_decl_label = get_relevant_span(orig_fi);
|
||||
let mismatch_label = get_relevant_span(this_fi);
|
||||
let sub = BuiltinClashingExternSub {
|
||||
tcx,
|
||||
expected: existing_decl_ty,
|
||||
found: this_decl_ty,
|
||||
};
|
||||
tcx.struct_span_lint_hir(
|
||||
let decorator = if orig == this {
|
||||
BuiltinClashingExtern::SameName {
|
||||
this,
|
||||
orig,
|
||||
previous_decl_label,
|
||||
mismatch_label,
|
||||
sub,
|
||||
}
|
||||
} else {
|
||||
BuiltinClashingExtern::DiffName {
|
||||
this,
|
||||
orig,
|
||||
previous_decl_label,
|
||||
mismatch_label,
|
||||
sub,
|
||||
}
|
||||
};
|
||||
tcx.emit_spanned_lint(
|
||||
CLASHING_EXTERN_DECLARATIONS,
|
||||
this_fi.hir_id(),
|
||||
get_relevant_span(this_fi),
|
||||
msg,
|
||||
|lint| {
|
||||
let mut expected_str = DiagnosticStyledString::new();
|
||||
expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
|
||||
let mut found_str = DiagnosticStyledString::new();
|
||||
found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
|
||||
|
||||
lint.set_arg("this_fi", this_fi.ident.name)
|
||||
.set_arg("orig", orig.get_name())
|
||||
.span_label(get_relevant_span(orig_fi), fluent::previous_decl_label)
|
||||
.span_label(get_relevant_span(this_fi), fluent::mismatch_label)
|
||||
// FIXME(davidtwco): translatable expected/found
|
||||
.note_expected_found(&"", expected_str, &"", found_str)
|
||||
},
|
||||
decorator,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3275,11 +3064,10 @@ fn is_zero(expr: &hir::Expr<'_>) -> bool {
|
||||
|
||||
if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
|
||||
if is_null_ptr(cx, expr_deref) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
DEREF_NULLPTR,
|
||||
expr.span,
|
||||
fluent::lint_builtin_deref_nullptr,
|
||||
|lint| lint.span_label(expr.span, fluent::label),
|
||||
BuiltinDerefNullptr { label: expr.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3324,6 +3112,7 @@ fn is_zero(expr: &hir::Expr<'_>) -> bool {
|
||||
declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if let hir::Expr {
|
||||
kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
|
||||
@@ -3464,16 +3253,17 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
|
||||
}
|
||||
|
||||
match item.ident.name.as_str() {
|
||||
"lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| {
|
||||
lint
|
||||
.note("lib.rs is the root of this crate's library target")
|
||||
.help("to refer to it from other targets, use the library's name as the path")
|
||||
}),
|
||||
"main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| {
|
||||
lint
|
||||
.note("a binary crate cannot be used as library")
|
||||
}),
|
||||
_ => continue
|
||||
"lib" => cx.emit_spanned_lint(
|
||||
SPECIAL_MODULE_NAME,
|
||||
item.span,
|
||||
BuiltinSpecialModuleNameUsed::Lib,
|
||||
),
|
||||
"main" => cx.emit_spanned_lint(
|
||||
SPECIAL_MODULE_NAME,
|
||||
item.span,
|
||||
BuiltinSpecialModuleNameUsed::Main,
|
||||
),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3489,31 +3279,16 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
|
||||
let cfg = &cx.sess().parse_sess.config;
|
||||
let check_cfg = &cx.sess().parse_sess.check_config;
|
||||
for &(name, value) in cfg {
|
||||
if let Some(names_valid) = &check_cfg.names_valid {
|
||||
if !names_valid.contains(&name) {
|
||||
cx.lookup(
|
||||
UNEXPECTED_CFGS,
|
||||
None::<MultiSpan>,
|
||||
fluent::lint_builtin_unexpected_cli_config_name,
|
||||
|diag| diag.help(fluent::help).set_arg("name", name),
|
||||
);
|
||||
}
|
||||
if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
|
||||
cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
|
||||
name,
|
||||
});
|
||||
}
|
||||
if let Some(value) = value {
|
||||
if let Some(values) = &check_cfg.values_valid.get(&name) {
|
||||
if !values.contains(&value) {
|
||||
cx.lookup(
|
||||
UNEXPECTED_CFGS,
|
||||
None::<MultiSpan>,
|
||||
fluent::lint_builtin_unexpected_cli_config_value,
|
||||
|diag| {
|
||||
diag.help(fluent::help)
|
||||
.set_arg("name", name)
|
||||
.set_arg("value", value)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
|
||||
cx.emit_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
BuiltinUnexpectedCliConfigValue { name, value },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,6 +965,7 @@ fn lint(
|
||||
/// Note that this function should only be called for [`LintExpectationId`]s
|
||||
/// retrieved from the current lint pass. Buffered or manually created ids can
|
||||
/// cause ICEs.
|
||||
#[rustc_lint_diagnostics]
|
||||
fn fulfill_expectation(&self, expectation: LintExpectationId) {
|
||||
// We need to make sure that submitted expectation ids are correctly fulfilled suppressed
|
||||
// and stored between compilation sessions. To not manually do these steps, we simply create
|
||||
@@ -1011,6 +1012,7 @@ fn lints(&self) -> &LintStore {
|
||||
&*self.lint_store
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
fn lookup<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
@@ -1045,6 +1047,7 @@ fn lints(&self) -> &LintStore {
|
||||
self.builder.lint_store()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
fn lookup<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use crate::{
|
||||
lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel},
|
||||
LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
|
||||
use rustc_errors::DelayDm;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::{traits::util::supertraits, ty};
|
||||
use rustc_span::sym;
|
||||
@@ -71,22 +73,14 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
&& supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
|
||||
.any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
|
||||
{
|
||||
cx.struct_span_lint(
|
||||
DEREF_INTO_DYN_SUPERTRAIT,
|
||||
cx.tcx.def_span(item.owner_id.def_id),
|
||||
DelayDm(|| {
|
||||
format!(
|
||||
"`{t}` implements `Deref` with supertrait `{target_principal}` as target"
|
||||
)
|
||||
}),
|
||||
|lint| {
|
||||
if let Some(target_span) = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) {
|
||||
lint.span_label(target_span, "target type is set here");
|
||||
}
|
||||
|
||||
lint
|
||||
},
|
||||
)
|
||||
let label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel {
|
||||
label,
|
||||
});
|
||||
cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget {
|
||||
t,
|
||||
target_principal: target_principal.to_string(),
|
||||
label,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
|
||||
impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
||||
// This always-inlined function is for the hot call site.
|
||||
#[inline(always)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn inlined_check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{context::LintContext, LateContext, LateLintPass};
|
||||
use rustc_errors::fluent;
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
lints::{EnumIntrinsicsMemDiscriminate, EnumIntrinsicsMemVariant},
|
||||
LateContext, LateLintPass,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::{visit::TypeVisitable, Ty};
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
@@ -50,11 +53,10 @@ fn enforce_mem_discriminant(
|
||||
) {
|
||||
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
|
||||
if is_non_enum(ty_param) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
ENUM_INTRINSICS_NON_ENUMS,
|
||||
expr_span,
|
||||
fluent::lint_enum_intrinsics_mem_discriminant,
|
||||
|lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note),
|
||||
EnumIntrinsicsMemDiscriminate { ty_param, note: args_span },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -62,11 +64,10 @@ fn enforce_mem_discriminant(
|
||||
fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
|
||||
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
|
||||
if is_non_enum(ty_param) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
ENUM_INTRINSICS_NON_ENUMS,
|
||||
span,
|
||||
fluent::lint_enum_intrinsics_mem_variant,
|
||||
|lint| lint.set_arg("ty_param", ty_param).note(fluent::note),
|
||||
EnumIntrinsicsMemVariant { ty_param },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_overruled_attribute, code = "E0453")]
|
||||
pub struct OverruledAttribute {
|
||||
pub struct OverruledAttribute<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub overruled: Span,
|
||||
pub lint_level: String,
|
||||
pub lint_level: &'a str,
|
||||
pub lint_source: Symbol,
|
||||
#[subdiagnostic]
|
||||
pub sub: OverruledAttributeSub,
|
||||
@@ -38,6 +38,7 @@ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
OverruledAttributeSub::NodeSource { span, reason } => {
|
||||
diag.span_label(span, fluent::lint_node_source);
|
||||
if let Some(rationale) = reason {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(rationale.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::builtin;
|
||||
use rustc_errors::fluent;
|
||||
use rustc_hir::HirId;
|
||||
use crate::lints::{Expectation, ExpectationNote};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
|
||||
use rustc_session::lint::LintExpectationId;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Symbol;
|
||||
@@ -28,34 +27,17 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
||||
if !fulfilled_expectations.contains(&id)
|
||||
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
|
||||
{
|
||||
emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation);
|
||||
let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
|
||||
let note = expectation.is_unfulfilled_lint_expectations.then_some(());
|
||||
tcx.emit_spanned_lint(
|
||||
UNFULFILLED_LINT_EXPECTATIONS,
|
||||
*hir_id,
|
||||
expectation.emission_span,
|
||||
Expectation { rationale, note },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
unreachable!("at this stage all `LintExpectationId`s are stable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_unfulfilled_expectation_lint(
|
||||
tcx: TyCtxt<'_>,
|
||||
hir_id: HirId,
|
||||
expectation: &LintExpectation,
|
||||
) {
|
||||
tcx.struct_span_lint_hir(
|
||||
builtin::UNFULFILLED_LINT_EXPECTATIONS,
|
||||
hir_id,
|
||||
expectation.emission_span,
|
||||
fluent::lint_expectation,
|
||||
|lint| {
|
||||
if let Some(rationale) = expectation.reason {
|
||||
lint.note(rationale.as_str());
|
||||
}
|
||||
|
||||
if expectation.is_unfulfilled_lint_expectations {
|
||||
lint.note(fluent::note);
|
||||
}
|
||||
|
||||
lint
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use crate::{
|
||||
lints::{
|
||||
ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark,
|
||||
ForLoopsOverFalliblesSuggestion,
|
||||
},
|
||||
LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
|
||||
use hir::{Expr, Pat};
|
||||
use rustc_errors::{Applicability, DelayDm};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
|
||||
use rustc_middle::ty::{self, List};
|
||||
@@ -53,53 +58,29 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let msg = DelayDm(|| {
|
||||
format!(
|
||||
"for loop over {article} `{ty}`. This is more readably written as an `if let` statement",
|
||||
)
|
||||
});
|
||||
|
||||
cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| {
|
||||
if let Some(recv) = extract_iterator_next_call(cx, arg)
|
||||
let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
|
||||
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
|
||||
{
|
||||
lint.span_suggestion(
|
||||
recv.span.between(arg.span.shrink_to_hi()),
|
||||
format!("to iterate over `{recv_snip}` remove the call to `next`"),
|
||||
".by_ref()",
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip }
|
||||
} else {
|
||||
lint.multipart_suggestion_verbose(
|
||||
"to check pattern in a loop use `while let`",
|
||||
vec![
|
||||
// NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
|
||||
(expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
|
||||
(pat.span.between(arg.span), ") = ".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
}
|
||||
ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var }
|
||||
} ;
|
||||
let question_mark = if suggest_question_mark(cx, adt, substs, expr.span) {
|
||||
Some(ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let suggestion = ForLoopsOverFalliblesSuggestion {
|
||||
var,
|
||||
start_span: expr.span.with_hi(pat.span.lo()),
|
||||
end_span: pat.span.between(arg.span),
|
||||
};
|
||||
|
||||
if suggest_question_mark(cx, adt, substs, expr.span) {
|
||||
lint.span_suggestion(
|
||||
arg.span.shrink_to_hi(),
|
||||
"consider unwrapping the `Result` with `?` to iterate over its contents",
|
||||
"?",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
lint.multipart_suggestion_verbose(
|
||||
"consider using `if let` to clear intent",
|
||||
vec![
|
||||
// NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
|
||||
(expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
|
||||
(pat.span.between(arg.span), ") = ".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
})
|
||||
cx.emit_spanned_lint(
|
||||
FOR_LOOPS_OVER_FALLIBLES,
|
||||
arg.span,
|
||||
ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use crate::{
|
||||
lints::{
|
||||
HiddenUnicodeCodepointsDiag, HiddenUnicodeCodepointsDiagLabels,
|
||||
HiddenUnicodeCodepointsDiagSub,
|
||||
},
|
||||
EarlyContext, EarlyLintPass, LintContext,
|
||||
};
|
||||
use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{fluent, Applicability, SuggestionStyle};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
|
||||
declare_lint! {
|
||||
@@ -60,55 +65,19 @@ fn lint_text_direction_codepoint(
|
||||
})
|
||||
.collect();
|
||||
|
||||
cx.struct_span_lint(
|
||||
let count = spans.len();
|
||||
let labels = point_at_inner_spans
|
||||
.then_some(HiddenUnicodeCodepointsDiagLabels { spans: spans.clone() });
|
||||
let sub = if point_at_inner_spans && !spans.is_empty() {
|
||||
HiddenUnicodeCodepointsDiagSub::Escape { spans }
|
||||
} else {
|
||||
HiddenUnicodeCodepointsDiagSub::NoEscape { spans }
|
||||
};
|
||||
|
||||
cx.emit_spanned_lint(
|
||||
TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
|
||||
span,
|
||||
fluent::lint_hidden_unicode_codepoints,
|
||||
|lint| {
|
||||
lint.set_arg("label", label);
|
||||
lint.set_arg("count", spans.len());
|
||||
lint.span_label(span, fluent::label);
|
||||
lint.note(fluent::note);
|
||||
if point_at_inner_spans {
|
||||
for (c, span) in &spans {
|
||||
lint.span_label(*span, format!("{:?}", c));
|
||||
}
|
||||
}
|
||||
if point_at_inner_spans && !spans.is_empty() {
|
||||
lint.multipart_suggestion_with_style(
|
||||
fluent::suggestion_remove,
|
||||
spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
lint.multipart_suggestion(
|
||||
fluent::suggestion_escape,
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, span)| {
|
||||
let c = format!("{:?}", c);
|
||||
(span, c[1..c.len() - 1].to_string())
|
||||
})
|
||||
.collect(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We
|
||||
// should do the same here to provide the same good suggestions as we do for
|
||||
// literals above.
|
||||
lint.set_arg(
|
||||
"escaped",
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, _)| format!("{:?}", c))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
);
|
||||
lint.note(fluent::suggestion_remove);
|
||||
lint.note(fluent::no_suggestion_note_escape);
|
||||
}
|
||||
lint
|
||||
},
|
||||
HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
|
||||
//! Clippy.
|
||||
|
||||
use crate::lints::{
|
||||
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistantDocKeyword,
|
||||
QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
|
||||
use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
|
||||
@@ -29,20 +32,15 @@ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
|
||||
// don't lint imports, only actual usages
|
||||
return;
|
||||
}
|
||||
let replace = match cx.tcx.get_diagnostic_name(def_id) {
|
||||
let preferred = match cx.tcx.get_diagnostic_name(def_id) {
|
||||
Some(sym::HashMap) => "FxHashMap",
|
||||
Some(sym::HashSet) => "FxHashSet",
|
||||
_ => return,
|
||||
};
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
DEFAULT_HASH_TYPES,
|
||||
path.span,
|
||||
fluent::lint_default_hash_types,
|
||||
|lint| {
|
||||
lint.set_arg("preferred", replace)
|
||||
.set_arg("used", cx.tcx.item_name(def_id))
|
||||
.note(fluent::note)
|
||||
},
|
||||
DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -83,12 +81,11 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
|
||||
let def_id = instance.def_id();
|
||||
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
POTENTIAL_QUERY_INSTABILITY,
|
||||
span,
|
||||
fluent::lint_query_instability,
|
||||
|lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note),
|
||||
)
|
||||
QueryInstability { query: cx.tcx.item_name(def_id) },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,14 +123,8 @@ fn check_path(
|
||||
let span = path.span.with_hi(
|
||||
segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
|
||||
);
|
||||
cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| {
|
||||
lint
|
||||
.span_suggestion(
|
||||
span,
|
||||
fluent::suggestion,
|
||||
"ty",
|
||||
Applicability::MaybeIncorrect, // ty maybe needs an import
|
||||
)
|
||||
cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind {
|
||||
suggestion: span,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -190,39 +181,17 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
|
||||
|
||||
match span {
|
||||
Some(span) => {
|
||||
cx.struct_span_lint(
|
||||
USAGE_OF_TY_TYKIND,
|
||||
path.span,
|
||||
fluent::lint_tykind_kind,
|
||||
|lint| lint.span_suggestion(
|
||||
span,
|
||||
fluent::suggestion,
|
||||
"ty",
|
||||
Applicability::MaybeIncorrect, // ty maybe needs an import
|
||||
)
|
||||
)
|
||||
cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind {
|
||||
suggestion: span,
|
||||
});
|
||||
},
|
||||
None => cx.struct_span_lint(
|
||||
USAGE_OF_TY_TYKIND,
|
||||
path.span,
|
||||
fluent::lint_tykind,
|
||||
|lint| lint.help(fluent::help)
|
||||
)
|
||||
}
|
||||
} else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
|
||||
if path.segments.len() > 1 {
|
||||
cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| {
|
||||
lint
|
||||
.set_arg("ty", t.clone())
|
||||
.span_suggestion(
|
||||
path.span,
|
||||
fluent::suggestion,
|
||||
t,
|
||||
// The import probably needs to be changed
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
})
|
||||
None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
|
||||
}
|
||||
} else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
|
||||
cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified {
|
||||
ty: t.clone(),
|
||||
suggestion: path.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -303,12 +272,11 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||
&& call_site.ctxt().outer_expn_data().kind
|
||||
!= ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
|
||||
{
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
LINT_PASS_IMPL_WITHOUT_MACRO,
|
||||
lint_pass.path.span,
|
||||
fluent::lint_lintpass_by_hand,
|
||||
|lint| lint.help(fluent::help),
|
||||
)
|
||||
LintPassByHand,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,17 +306,16 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for nested in list {
|
||||
if nested.has_name(sym::keyword) {
|
||||
let v = nested
|
||||
let keyword = nested
|
||||
.value_str()
|
||||
.expect("#[doc(keyword = \"...\")] expected a value!");
|
||||
if is_doc_keyword(v) {
|
||||
if is_doc_keyword(keyword) {
|
||||
return;
|
||||
}
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
EXISTING_DOC_KEYWORD,
|
||||
attr.span,
|
||||
fluent::lint_non_existant_doc_keyword,
|
||||
|lint| lint.set_arg("keyword", v).help(fluent::help),
|
||||
NonExistantDocKeyword { keyword },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -407,12 +374,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
}
|
||||
debug!(?found_impl);
|
||||
if !found_parent_with_attr && !found_impl {
|
||||
cx.struct_span_lint(
|
||||
DIAGNOSTIC_OUTSIDE_OF_IMPL,
|
||||
span,
|
||||
fluent::lint_diag_out_of_impl,
|
||||
|lint| lint,
|
||||
)
|
||||
cx.emit_spanned_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
|
||||
}
|
||||
|
||||
let mut found_diagnostic_message = false;
|
||||
@@ -428,12 +390,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
}
|
||||
debug!(?found_diagnostic_message);
|
||||
if !found_parent_with_attr && !found_diagnostic_message {
|
||||
cx.struct_span_lint(
|
||||
UNTRANSLATABLE_DIAGNOSTIC,
|
||||
span,
|
||||
fluent::lint_untranslatable_diag,
|
||||
|lint| lint,
|
||||
)
|
||||
cx.emit_spanned_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,9 +422,9 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
let Some(lit) = item.lit() &&
|
||||
let ast::LitKind::Str(val, _) = lit.kind
|
||||
{
|
||||
cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint|
|
||||
lint
|
||||
);
|
||||
cx.emit_spanned_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag {
|
||||
msg: val.as_str(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan};
|
||||
use crate::{
|
||||
lints::{NonBindingLet, NonBindingLetSub},
|
||||
LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::Symbol;
|
||||
@@ -119,6 +122,11 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let sub = NonBindingLetSub {
|
||||
suggestion: local.pat.span,
|
||||
multi_suggestion_start: local.span.until(init.span),
|
||||
multi_suggestion_end: init.span.shrink_to_hi(),
|
||||
};
|
||||
if is_sync_lock {
|
||||
let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]);
|
||||
span.push_span_label(
|
||||
@@ -129,41 +137,14 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
|
||||
init.span,
|
||||
"this binding will immediately drop the value assigned to it".to_string(),
|
||||
);
|
||||
cx.struct_span_lint(
|
||||
LET_UNDERSCORE_LOCK,
|
||||
span,
|
||||
"non-binding let on a synchronization lock",
|
||||
|lint| build_lint(lint, local, init.span),
|
||||
)
|
||||
cx.emit_spanned_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub });
|
||||
} else {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
LET_UNDERSCORE_DROP,
|
||||
local.span,
|
||||
"non-binding let on a type that implements `Drop`",
|
||||
|lint| build_lint(lint, local, init.span),
|
||||
)
|
||||
NonBindingLet::DropType { sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_lint<'a, 'b>(
|
||||
lint: &'a mut DiagnosticBuilder<'b, ()>,
|
||||
local: &hir::Local<'_>,
|
||||
init_span: rustc_span::Span,
|
||||
) -> &'a mut DiagnosticBuilder<'b, ()> {
|
||||
lint.span_suggestion_verbose(
|
||||
local.pat.span,
|
||||
"consider binding to an unused variable to avoid immediately dropping the value",
|
||||
"_unused",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.multipart_suggestion(
|
||||
"consider immediately dropping the value",
|
||||
vec![
|
||||
(local.span.until(init_span), "drop(".to_string()),
|
||||
(init_span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
use crate::context::{CheckLintNameResult, LintStore};
|
||||
use crate::late::unerased_lint_store;
|
||||
use crate::lints::{
|
||||
DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint,
|
||||
RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion,
|
||||
};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
|
||||
use rustc_errors::{fluent, DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::HirId;
|
||||
@@ -15,6 +19,7 @@
|
||||
};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{RegisteredTools, TyCtxt};
|
||||
use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
|
||||
use rustc_session::lint::{
|
||||
builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS},
|
||||
Level, Lint, LintExpectationId, LintId,
|
||||
@@ -583,57 +588,32 @@ fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) {
|
||||
old_src,
|
||||
id_name
|
||||
);
|
||||
|
||||
let decorate_diag = |diag: &mut Diagnostic| {
|
||||
diag.span_label(src.span(), "overruled by previous forbid");
|
||||
match old_src {
|
||||
LintLevelSource::Default => {
|
||||
diag.note(&format!(
|
||||
"`forbid` lint level is the default for {}",
|
||||
id.to_string()
|
||||
));
|
||||
}
|
||||
LintLevelSource::Node { span, reason, .. } => {
|
||||
diag.span_label(span, "`forbid` level set here");
|
||||
if let Some(rationale) = reason {
|
||||
diag.note(rationale.as_str());
|
||||
}
|
||||
}
|
||||
LintLevelSource::CommandLine(_, _) => {
|
||||
diag.note("`forbid` lint level was set on command line");
|
||||
}
|
||||
let sub = match old_src {
|
||||
LintLevelSource::Default => {
|
||||
OverruledAttributeSub::DefaultSource { id: id.to_string() }
|
||||
}
|
||||
LintLevelSource::Node { span, reason, .. } => {
|
||||
OverruledAttributeSub::NodeSource { span, reason }
|
||||
}
|
||||
LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource,
|
||||
};
|
||||
if !fcw_warning {
|
||||
self.sess.emit_err(OverruledAttribute {
|
||||
span: src.span(),
|
||||
overruled: src.span(),
|
||||
lint_level: level.as_str().to_string(),
|
||||
lint_level: level.as_str(),
|
||||
lint_source: src.name(),
|
||||
sub: match old_src {
|
||||
LintLevelSource::Default => {
|
||||
OverruledAttributeSub::DefaultSource { id: id.to_string() }
|
||||
}
|
||||
LintLevelSource::Node { span, reason, .. } => {
|
||||
OverruledAttributeSub::NodeSource { span, reason }
|
||||
}
|
||||
LintLevelSource::CommandLine(_, _) => {
|
||||
OverruledAttributeSub::CommandLineSource
|
||||
}
|
||||
},
|
||||
sub,
|
||||
});
|
||||
} else {
|
||||
self.struct_lint(
|
||||
self.emit_spanned_lint(
|
||||
FORBIDDEN_LINT_GROUPS,
|
||||
Some(src.span().into()),
|
||||
format!(
|
||||
"{}({}) incompatible with previous forbid",
|
||||
level.as_str(),
|
||||
src.name(),
|
||||
),
|
||||
|lint| {
|
||||
decorate_diag(lint);
|
||||
lint
|
||||
src.span().into(),
|
||||
OverruledAtributeLint {
|
||||
overruled: src.span(),
|
||||
lint_level: level.as_str(),
|
||||
lint_source: src.name(),
|
||||
sub,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -858,25 +838,13 @@ fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id:
|
||||
}
|
||||
Err((Some(ids), ref new_lint_name)) => {
|
||||
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
||||
let (lvl, src) = self.provider.get_lint_level(lint, &sess);
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
self.emit_spanned_lint(
|
||||
lint,
|
||||
lvl,
|
||||
src,
|
||||
Some(sp.into()),
|
||||
format!(
|
||||
"lint name `{}` is deprecated \
|
||||
and may not have an effect in the future.",
|
||||
name
|
||||
),
|
||||
|lint| {
|
||||
lint.span_suggestion(
|
||||
sp,
|
||||
"change it to",
|
||||
new_lint_name,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
sp.into(),
|
||||
DeprecatedLintName {
|
||||
name,
|
||||
suggestion: sp,
|
||||
replace: &new_lint_name,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -917,54 +885,29 @@ fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id:
|
||||
_ if !self.warn_about_weird_lints => {}
|
||||
|
||||
CheckLintNameResult::Warning(msg, renamed) => {
|
||||
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
||||
let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess);
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
renamed_lint_level,
|
||||
src,
|
||||
Some(sp.into()),
|
||||
msg,
|
||||
|lint| {
|
||||
if let Some(new_name) = &renamed {
|
||||
lint.span_suggestion(
|
||||
sp,
|
||||
"use the new name",
|
||||
new_name,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
lint
|
||||
},
|
||||
let suggestion =
|
||||
renamed.as_ref().map(|replace| RenamedOrRemovedLintSuggestion {
|
||||
suggestion: sp,
|
||||
replace: replace.as_str(),
|
||||
});
|
||||
self.emit_spanned_lint(
|
||||
RENAMED_AND_REMOVED_LINTS,
|
||||
sp.into(),
|
||||
RenamedOrRemovedLint { msg, suggestion },
|
||||
);
|
||||
}
|
||||
CheckLintNameResult::NoLint(suggestion) => {
|
||||
let lint = builtin::UNKNOWN_LINTS;
|
||||
let (level, src) = self.provider.get_lint_level(lint, self.sess);
|
||||
let name = if let Some(tool_ident) = tool_ident {
|
||||
format!("{}::{}", tool_ident.name, name)
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(sp.into()),
|
||||
format!("unknown lint: `{}`", name),
|
||||
|lint| {
|
||||
if let Some(suggestion) = suggestion {
|
||||
lint.span_suggestion(
|
||||
sp,
|
||||
"did you mean",
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
lint
|
||||
},
|
||||
let suggestion = suggestion
|
||||
.map(|replace| UnknownLintSuggestion { suggestion: sp, replace });
|
||||
self.emit_spanned_lint(
|
||||
UNKNOWN_LINTS,
|
||||
sp.into(),
|
||||
UnknownLint { name, suggestion },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1010,20 +953,10 @@ fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id:
|
||||
continue
|
||||
};
|
||||
|
||||
let lint = builtin::UNUSED_ATTRIBUTES;
|
||||
let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess);
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
lint_level,
|
||||
lint_src,
|
||||
Some(lint_attr_span.into()),
|
||||
format!(
|
||||
"{}({}) is ignored unless specified at crate level",
|
||||
level.as_str(),
|
||||
lint_attr_name
|
||||
),
|
||||
|lint| lint,
|
||||
self.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
lint_attr_span.into(),
|
||||
IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name },
|
||||
);
|
||||
// don't set a separate error for every lint in the group
|
||||
break;
|
||||
@@ -1047,11 +980,10 @@ fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
|
||||
level,
|
||||
src,
|
||||
Some(span.into()),
|
||||
format!("unknown lint: `{}`", lint_id.lint.name_lower()),
|
||||
fluent::lint_unknown_gated_lint,
|
||||
|lint| {
|
||||
lint.note(
|
||||
&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),),
|
||||
);
|
||||
lint.set_arg("name", lint_id.lint.name_lower());
|
||||
lint.note(fluent::note);
|
||||
add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
|
||||
lint
|
||||
},
|
||||
@@ -1086,6 +1018,25 @@ pub(crate) fn struct_lint(
|
||||
let (level, src) = self.lint_level(lint);
|
||||
struct_lint_level(self.sess, lint, level, src, span, msg, decorate)
|
||||
}
|
||||
|
||||
pub fn emit_spanned_lint(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: MultiSpan,
|
||||
decorate: impl for<'a> DecorateLint<'a, ()>,
|
||||
) {
|
||||
let (level, src) = self.lint_level(lint);
|
||||
struct_lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| {
|
||||
decorate.decorate_lint(lint)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> DecorateLint<'a, ()>) {
|
||||
let (level, src) = self.lint_level(lint);
|
||||
struct_lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| {
|
||||
decorate.decorate_lint(lint)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
@@ -60,6 +62,7 @@
|
||||
mod late;
|
||||
mod let_underscore;
|
||||
mod levels;
|
||||
mod lints;
|
||||
mod methods;
|
||||
mod non_ascii_idents;
|
||||
mod non_fmt_panic;
|
||||
|
||||
@@ -0,0 +1,1479 @@
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use rustc_errors::{
|
||||
fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage,
|
||||
DiagnosticStyledString, SuggestionStyle,
|
||||
};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{Predicate, Ty, TyCtxt};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
|
||||
|
||||
use crate::{
|
||||
builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext,
|
||||
};
|
||||
|
||||
// array_into_iter.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_array_into_iter)]
|
||||
pub struct ArrayIntoIterDiag<'a> {
|
||||
pub target: &'a str,
|
||||
#[suggestion(use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<ArrayIntoIterDiagSub>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ArrayIntoIterDiagSub {
|
||||
#[suggestion(remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
|
||||
RemoveIntoIter {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(use_explicit_into_iter_suggestion, applicability = "maybe-incorrect")]
|
||||
UseExplicitIntoIter {
|
||||
#[suggestion_part(code = "IntoIterator::into_iter(")]
|
||||
start_span: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
end_span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
// builtin.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_while_true)]
|
||||
pub struct BuiltinWhileTrue {
|
||||
#[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
pub replace: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_box_pointers)]
|
||||
pub struct BuiltinBoxPointers<'a> {
|
||||
pub ty: Ty<'a>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_non_shorthand_field_patterns)]
|
||||
pub struct BuiltinNonShorthandFieldPatterns {
|
||||
pub ident: Ident,
|
||||
#[suggestion(code = "{prefix}{ident}", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
pub prefix: &'static str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum BuiltinUnsafe {
|
||||
#[diag(lint_builtin_allow_internal_unsafe)]
|
||||
AllowInternalUnsafe,
|
||||
#[diag(lint_builtin_unsafe_block)]
|
||||
UnsafeBlock,
|
||||
#[diag(lint_builtin_unsafe_trait)]
|
||||
UnsafeTrait,
|
||||
#[diag(lint_builtin_unsafe_impl)]
|
||||
UnsafeImpl,
|
||||
#[diag(lint_builtin_no_mangle_fn)]
|
||||
#[note(lint_builtin_overridden_symbol_name)]
|
||||
NoMangleFn,
|
||||
#[diag(lint_builtin_export_name_fn)]
|
||||
#[note(lint_builtin_overridden_symbol_name)]
|
||||
ExportNameFn,
|
||||
#[diag(lint_builtin_link_section_fn)]
|
||||
#[note(lint_builtin_overridden_symbol_section)]
|
||||
LinkSectionFn,
|
||||
#[diag(lint_builtin_no_mangle_static)]
|
||||
#[note(lint_builtin_overridden_symbol_name)]
|
||||
NoMangleStatic,
|
||||
#[diag(lint_builtin_export_name_static)]
|
||||
#[note(lint_builtin_overridden_symbol_name)]
|
||||
ExportNameStatic,
|
||||
#[diag(lint_builtin_link_section_static)]
|
||||
#[note(lint_builtin_overridden_symbol_section)]
|
||||
LinkSectionStatic,
|
||||
#[diag(lint_builtin_no_mangle_method)]
|
||||
#[note(lint_builtin_overridden_symbol_name)]
|
||||
NoMangleMethod,
|
||||
#[diag(lint_builtin_export_name_method)]
|
||||
#[note(lint_builtin_overridden_symbol_name)]
|
||||
ExportNameMethod,
|
||||
#[diag(lint_builtin_decl_unsafe_fn)]
|
||||
DeclUnsafeFn,
|
||||
#[diag(lint_builtin_decl_unsafe_method)]
|
||||
DeclUnsafeMethod,
|
||||
#[diag(lint_builtin_impl_unsafe_method)]
|
||||
ImplUnsafeMethod,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_missing_doc)]
|
||||
pub struct BuiltinMissingDoc<'a> {
|
||||
pub article: &'a str,
|
||||
pub desc: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_missing_copy_impl)]
|
||||
pub struct BuiltinMissingCopyImpl;
|
||||
|
||||
pub struct BuiltinMissingDebugImpl<'a> {
|
||||
pub tcx: TyCtxt<'a>,
|
||||
pub def_id: DefId,
|
||||
}
|
||||
|
||||
// Needed for def_path_str
|
||||
impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("debug", self.tcx.def_path_str(self.def_id));
|
||||
diag
|
||||
}
|
||||
|
||||
fn msg(&self) -> DiagnosticMessage {
|
||||
fluent::lint_builtin_missing_debug_impl
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_anonymous_params)]
|
||||
pub struct BuiltinAnonymousParams<'a> {
|
||||
#[suggestion(code = "_: {ty_snip}")]
|
||||
pub suggestion: (Span, Applicability),
|
||||
pub ty_snip: &'a str,
|
||||
}
|
||||
|
||||
// FIXME(davidtwco) translatable deprecated attr
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_deprecated_attr_link)]
|
||||
pub struct BuiltinDeprecatedAttrLink<'a> {
|
||||
pub name: Symbol,
|
||||
pub reason: &'a str,
|
||||
pub link: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
|
||||
#[suggestion(msg_suggestion, code = "", applicability = "machine-applicable")]
|
||||
Msg {
|
||||
#[primary_span]
|
||||
suggestion: Span,
|
||||
msg: &'a str,
|
||||
},
|
||||
#[suggestion(default_suggestion, code = "", applicability = "machine-applicable")]
|
||||
Default {
|
||||
#[primary_span]
|
||||
suggestion: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_deprecated_attr_used)]
|
||||
pub struct BuiltinDeprecatedAttrUsed {
|
||||
pub name: String,
|
||||
#[suggestion(
|
||||
lint_builtin_deprecated_attr_default_suggestion,
|
||||
style = "short",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unused_doc_comment)]
|
||||
pub struct BuiltinUnusedDocComment<'a> {
|
||||
pub kind: &'a str,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: BuiltinUnusedDocCommentSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum BuiltinUnusedDocCommentSub {
|
||||
#[help(plain_help)]
|
||||
PlainHelp,
|
||||
#[help(block_help)]
|
||||
BlockHelp,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_no_mangle_generic)]
|
||||
pub struct BuiltinNoMangleGeneric {
|
||||
// Use of `#[no_mangle]` suggests FFI intent; correct
|
||||
// fix may be to monomorphize source by hand
|
||||
#[suggestion(style = "short", code = "", applicability = "maybe-incorrect")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_const_no_mangle)]
|
||||
pub struct BuiltinConstNoMangle {
|
||||
#[suggestion(code = "pub static", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_mutable_transmutes)]
|
||||
pub struct BuiltinMutablesTransmutes;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unstable_features)]
|
||||
pub struct BuiltinUnstableFeatures;
|
||||
|
||||
// lint_ungated_async_fn_track_caller
|
||||
pub struct BuiltinUngatedAsyncFnTrackCaller<'a> {
|
||||
pub label: Span,
|
||||
pub parse_sess: &'a ParseSess,
|
||||
}
|
||||
|
||||
impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.span_label(self.label, fluent::label);
|
||||
rustc_session::parse::add_feature_diagnostics(
|
||||
diag,
|
||||
&self.parse_sess,
|
||||
sym::closure_track_caller,
|
||||
);
|
||||
diag
|
||||
}
|
||||
|
||||
fn msg(&self) -> DiagnosticMessage {
|
||||
fluent::lint_ungated_async_fn_track_caller
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unreachable_pub)]
|
||||
pub struct BuiltinUnreachablePub<'a> {
|
||||
pub what: &'a str,
|
||||
#[suggestion(code = "pub(crate)")]
|
||||
pub suggestion: (Span, Applicability),
|
||||
#[help]
|
||||
pub help: Option<()>,
|
||||
}
|
||||
|
||||
pub struct SuggestChangingAssocTypes<'a, 'b> {
|
||||
pub ty: &'a rustc_hir::Ty<'b>,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
|
||||
// bound. Let's see if this type does that.
|
||||
|
||||
// We use a HIR visitor to walk the type.
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
struct WalkAssocTypes<'a> {
|
||||
err: &'a mut rustc_errors::Diagnostic,
|
||||
}
|
||||
impl Visitor<'_> for WalkAssocTypes<'_> {
|
||||
fn visit_qpath(
|
||||
&mut self,
|
||||
qpath: &rustc_hir::QPath<'_>,
|
||||
id: rustc_hir::HirId,
|
||||
span: Span,
|
||||
) {
|
||||
if TypeAliasBounds::is_type_variable_assoc(qpath) {
|
||||
self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
|
||||
}
|
||||
intravisit::walk_qpath(self, qpath, id)
|
||||
}
|
||||
}
|
||||
|
||||
// Let's go for a walk!
|
||||
let mut visitor = WalkAssocTypes { err: diag };
|
||||
visitor.visit_ty(self.ty);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_type_alias_where_clause)]
|
||||
pub struct BuiltinTypeAliasWhereClause<'a, 'b> {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_type_alias_generic_bounds)]
|
||||
pub struct BuiltinTypeAliasGenericBounds<'a, 'b> {
|
||||
#[subdiagnostic]
|
||||
pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>,
|
||||
}
|
||||
|
||||
pub struct BuiltinTypeAliasGenericBoundsSuggestion {
|
||||
pub suggestions: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
diag.multipart_suggestion(
|
||||
fluent::suggestion,
|
||||
self.suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_trivial_bounds)]
|
||||
pub struct BuiltinTrivialBounds<'a> {
|
||||
pub predicate_kind_name: &'a str,
|
||||
pub predicate: Predicate<'a>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum BuiltinEllipsisInclusiveRangePatternsLint {
|
||||
#[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
|
||||
Parenthesise {
|
||||
#[suggestion(code = "{replace}", applicability = "machine-applicable")]
|
||||
suggestion: Span,
|
||||
replace: String,
|
||||
},
|
||||
#[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
|
||||
NonParenthesise {
|
||||
#[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
|
||||
suggestion: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unnameable_test_items)]
|
||||
pub struct BuiltinUnnameableTestItems;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_keyword_idents)]
|
||||
pub struct BuiltinKeywordIdents {
|
||||
pub kw: Ident,
|
||||
pub next: Edition,
|
||||
#[suggestion(code = "r#{kw}", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_explicit_outlives)]
|
||||
pub struct BuiltinExplicitOutlives {
|
||||
pub count: usize,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: BuiltinExplicitOutlivesSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(suggestion)]
|
||||
pub struct BuiltinExplicitOutlivesSuggestion {
|
||||
#[suggestion_part(code = "")]
|
||||
pub spans: Vec<Span>,
|
||||
#[applicability]
|
||||
pub applicability: Applicability,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_incomplete_features)]
|
||||
pub struct BuiltinIncompleteFeatures {
|
||||
pub name: Symbol,
|
||||
#[subdiagnostic]
|
||||
pub note: Option<BuiltinIncompleteFeaturesNote>,
|
||||
#[subdiagnostic]
|
||||
pub help: Option<BuiltinIncompleteFeaturesHelp>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(help)]
|
||||
pub struct BuiltinIncompleteFeaturesHelp;
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(note)]
|
||||
pub struct BuiltinIncompleteFeaturesNote {
|
||||
pub n: NonZeroU32,
|
||||
}
|
||||
|
||||
pub struct BuiltinUnpermittedTypeInit<'a> {
|
||||
pub msg: DiagnosticMessage,
|
||||
pub ty: Ty<'a>,
|
||||
pub label: Span,
|
||||
pub sub: BuiltinUnpermittedTypeInitSub,
|
||||
}
|
||||
|
||||
impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("ty", self.ty);
|
||||
diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
|
||||
diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label_suggestion);
|
||||
self.sub.add_to_diagnostic(diag);
|
||||
diag
|
||||
}
|
||||
|
||||
fn msg(&self) -> rustc_errors::DiagnosticMessage {
|
||||
self.msg.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(davidtwco): make translatable
|
||||
pub struct BuiltinUnpermittedTypeInitSub {
|
||||
pub err: InitError,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
let mut err = self.err;
|
||||
loop {
|
||||
if let Some(span) = err.span {
|
||||
diag.span_note(span, err.message);
|
||||
} else {
|
||||
diag.note(err.message);
|
||||
}
|
||||
if let Some(e) = err.nested {
|
||||
err = *e;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum BuiltinClashingExtern<'a> {
|
||||
#[diag(lint_builtin_clashing_extern_same_name)]
|
||||
SameName {
|
||||
this: Symbol,
|
||||
orig: Symbol,
|
||||
#[label(previous_decl_label)]
|
||||
previous_decl_label: Span,
|
||||
#[label(mismatch_label)]
|
||||
mismatch_label: Span,
|
||||
#[subdiagnostic]
|
||||
sub: BuiltinClashingExternSub<'a>,
|
||||
},
|
||||
#[diag(lint_builtin_clashing_extern_diff_name)]
|
||||
DiffName {
|
||||
this: Symbol,
|
||||
orig: Symbol,
|
||||
#[label(previous_decl_label)]
|
||||
previous_decl_label: Span,
|
||||
#[label(mismatch_label)]
|
||||
mismatch_label: Span,
|
||||
#[subdiagnostic]
|
||||
sub: BuiltinClashingExternSub<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
// FIXME(davidtwco): translatable expected/found
|
||||
pub struct BuiltinClashingExternSub<'a> {
|
||||
pub tcx: TyCtxt<'a>,
|
||||
pub expected: Ty<'a>,
|
||||
pub found: Ty<'a>,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for BuiltinClashingExternSub<'_> {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
let mut expected_str = DiagnosticStyledString::new();
|
||||
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
|
||||
let mut found_str = DiagnosticStyledString::new();
|
||||
found_str.push(self.found.fn_sig(self.tcx).to_string(), true);
|
||||
diag.note_expected_found(&"", expected_str, &"", found_str);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_deref_nullptr)]
|
||||
pub struct BuiltinDerefNullptr {
|
||||
#[label]
|
||||
pub label: Span,
|
||||
}
|
||||
|
||||
// FIXME: migrate fluent::lint::builtin_asm_labels
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum BuiltinSpecialModuleNameUsed {
|
||||
#[diag(lint_builtin_special_module_name_used_lib)]
|
||||
#[note]
|
||||
#[help]
|
||||
Lib,
|
||||
#[diag(lint_builtin_special_module_name_used_main)]
|
||||
#[note]
|
||||
Main,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unexpected_cli_config_name)]
|
||||
#[help]
|
||||
pub struct BuiltinUnexpectedCliConfigName {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unexpected_cli_config_value)]
|
||||
#[help]
|
||||
pub struct BuiltinUnexpectedCliConfigValue {
|
||||
pub name: Symbol,
|
||||
pub value: Symbol,
|
||||
}
|
||||
|
||||
// deref_into_dyn_supertrait.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_supertrait_as_deref_target)]
|
||||
pub struct SupertraitAsDerefTarget<'a> {
|
||||
pub t: Ty<'a>,
|
||||
pub target_principal: String,
|
||||
// pub target_principal: Binder<'a, ExistentialTraitRef<'b>>,
|
||||
#[subdiagnostic]
|
||||
pub label: Option<SupertraitAsDerefTargetLabel>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(label)]
|
||||
pub struct SupertraitAsDerefTargetLabel {
|
||||
#[primary_span]
|
||||
pub label: Span,
|
||||
}
|
||||
|
||||
// enum_intrinsics_non_enums.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_enum_intrinsics_mem_discriminant)]
|
||||
pub struct EnumIntrinsicsMemDiscriminate<'a> {
|
||||
pub ty_param: Ty<'a>,
|
||||
#[note]
|
||||
pub note: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_enum_intrinsics_mem_variant)]
|
||||
#[note]
|
||||
pub struct EnumIntrinsicsMemVariant<'a> {
|
||||
pub ty_param: Ty<'a>,
|
||||
}
|
||||
|
||||
// expect.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_expectation)]
|
||||
pub struct Expectation {
|
||||
#[subdiagnostic]
|
||||
pub rationale: Option<ExpectationNote>,
|
||||
#[note]
|
||||
pub note: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(rationale)]
|
||||
pub struct ExpectationNote {
|
||||
pub rationale: Symbol,
|
||||
}
|
||||
|
||||
// for_loops_over_fallibles.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_for_loops_over_fallibles)]
|
||||
pub struct ForLoopsOverFalliblesDiag<'a> {
|
||||
pub article: &'static str,
|
||||
pub ty: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub sub: ForLoopsOverFalliblesLoopSub<'a>,
|
||||
#[subdiagnostic]
|
||||
pub question_mark: Option<ForLoopsOverFalliblesQuestionMark>,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: ForLoopsOverFalliblesSuggestion<'a>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ForLoopsOverFalliblesLoopSub<'a> {
|
||||
#[suggestion(remove_next, code = ".by_ref()", applicability = "maybe-incorrect")]
|
||||
RemoveNext {
|
||||
#[primary_span]
|
||||
suggestion: Span,
|
||||
recv_snip: String,
|
||||
},
|
||||
#[multipart_suggestion(use_while_let, applicability = "maybe-incorrect")]
|
||||
UseWhileLet {
|
||||
#[suggestion_part(code = "while let {var}(")]
|
||||
start_span: Span,
|
||||
#[suggestion_part(code = ") = ")]
|
||||
end_span: Span,
|
||||
var: &'a str,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(use_question_mark, code = "?", applicability = "maybe-incorrect")]
|
||||
pub struct ForLoopsOverFalliblesQuestionMark {
|
||||
#[primary_span]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
|
||||
pub struct ForLoopsOverFalliblesSuggestion<'a> {
|
||||
pub var: &'a str,
|
||||
#[suggestion_part(code = "if let {var}(")]
|
||||
pub start_span: Span,
|
||||
#[suggestion_part(code = ") = ")]
|
||||
pub end_span: Span,
|
||||
}
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_hidden_unicode_codepoints)]
|
||||
#[note]
|
||||
pub struct HiddenUnicodeCodepointsDiag<'a> {
|
||||
pub label: &'a str,
|
||||
pub count: usize,
|
||||
#[label]
|
||||
pub span_label: Span,
|
||||
#[subdiagnostic]
|
||||
pub labels: Option<HiddenUnicodeCodepointsDiagLabels>,
|
||||
#[subdiagnostic]
|
||||
pub sub: HiddenUnicodeCodepointsDiagSub,
|
||||
}
|
||||
|
||||
pub struct HiddenUnicodeCodepointsDiagLabels {
|
||||
pub spans: Vec<(char, Span)>,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
for (c, span) in self.spans {
|
||||
diag.span_label(span, format!("{:?}", c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum HiddenUnicodeCodepointsDiagSub {
|
||||
Escape { spans: Vec<(char, Span)> },
|
||||
NoEscape { spans: Vec<(char, Span)> },
|
||||
}
|
||||
|
||||
// Used because of multiple multipart_suggestion and note
|
||||
impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
|
||||
diag.multipart_suggestion_with_style(
|
||||
fluent::suggestion_remove,
|
||||
spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
diag.multipart_suggestion(
|
||||
fluent::suggestion_escape,
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, span)| {
|
||||
let c = format!("{:?}", c);
|
||||
(span, c[1..c.len() - 1].to_string())
|
||||
})
|
||||
.collect(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => {
|
||||
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We
|
||||
// should do the same here to provide the same good suggestions as we do for
|
||||
// literals above.
|
||||
diag.set_arg(
|
||||
"escaped",
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, _)| format!("{:?}", c))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
);
|
||||
diag.note(fluent::suggestion_remove);
|
||||
diag.note(fluent::no_suggestion_note_escape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// internal.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_default_hash_types)]
|
||||
#[note]
|
||||
pub struct DefaultHashTypesDiag<'a> {
|
||||
pub preferred: &'a str,
|
||||
pub used: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_query_instability)]
|
||||
#[note]
|
||||
pub struct QueryInstability {
|
||||
pub query: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_tykind_kind)]
|
||||
pub struct TykindKind {
|
||||
#[suggestion(code = "ty", applicability = "maybe-incorrect")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_tykind)]
|
||||
#[help]
|
||||
pub struct TykindDiag;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_ty_qualified)]
|
||||
pub struct TyQualified {
|
||||
pub ty: String,
|
||||
#[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_lintpass_by_hand)]
|
||||
#[help]
|
||||
pub struct LintPassByHand;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_non_existant_doc_keyword)]
|
||||
#[help]
|
||||
pub struct NonExistantDocKeyword {
|
||||
pub keyword: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_diag_out_of_impl)]
|
||||
pub struct DiagOutOfImpl;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_untranslatable_diag)]
|
||||
pub struct UntranslatableDiag;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_bad_opt_access)]
|
||||
pub struct BadOptAccessDiag<'a> {
|
||||
pub msg: &'a str,
|
||||
}
|
||||
|
||||
// let_underscore.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum NonBindingLet {
|
||||
#[diag(lint_non_binding_let_on_sync_lock)]
|
||||
SyncLock {
|
||||
#[subdiagnostic]
|
||||
sub: NonBindingLetSub,
|
||||
},
|
||||
#[diag(lint_non_binding_let_on_drop_type)]
|
||||
DropType {
|
||||
#[subdiagnostic]
|
||||
sub: NonBindingLetSub,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct NonBindingLetSub {
|
||||
pub suggestion: Span,
|
||||
pub multi_suggestion_start: Span,
|
||||
pub multi_suggestion_end: Span,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for NonBindingLetSub {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
diag.span_suggestion_verbose(
|
||||
self.suggestion,
|
||||
fluent::lint_non_binding_let_suggestion,
|
||||
"_unused",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.multipart_suggestion(
|
||||
fluent::lint_non_binding_let_multi_suggestion,
|
||||
vec![
|
||||
(self.multi_suggestion_start, "drop(".to_string()),
|
||||
(self.multi_suggestion_end, ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// levels.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_overruled_attribute)]
|
||||
pub struct OverruledAtributeLint<'a> {
|
||||
#[label]
|
||||
pub overruled: Span,
|
||||
pub lint_level: &'a str,
|
||||
pub lint_source: Symbol,
|
||||
#[subdiagnostic]
|
||||
pub sub: OverruledAttributeSub,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_deprecated_lint_name)]
|
||||
pub struct DeprecatedLintName<'a> {
|
||||
pub name: String,
|
||||
#[suggestion(code = "{replace}", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
pub replace: &'a str,
|
||||
}
|
||||
|
||||
// FIXME: Non-translatable msg
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_renamed_or_removed_lint)]
|
||||
pub struct RenamedOrRemovedLint<'a> {
|
||||
pub msg: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<RenamedOrRemovedLintSuggestion<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(suggestion, code = "{replace}", applicability = "machine-applicable")]
|
||||
pub struct RenamedOrRemovedLintSuggestion<'a> {
|
||||
#[primary_span]
|
||||
pub suggestion: Span,
|
||||
pub replace: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unknown_lint)]
|
||||
pub struct UnknownLint {
|
||||
pub name: String,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<UnknownLintSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
|
||||
pub struct UnknownLintSuggestion {
|
||||
#[primary_span]
|
||||
pub suggestion: Span,
|
||||
pub replace: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_ignored_unless_crate_specified)]
|
||||
pub struct IgnoredUnlessCrateSpecified<'a> {
|
||||
pub level: &'a str,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
// methods.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_cstring_ptr)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct CStringPtr {
|
||||
#[label(as_ptr_label)]
|
||||
pub as_ptr: Span,
|
||||
#[label(unwrap_label)]
|
||||
pub unwrap: Span,
|
||||
}
|
||||
|
||||
// non_ascii_idents.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_identifier_non_ascii_char)]
|
||||
pub struct IdentifierNonAsciiChar;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_identifier_uncommon_codepoints)]
|
||||
pub struct IdentifierUncommonCodepoints;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_confusable_identifier_pair)]
|
||||
pub struct ConfusableIdentifierPair {
|
||||
pub existing_sym: Symbol,
|
||||
pub sym: Symbol,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_mixed_script_confusables)]
|
||||
#[note(includes_note)]
|
||||
#[note]
|
||||
pub struct MixedScriptConfusables {
|
||||
pub set: String,
|
||||
pub includes: String,
|
||||
}
|
||||
|
||||
// non_fmt_panic.rs
|
||||
pub struct NonFmtPanicUnused {
|
||||
pub count: usize,
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
// Used because of two suggestions based on one Option<Span>
|
||||
impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("count", self.count);
|
||||
diag.note(fluent::note);
|
||||
if let Some(span) = self.suggestion {
|
||||
diag.span_suggestion(
|
||||
span.shrink_to_hi(),
|
||||
fluent::add_args_suggestion,
|
||||
", ...",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
diag.span_suggestion(
|
||||
span.shrink_to_lo(),
|
||||
fluent::add_fmt_suggestion,
|
||||
"\"{}\", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
diag
|
||||
}
|
||||
|
||||
fn msg(&self) -> rustc_errors::DiagnosticMessage {
|
||||
fluent::lint_non_fmt_panic_unused
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_non_fmt_panic_braces)]
|
||||
#[note]
|
||||
pub struct NonFmtPanicBraces {
|
||||
pub count: usize,
|
||||
#[suggestion(code = "\"{{}}\", ", applicability = "machine-applicable")]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
// nonstandard_style.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_non_camel_case_type)]
|
||||
pub struct NonCamelCaseType<'a> {
|
||||
pub sort: &'a str,
|
||||
pub name: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub sub: NonCamelCaseTypeSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum NonCamelCaseTypeSub {
|
||||
#[label(label)]
|
||||
Label {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
|
||||
Suggestion {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
replace: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_non_snake_case)]
|
||||
pub struct NonSnakeCaseDiag<'a> {
|
||||
pub sort: &'a str,
|
||||
pub name: &'a str,
|
||||
pub sc: String,
|
||||
#[subdiagnostic]
|
||||
pub sub: NonSnakeCaseDiagSub,
|
||||
}
|
||||
|
||||
pub enum NonSnakeCaseDiagSub {
|
||||
Label { span: Span },
|
||||
Help,
|
||||
RenameOrConvertSuggestion { span: Span, suggestion: Ident },
|
||||
ConvertSuggestion { span: Span, suggestion: String },
|
||||
SuggestionAndNote { span: Span },
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for NonSnakeCaseDiagSub {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
NonSnakeCaseDiagSub::Label { span } => {
|
||||
diag.span_label(span, fluent::label);
|
||||
}
|
||||
NonSnakeCaseDiagSub::Help => {
|
||||
diag.help(fluent::help);
|
||||
}
|
||||
NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
fluent::convert_suggestion,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
fluent::rename_or_convert_suggestion,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
NonSnakeCaseDiagSub::SuggestionAndNote { span } => {
|
||||
diag.note(fluent::cannot_convert_note);
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
fluent::rename_suggestion,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_non_upper_case_global)]
|
||||
pub struct NonUpperCaseGlobal<'a> {
|
||||
pub sort: &'a str,
|
||||
pub name: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub sub: NonUpperCaseGlobalSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum NonUpperCaseGlobalSub {
|
||||
#[label(label)]
|
||||
Label {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
|
||||
Suggestion {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
replace: String,
|
||||
},
|
||||
}
|
||||
|
||||
// noop_method_call.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_noop_method_call)]
|
||||
#[note]
|
||||
pub struct NoopMethodCallDiag<'a> {
|
||||
pub method: Symbol,
|
||||
pub receiver_ty: Ty<'a>,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
}
|
||||
|
||||
// pass_by_value.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_pass_by_value)]
|
||||
pub struct PassByValueDiag {
|
||||
pub ty: String,
|
||||
#[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
// redundant_semicolon.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_redundant_semicolons)]
|
||||
pub struct RedundantSemicolonsDiag {
|
||||
pub multiple: bool,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
// traits.rs
|
||||
pub struct DropTraitConstraintsDiag<'a> {
|
||||
pub predicate: Predicate<'a>,
|
||||
pub tcx: TyCtxt<'a>,
|
||||
pub def_id: DefId,
|
||||
}
|
||||
|
||||
// Needed for def_path_str
|
||||
impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("predicate", self.predicate);
|
||||
diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
|
||||
}
|
||||
|
||||
fn msg(&self) -> rustc_errors::DiagnosticMessage {
|
||||
fluent::lint_drop_trait_constraints
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DropGlue<'a> {
|
||||
pub tcx: TyCtxt<'a>,
|
||||
pub def_id: DefId,
|
||||
}
|
||||
|
||||
// Needed for def_path_str
|
||||
impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
|
||||
}
|
||||
|
||||
fn msg(&self) -> rustc_errors::DiagnosticMessage {
|
||||
fluent::lint_drop_glue
|
||||
}
|
||||
}
|
||||
|
||||
// types.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_range_endpoint_out_of_range)]
|
||||
pub struct RangeEndpointOutOfRange<'a> {
|
||||
pub ty: &'a str,
|
||||
#[suggestion(code = "{start}..={literal}{suffix}", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
pub start: String,
|
||||
pub literal: u128,
|
||||
pub suffix: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_overflowing_bin_hex)]
|
||||
pub struct OverflowingBinHex<'a> {
|
||||
pub ty: &'a str,
|
||||
pub lit: String,
|
||||
pub dec: u128,
|
||||
pub actually: String,
|
||||
#[subdiagnostic]
|
||||
pub sign: OverflowingBinHexSign,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<OverflowingBinHexSub<'a>>,
|
||||
}
|
||||
|
||||
pub enum OverflowingBinHexSign {
|
||||
Positive,
|
||||
Negative,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for OverflowingBinHexSign {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
OverflowingBinHexSign::Positive => {
|
||||
diag.note(fluent::positive_note);
|
||||
}
|
||||
OverflowingBinHexSign::Negative => {
|
||||
diag.note(fluent::negative_note);
|
||||
diag.note(fluent::negative_becomes_note);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum OverflowingBinHexSub<'a> {
|
||||
#[suggestion(
|
||||
suggestion,
|
||||
code = "{sans_suffix}{suggestion_ty}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
Suggestion {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
suggestion_ty: &'a str,
|
||||
sans_suffix: &'a str,
|
||||
},
|
||||
#[help(help)]
|
||||
Help { suggestion_ty: &'a str },
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_overflowing_int)]
|
||||
#[note]
|
||||
pub struct OverflowingInt<'a> {
|
||||
pub ty: &'a str,
|
||||
pub lit: String,
|
||||
pub min: i128,
|
||||
pub max: u128,
|
||||
#[subdiagnostic]
|
||||
pub help: Option<OverflowingIntHelp<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(help)]
|
||||
pub struct OverflowingIntHelp<'a> {
|
||||
pub suggestion_ty: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_only_cast_u8_to_char)]
|
||||
pub struct OnlyCastu8ToChar {
|
||||
#[suggestion(code = "'\\u{{{literal:X}}}'", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
pub literal: u128,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_overflowing_uint)]
|
||||
#[note]
|
||||
pub struct OverflowingUInt<'a> {
|
||||
pub ty: &'a str,
|
||||
pub lit: String,
|
||||
pub min: u128,
|
||||
pub max: u128,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_overflowing_literal)]
|
||||
#[note]
|
||||
pub struct OverflowingLiteral<'a> {
|
||||
pub ty: &'a str,
|
||||
pub lit: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_comparisons)]
|
||||
pub struct UnusedComparisons;
|
||||
|
||||
pub struct ImproperCTypes<'a> {
|
||||
pub ty: Ty<'a>,
|
||||
pub desc: &'a str,
|
||||
pub label: Span,
|
||||
pub help: Option<DiagnosticMessage>,
|
||||
pub note: DiagnosticMessage,
|
||||
pub span_note: Option<Span>,
|
||||
}
|
||||
|
||||
// Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span>
|
||||
impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("ty", self.ty);
|
||||
diag.set_arg("desc", self.desc);
|
||||
diag.span_label(self.label, fluent::label);
|
||||
if let Some(help) = self.help {
|
||||
diag.help(help);
|
||||
}
|
||||
diag.note(self.note);
|
||||
if let Some(note) = self.span_note {
|
||||
diag.span_note(note, fluent::note);
|
||||
}
|
||||
diag
|
||||
}
|
||||
|
||||
fn msg(&self) -> rustc_errors::DiagnosticMessage {
|
||||
fluent::lint_improper_ctypes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_variant_size_differences)]
|
||||
pub struct VariantSizeDifferencesDiag {
|
||||
pub largest: u64,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_atomic_ordering_load)]
|
||||
#[help]
|
||||
pub struct AtomicOrderingLoad;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_atomic_ordering_store)]
|
||||
#[help]
|
||||
pub struct AtomicOrderingStore;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_atomic_ordering_fence)]
|
||||
#[help]
|
||||
pub struct AtomicOrderingFence;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_atomic_ordering_invalid)]
|
||||
#[help]
|
||||
pub struct InvalidAtomicOrderingDiag {
|
||||
pub method: Symbol,
|
||||
#[label]
|
||||
pub fail_order_arg_span: Span,
|
||||
}
|
||||
|
||||
// unused.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_op)]
|
||||
pub struct UnusedOp<'a> {
|
||||
pub op: &'a str,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_result)]
|
||||
pub struct UnusedResult<'a> {
|
||||
pub ty: Ty<'a>,
|
||||
}
|
||||
|
||||
// FIXME(davidtwco): this isn't properly translatable becauses of the
|
||||
// pre/post strings
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_closure)]
|
||||
#[note]
|
||||
pub struct UnusedClosure<'a> {
|
||||
pub count: usize,
|
||||
pub pre: &'a str,
|
||||
pub post: &'a str,
|
||||
}
|
||||
|
||||
// FIXME(davidtwco): this isn't properly translatable becauses of the
|
||||
// pre/post strings
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_generator)]
|
||||
#[note]
|
||||
pub struct UnusedGenerator<'a> {
|
||||
pub count: usize,
|
||||
pub pre: &'a str,
|
||||
pub post: &'a str,
|
||||
}
|
||||
|
||||
// FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
|
||||
// strings
|
||||
pub struct UnusedDef<'a, 'b> {
|
||||
pub pre: &'a str,
|
||||
pub post: &'a str,
|
||||
pub cx: &'a LateContext<'b>,
|
||||
pub def_id: DefId,
|
||||
pub note: Option<Symbol>,
|
||||
}
|
||||
|
||||
// Needed because of def_path_str
|
||||
impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
|
||||
fn decorate_lint<'b>(
|
||||
self,
|
||||
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
|
||||
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
|
||||
diag.set_arg("pre", self.pre);
|
||||
diag.set_arg("post", self.post);
|
||||
diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id));
|
||||
// check for #[must_use = "..."]
|
||||
if let Some(note) = self.note {
|
||||
diag.note(note.as_str());
|
||||
}
|
||||
diag
|
||||
}
|
||||
|
||||
fn msg(&self) -> rustc_errors::DiagnosticMessage {
|
||||
fluent::lint_unused_def
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_path_statement_drop)]
|
||||
pub struct PathStatementDrop {
|
||||
#[subdiagnostic]
|
||||
pub sub: PathStatementDropSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum PathStatementDropSub {
|
||||
#[suggestion(suggestion, code = "drop({snippet});", applicability = "machine-applicable")]
|
||||
Suggestion {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
#[help(help)]
|
||||
Help {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_path_statement_no_effect)]
|
||||
pub struct PathStatementNoEffect;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_delim)]
|
||||
pub struct UnusedDelim<'a> {
|
||||
pub delim: &'static str,
|
||||
pub item: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<UnusedDelimSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
|
||||
pub struct UnusedDelimSuggestion {
|
||||
#[suggestion_part(code = "{start_replace}")]
|
||||
pub start_span: Span,
|
||||
pub start_replace: &'static str,
|
||||
#[suggestion_part(code = "{end_replace}")]
|
||||
pub end_span: Span,
|
||||
pub end_replace: &'static str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_import_braces)]
|
||||
pub struct UnusedImportBracesDiag {
|
||||
pub node: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_allocation)]
|
||||
pub struct UnusedAllocationDiag;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_allocation_mut)]
|
||||
pub struct UnusedAllocationMutDiag;
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::lints::CStringPtr;
|
||||
use crate::LateContext;
|
||||
use crate::LateLintPass;
|
||||
use crate::LintContext;
|
||||
use rustc_errors::fluent;
|
||||
use rustc_hir::{Expr, ExprKind, PathSegment};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::{symbol::sym, ExpnKind, Span};
|
||||
@@ -90,16 +90,10 @@ fn lint_cstring_as_ptr(
|
||||
if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
|
||||
if let ty::Adt(adt, _) = substs.type_at(0).kind() {
|
||||
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
TEMPORARY_CSTRING_AS_PTR,
|
||||
as_ptr_span,
|
||||
fluent::lint_cstring_ptr,
|
||||
|diag| {
|
||||
diag.span_label(as_ptr_span, fluent::as_ptr_label)
|
||||
.span_label(unwrap.span, fluent::unwrap_label)
|
||||
.note(fluent::note)
|
||||
.help(fluent::help)
|
||||
},
|
||||
CStringPtr { as_ptr: as_ptr_span, unwrap: unwrap.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use crate::lints::{
|
||||
ConfusableIdentifierPair, IdentifierNonAsciiChar, IdentifierUncommonCodepoints,
|
||||
MixedScriptConfusables,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::fluent;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
declare_lint! {
|
||||
@@ -180,21 +183,11 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
|
||||
continue;
|
||||
}
|
||||
has_non_ascii_idents = true;
|
||||
cx.struct_span_lint(
|
||||
NON_ASCII_IDENTS,
|
||||
sp,
|
||||
fluent::lint_identifier_non_ascii_char,
|
||||
|lint| lint,
|
||||
);
|
||||
cx.emit_spanned_lint(NON_ASCII_IDENTS, sp, IdentifierNonAsciiChar);
|
||||
if check_uncommon_codepoints
|
||||
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
|
||||
{
|
||||
cx.struct_span_lint(
|
||||
UNCOMMON_CODEPOINTS,
|
||||
sp,
|
||||
fluent::lint_identifier_uncommon_codepoints,
|
||||
|lint| lint,
|
||||
)
|
||||
cx.emit_spanned_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,14 +215,13 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
|
||||
.entry(skeleton_sym)
|
||||
.and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
|
||||
if !*existing_is_ascii || !is_ascii {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
CONFUSABLE_IDENTS,
|
||||
sp,
|
||||
fluent::lint_confusable_identifier_pair,
|
||||
|lint| {
|
||||
lint.set_arg("existing_sym", *existing_symbol)
|
||||
.set_arg("sym", symbol)
|
||||
.span_label(*existing_span, fluent::label)
|
||||
ConfusableIdentifierPair {
|
||||
existing_sym: *existing_symbol,
|
||||
sym: symbol,
|
||||
label: *existing_span,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -331,24 +323,18 @@ enum ScriptSetUsage {
|
||||
}
|
||||
|
||||
for ((sp, ch_list), script_set) in lint_reports {
|
||||
cx.struct_span_lint(
|
||||
let mut includes = String::new();
|
||||
for (idx, ch) in ch_list.into_iter().enumerate() {
|
||||
if idx != 0 {
|
||||
includes += ", ";
|
||||
}
|
||||
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
|
||||
includes += &char_info;
|
||||
}
|
||||
cx.emit_spanned_lint(
|
||||
MIXED_SCRIPT_CONFUSABLES,
|
||||
sp,
|
||||
fluent::lint_mixed_script_confusables,
|
||||
|lint| {
|
||||
let mut includes = String::new();
|
||||
for (idx, ch) in ch_list.into_iter().enumerate() {
|
||||
if idx != 0 {
|
||||
includes += ", ";
|
||||
}
|
||||
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
|
||||
includes += &char_info;
|
||||
}
|
||||
lint.set_arg("set", script_set.to_string())
|
||||
.set_arg("includes", includes)
|
||||
.note(fluent::includes_note)
|
||||
.note(fluent::note)
|
||||
},
|
||||
MixedScriptConfusables { set: script_set.to_string(), includes },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
@@ -118,6 +119,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||
arg_span = expn.call_site;
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
|
||||
lint.set_arg("name", symbol);
|
||||
lint.note(fluent::note);
|
||||
@@ -253,25 +255,14 @@ fn check_panic_str<'tcx>(
|
||||
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
|
||||
.collect(),
|
||||
};
|
||||
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| {
|
||||
lint.set_arg("count", n_arguments);
|
||||
lint.note(fluent::note);
|
||||
if is_arg_inside_call(arg.span, span) {
|
||||
lint.span_suggestion(
|
||||
arg.span.shrink_to_hi(),
|
||||
fluent::add_args_suggestion,
|
||||
", ...",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
lint.span_suggestion(
|
||||
arg.span.shrink_to_lo(),
|
||||
fluent::add_fmt_suggestion,
|
||||
"\"{}\", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
lint
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
NON_FMT_PANICS,
|
||||
arg_spans,
|
||||
NonFmtPanicUnused {
|
||||
count: n_arguments,
|
||||
suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let brace_spans: Option<Vec<_>> =
|
||||
snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
|
||||
@@ -281,22 +272,12 @@ fn check_panic_str<'tcx>(
|
||||
.collect()
|
||||
});
|
||||
let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
NON_FMT_PANICS,
|
||||
brace_spans.unwrap_or_else(|| vec![span]),
|
||||
fluent::lint_non_fmt_panic_braces,
|
||||
|lint| {
|
||||
lint.set_arg("count", count);
|
||||
lint.note(fluent::note);
|
||||
if is_arg_inside_call(arg.span, span) {
|
||||
lint.span_suggestion(
|
||||
arg.span.shrink_to_lo(),
|
||||
fluent::suggestion,
|
||||
"\"{}\", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
lint
|
||||
NonFmtPanicBraces {
|
||||
count,
|
||||
suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span.shrink_to_lo()),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use crate::lints::{
|
||||
NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub,
|
||||
NonUpperCaseGlobal, NonUpperCaseGlobalSub,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
@@ -136,30 +139,17 @@ fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) {
|
||||
let name = ident.name.as_str();
|
||||
|
||||
if !is_camel_case(name) {
|
||||
cx.struct_span_lint(
|
||||
let cc = to_camel_case(name);
|
||||
let sub = if *name != cc {
|
||||
NonCamelCaseTypeSub::Suggestion { span: ident.span, replace: cc }
|
||||
} else {
|
||||
NonCamelCaseTypeSub::Label { span: ident.span }
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
NON_CAMEL_CASE_TYPES,
|
||||
ident.span,
|
||||
fluent::lint_non_camel_case_type,
|
||||
|lint| {
|
||||
let cc = to_camel_case(name);
|
||||
// We cannot provide meaningful suggestions
|
||||
// if the characters are in the category of "Lowercase Letter".
|
||||
if *name != cc {
|
||||
lint.span_suggestion(
|
||||
ident.span,
|
||||
fluent::suggestion,
|
||||
to_camel_case(name),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
lint.span_label(ident.span, fluent::label);
|
||||
}
|
||||
|
||||
lint.set_arg("sort", sort);
|
||||
lint.set_arg("name", name);
|
||||
lint
|
||||
},
|
||||
)
|
||||
NonCamelCaseType { sort, name, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,47 +284,37 @@ fn is_snake_case(ident: &str) -> bool {
|
||||
let name = ident.name.as_str();
|
||||
|
||||
if !is_snake_case(name) {
|
||||
cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| {
|
||||
let sc = NonSnakeCase::to_snake_case(name);
|
||||
// We cannot provide meaningful suggestions
|
||||
// if the characters are in the category of "Uppercase Letter".
|
||||
if name != sc {
|
||||
// We have a valid span in almost all cases, but we don't have one when linting a crate
|
||||
// name provided via the command line.
|
||||
if !ident.span.is_dummy() {
|
||||
let sc_ident = Ident::from_str_and_span(&sc, ident.span);
|
||||
let (message, suggestion) = if sc_ident.is_reserved() {
|
||||
// We shouldn't suggest a reserved identifier to fix non-snake-case identifiers.
|
||||
// Instead, recommend renaming the identifier entirely or, if permitted,
|
||||
// escaping it to create a raw identifier.
|
||||
if sc_ident.name.can_be_raw() {
|
||||
(fluent::rename_or_convert_suggestion, sc_ident.to_string())
|
||||
} else {
|
||||
lint.note(fluent::cannot_convert_note);
|
||||
(fluent::rename_suggestion, String::new())
|
||||
let span = ident.span;
|
||||
let sc = NonSnakeCase::to_snake_case(name);
|
||||
// We cannot provide meaningful suggestions
|
||||
// if the characters are in the category of "Uppercase Letter".
|
||||
let sub = if name != sc {
|
||||
// We have a valid span in almost all cases, but we don't have one when linting a crate
|
||||
// name provided via the command line.
|
||||
if !span.is_dummy() {
|
||||
let sc_ident = Ident::from_str_and_span(&sc, span);
|
||||
if sc_ident.is_reserved() {
|
||||
// We shouldn't suggest a reserved identifier to fix non-snake-case identifiers.
|
||||
// Instead, recommend renaming the identifier entirely or, if permitted,
|
||||
// escaping it to create a raw identifier.
|
||||
if sc_ident.name.can_be_raw() {
|
||||
NonSnakeCaseDiagSub::RenameOrConvertSuggestion {
|
||||
span,
|
||||
suggestion: sc_ident,
|
||||
}
|
||||
} else {
|
||||
(fluent::convert_suggestion, sc.clone())
|
||||
};
|
||||
|
||||
lint.span_suggestion(
|
||||
ident.span,
|
||||
message,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
NonSnakeCaseDiagSub::SuggestionAndNote { span }
|
||||
}
|
||||
} else {
|
||||
lint.help(fluent::help);
|
||||
NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion: sc.clone() }
|
||||
}
|
||||
} else {
|
||||
lint.span_label(ident.span, fluent::label);
|
||||
NonSnakeCaseDiagSub::Help
|
||||
}
|
||||
|
||||
lint.set_arg("sort", sort);
|
||||
lint.set_arg("name", name);
|
||||
lint.set_arg("sc", sc);
|
||||
lint
|
||||
});
|
||||
} else {
|
||||
NonSnakeCaseDiagSub::Label { span }
|
||||
};
|
||||
cx.emit_spanned_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,30 +470,19 @@ impl NonUpperCaseGlobals {
|
||||
fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
|
||||
let name = ident.name.as_str();
|
||||
if name.chars().any(|c| c.is_lowercase()) {
|
||||
cx.struct_span_lint(
|
||||
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
|
||||
// We cannot provide meaningful suggestions
|
||||
// if the characters are in the category of "Lowercase Letter".
|
||||
let sub = if *name != uc {
|
||||
NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc }
|
||||
} else {
|
||||
NonUpperCaseGlobalSub::Label { span: ident.span }
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
NON_UPPER_CASE_GLOBALS,
|
||||
ident.span,
|
||||
fluent::lint_non_upper_case_global,
|
||||
|lint| {
|
||||
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
|
||||
// We cannot provide meaningful suggestions
|
||||
// if the characters are in the category of "Lowercase Letter".
|
||||
if *name != uc {
|
||||
lint.span_suggestion(
|
||||
ident.span,
|
||||
fluent::suggestion,
|
||||
uc,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
lint.span_label(ident.span, fluent::label);
|
||||
}
|
||||
|
||||
lint.set_arg("sort", sort);
|
||||
lint.set_arg("name", name);
|
||||
lint
|
||||
},
|
||||
)
|
||||
NonUpperCaseGlobal { sort, name, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::context::LintContext;
|
||||
use crate::lints::NoopMethodCallDiag;
|
||||
use crate::LateContext;
|
||||
use crate::LateLintPass;
|
||||
use rustc_errors::fluent;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_middle::ty;
|
||||
@@ -85,11 +85,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
}
|
||||
let expr_span = expr.span;
|
||||
let span = expr_span.with_lo(receiver.span.hi());
|
||||
cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| {
|
||||
lint.set_arg("method", call.ident.name)
|
||||
.set_arg("receiver_ty", receiver_ty)
|
||||
.span_label(span, fluent::label)
|
||||
.note(fluent::note)
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
NOOP_METHOD_CALL,
|
||||
span,
|
||||
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::lints::PassByValueDiag;
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
|
||||
@@ -29,20 +29,11 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
|
||||
}
|
||||
}
|
||||
if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
PASS_BY_VALUE,
|
||||
ty.span,
|
||||
fluent::lint_pass_by_value,
|
||||
|lint| {
|
||||
lint.set_arg("ty", t.clone()).span_suggestion(
|
||||
ty.span,
|
||||
fluent::suggestion,
|
||||
t,
|
||||
// Changing type of function argument
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
},
|
||||
)
|
||||
PassByValueDiag { ty: t.clone(), suggestion: ty.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use crate::{lints::RedundantSemicolonsDiag, EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_ast::{Block, StmtKind};
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_lint! {
|
||||
@@ -48,18 +47,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
|
||||
return;
|
||||
}
|
||||
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
REDUNDANT_SEMICOLONS,
|
||||
span,
|
||||
fluent::lint_redundant_semicolons,
|
||||
|lint| {
|
||||
lint.set_arg("multiple", multiple).span_suggestion(
|
||||
span,
|
||||
fluent::suggestion,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
},
|
||||
RedundantSemicolonsDiag { multiple, suggestion: span },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::lints::{DropGlue, DropTraitConstraintsDiag};
|
||||
use crate::LateContext;
|
||||
use crate::LateLintPass;
|
||||
use crate::LintContext;
|
||||
use rustc_errors::fluent;
|
||||
use rustc_hir as hir;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
@@ -101,17 +101,13 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
if trait_predicate.trait_ref.self_ty().is_impl_trait() {
|
||||
continue;
|
||||
}
|
||||
let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
|
||||
continue;
|
||||
let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
|
||||
return
|
||||
};
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
DROP_BOUNDS,
|
||||
span,
|
||||
fluent::lint_drop_trait_constraints,
|
||||
|lint| {
|
||||
lint.set_arg("predicate", predicate)
|
||||
.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
|
||||
},
|
||||
DropTraitConstraintsDiag { predicate, tcx: cx.tcx, def_id },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -123,12 +119,11 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
|
||||
};
|
||||
for bound in &bounds[..] {
|
||||
let def_id = bound.trait_ref.trait_def_id();
|
||||
if cx.tcx.lang_items().drop_trait() == def_id
|
||||
&& let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
|
||||
{
|
||||
cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| {
|
||||
lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
|
||||
});
|
||||
if cx.tcx.lang_items().drop_trait() == def_id {
|
||||
let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
|
||||
return
|
||||
};
|
||||
cx.emit_spanned_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+110
-177
@@ -1,11 +1,16 @@
|
||||
use crate::lints::{
|
||||
AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
|
||||
InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
|
||||
OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
|
||||
RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag,
|
||||
};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{fluent, Applicability, DiagnosticMessage};
|
||||
use rustc_errors::{fluent, DiagnosticMessage};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
|
||||
@@ -146,32 +151,22 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
||||
};
|
||||
let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
|
||||
|
||||
cx.struct_span_lint(
|
||||
use rustc_ast::{LitIntType, LitKind};
|
||||
let suffix = match lit.node {
|
||||
LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsuffixed) => "",
|
||||
_ => bug!(),
|
||||
};
|
||||
cx.emit_spanned_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
struct_expr.span,
|
||||
fluent::lint_range_endpoint_out_of_range,
|
||||
|lint| {
|
||||
use ast::{LitIntType, LitKind};
|
||||
|
||||
lint.set_arg("ty", ty);
|
||||
|
||||
// We need to preserve the literal's suffix,
|
||||
// as it may determine typing information.
|
||||
let suffix = match lit.node {
|
||||
LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
|
||||
LitKind::Int(_, LitIntType::Unsuffixed) => "",
|
||||
_ => bug!(),
|
||||
};
|
||||
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
|
||||
lint.span_suggestion(
|
||||
struct_expr.span,
|
||||
fluent::suggestion,
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
lint
|
||||
RangeEndpointOutOfRange {
|
||||
ty,
|
||||
suggestion: struct_expr.span,
|
||||
start,
|
||||
literal: lit_val - 1,
|
||||
suffix,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -228,58 +223,37 @@ fn report_bin_hex_error(
|
||||
val: u128,
|
||||
negative: bool,
|
||||
) {
|
||||
cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
expr.span,
|
||||
fluent::lint_overflowing_bin_hex,
|
||||
|lint| {
|
||||
let (t, actually) = match ty {
|
||||
attr::IntType::SignedInt(t) => {
|
||||
let actually = if negative {
|
||||
-(size.sign_extend(val) as i128)
|
||||
} else {
|
||||
size.sign_extend(val) as i128
|
||||
};
|
||||
(t.name_str(), actually.to_string())
|
||||
}
|
||||
attr::IntType::UnsignedInt(t) => {
|
||||
let actually = size.truncate(val);
|
||||
(t.name_str(), actually.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
if negative {
|
||||
// If the value is negative,
|
||||
// emits a note about the value itself, apart from the literal.
|
||||
lint.note(fluent::negative_note);
|
||||
lint.note(fluent::negative_becomes_note);
|
||||
let (t, actually) = match ty {
|
||||
attr::IntType::SignedInt(t) => {
|
||||
let actually = if negative {
|
||||
-(size.sign_extend(val) as i128)
|
||||
} else {
|
||||
lint.note(fluent::positive_note);
|
||||
size.sign_extend(val) as i128
|
||||
};
|
||||
(t.name_str(), actually.to_string())
|
||||
}
|
||||
attr::IntType::UnsignedInt(t) => {
|
||||
let actually = size.truncate(val);
|
||||
(t.name_str(), actually.to_string())
|
||||
}
|
||||
};
|
||||
let sign =
|
||||
if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive };
|
||||
let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map(
|
||||
|suggestion_ty| {
|
||||
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
|
||||
let (sans_suffix, _) = repr_str.split_at(pos);
|
||||
OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix }
|
||||
} else {
|
||||
OverflowingBinHexSub::Help { suggestion_ty }
|
||||
}
|
||||
if let Some(sugg_ty) =
|
||||
get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
|
||||
{
|
||||
lint.set_arg("suggestion_ty", sugg_ty);
|
||||
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
|
||||
let (sans_suffix, _) = repr_str.split_at(pos);
|
||||
lint.span_suggestion(
|
||||
expr.span,
|
||||
fluent::suggestion,
|
||||
format!("{}{}", sans_suffix, sugg_ty),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
lint.help(fluent::help);
|
||||
}
|
||||
}
|
||||
lint.set_arg("ty", t)
|
||||
.set_arg("lit", repr_str)
|
||||
.set_arg("dec", val)
|
||||
.set_arg("actually", actually);
|
||||
|
||||
lint
|
||||
},
|
||||
);
|
||||
cx.emit_spanned_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
expr.span,
|
||||
OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub },
|
||||
)
|
||||
}
|
||||
|
||||
// This function finds the next fitting type and generates a suggestion string.
|
||||
@@ -363,28 +337,19 @@ fn lint_int_literal<'tcx>(
|
||||
return;
|
||||
}
|
||||
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| {
|
||||
lint.set_arg("ty", t.name_str())
|
||||
.set_arg(
|
||||
"lit",
|
||||
cx.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.expect("must get snippet from literal"),
|
||||
)
|
||||
.set_arg("min", min)
|
||||
.set_arg("max", max)
|
||||
.note(fluent::note);
|
||||
let lit = cx
|
||||
.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.expect("must get snippet from literal");
|
||||
let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
|
||||
.map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
|
||||
|
||||
if let Some(sugg_ty) =
|
||||
get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
|
||||
{
|
||||
lint.set_arg("suggestion_ty", sugg_ty);
|
||||
lint.help(fluent::help);
|
||||
}
|
||||
|
||||
lint
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
OverflowingInt { ty: t.name_str(), lit, min, max, help },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,18 +373,10 @@ fn lint_uint_literal<'tcx>(
|
||||
match par_e.kind {
|
||||
hir::ExprKind::Cast(..) => {
|
||||
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
par_e.span,
|
||||
fluent::lint_only_cast_u8_to_char,
|
||||
|lint| {
|
||||
lint.span_suggestion(
|
||||
par_e.span,
|
||||
fluent::suggestion,
|
||||
format!("'\\u{{{:X}}}'", lit_val),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
},
|
||||
OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -443,19 +400,20 @@ fn lint_uint_literal<'tcx>(
|
||||
);
|
||||
return;
|
||||
}
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| {
|
||||
lint.set_arg("ty", t.name_str())
|
||||
.set_arg(
|
||||
"lit",
|
||||
cx.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.expect("must get snippet from literal"),
|
||||
)
|
||||
.set_arg("min", min)
|
||||
.set_arg("max", max)
|
||||
.note(fluent::note)
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
OverflowingUInt {
|
||||
ty: t.name_str(),
|
||||
lit: cx
|
||||
.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.expect("must get snippet from literal"),
|
||||
min,
|
||||
max,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,20 +442,16 @@ fn lint_literal<'tcx>(
|
||||
_ => bug!(),
|
||||
};
|
||||
if is_infinite == Ok(true) {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
fluent::lint_overflowing_literal,
|
||||
|lint| {
|
||||
lint.set_arg("ty", t.name_str())
|
||||
.set_arg(
|
||||
"lit",
|
||||
cx.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.expect("must get snippet from literal"),
|
||||
)
|
||||
.note(fluent::note)
|
||||
OverflowingLiteral {
|
||||
ty: t.name_str(),
|
||||
lit: cx
|
||||
.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.expect("must get snippet from literal"),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -517,12 +471,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
|
||||
}
|
||||
hir::ExprKind::Binary(binop, ref l, ref r) => {
|
||||
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
|
||||
cx.struct_span_lint(
|
||||
UNUSED_COMPARISONS,
|
||||
e.span,
|
||||
fluent::lint_unused_comparisons,
|
||||
|lint| lint,
|
||||
);
|
||||
cx.emit_spanned_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
|
||||
@@ -1174,26 +1123,21 @@ fn emit_ffi_unsafe_type_lint(
|
||||
CItemKind::Declaration => IMPROPER_CTYPES,
|
||||
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
|
||||
};
|
||||
|
||||
self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| {
|
||||
let item_description = match self.mode {
|
||||
CItemKind::Declaration => "block",
|
||||
CItemKind::Definition => "fn",
|
||||
let desc = match self.mode {
|
||||
CItemKind::Declaration => "block",
|
||||
CItemKind::Definition => "fn",
|
||||
};
|
||||
let span_note = if let ty::Adt(def, _) = ty.kind()
|
||||
&& let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
|
||||
Some(sp)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lint.set_arg("ty", ty);
|
||||
lint.set_arg("desc", item_description);
|
||||
lint.span_label(sp, fluent::label);
|
||||
if let Some(help) = help {
|
||||
lint.help(help);
|
||||
}
|
||||
lint.note(note);
|
||||
if let ty::Adt(def, _) = ty.kind() {
|
||||
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
|
||||
lint.span_note(sp, fluent::note);
|
||||
}
|
||||
}
|
||||
lint
|
||||
});
|
||||
self.cx.emit_spanned_lint(
|
||||
lint,
|
||||
sp,
|
||||
ImproperCTypes { ty, desc, label: sp, help, note, span_note },
|
||||
);
|
||||
}
|
||||
|
||||
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
|
||||
@@ -1397,11 +1341,10 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
// We only warn if the largest variant is at least thrice as large as
|
||||
// the second-largest.
|
||||
if largest > slargest * 3 && slargest > 0 {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
VARIANT_SIZE_DIFFERENCES,
|
||||
enum_definition.variants[largest_index].span,
|
||||
fluent::lint_variant_size_differences,
|
||||
|lint| lint.set_arg("largest", largest),
|
||||
VariantSizeDifferencesDiag { largest },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1509,17 +1452,19 @@ fn match_ordering(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<Symbol> {
|
||||
|
||||
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
|
||||
&& let Some((ordering_arg, invalid_ordering, msg)) = match method {
|
||||
sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)),
|
||||
sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)),
|
||||
&& let Some((ordering_arg, invalid_ordering)) = match method {
|
||||
sym::load => Some((&args[0], sym::Release)),
|
||||
sym::store => Some((&args[1], sym::Acquire)),
|
||||
_ => None,
|
||||
}
|
||||
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg)
|
||||
&& (ordering == invalid_ordering || ordering == sym::AcqRel)
|
||||
{
|
||||
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
|
||||
lint.help(fluent::help)
|
||||
});
|
||||
if method == sym::load {
|
||||
cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad);
|
||||
} else {
|
||||
cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1530,10 +1475,7 @@ fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
|
||||
&& Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
|
||||
{
|
||||
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| {
|
||||
lint
|
||||
.help(fluent::help)
|
||||
});
|
||||
cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, args[0].span, AtomicOrderingFence);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,15 +1492,6 @@ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return };
|
||||
|
||||
if matches!(fail_ordering, sym::Release | sym::AcqRel) {
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_atomic_ordering_invalid)]
|
||||
#[help]
|
||||
struct InvalidAtomicOrderingDiag {
|
||||
method: Symbol,
|
||||
#[label]
|
||||
fail_order_arg_span: Span,
|
||||
}
|
||||
|
||||
cx.emit_spanned_lint(
|
||||
INVALID_ATOMIC_ORDERING,
|
||||
fail_order_arg.span,
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
use crate::lints::{
|
||||
PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
|
||||
UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion,
|
||||
UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult,
|
||||
};
|
||||
use crate::Lint;
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::util::{classify, parser};
|
||||
use rustc_ast::{ExprKind, StmtKind};
|
||||
use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
|
||||
use rustc_errors::{pluralize, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@@ -163,23 +168,20 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
|
||||
let mut op_warned = false;
|
||||
|
||||
if let Some(must_use_op) = must_use_op {
|
||||
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
|
||||
lint.set_arg("op", must_use_op)
|
||||
.span_label(expr.span, fluent::label)
|
||||
.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
fluent::suggestion,
|
||||
"let _ = ",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
UNUSED_MUST_USE,
|
||||
expr.span,
|
||||
UnusedOp {
|
||||
op: must_use_op,
|
||||
label: expr.span,
|
||||
suggestion: expr.span.shrink_to_lo(),
|
||||
},
|
||||
);
|
||||
op_warned = true;
|
||||
}
|
||||
|
||||
if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) {
|
||||
cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
|
||||
lint.set_arg("ty", ty)
|
||||
});
|
||||
cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
|
||||
}
|
||||
|
||||
fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||
@@ -402,47 +404,31 @@ fn emit_must_use_untranslated(
|
||||
);
|
||||
}
|
||||
MustUsePath::Closure(span) => {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
UNUSED_MUST_USE,
|
||||
*span,
|
||||
fluent::lint_unused_closure,
|
||||
|lint| {
|
||||
// FIXME(davidtwco): this isn't properly translatable because of the
|
||||
// pre/post strings
|
||||
lint.set_arg("count", plural_len)
|
||||
.set_arg("pre", descr_pre)
|
||||
.set_arg("post", descr_post)
|
||||
.note(fluent::note)
|
||||
},
|
||||
UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post },
|
||||
);
|
||||
}
|
||||
MustUsePath::Generator(span) => {
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
UNUSED_MUST_USE,
|
||||
*span,
|
||||
fluent::lint_unused_generator,
|
||||
|lint| {
|
||||
// FIXME(davidtwco): this isn't properly translatable because of the
|
||||
// pre/post strings
|
||||
lint.set_arg("count", plural_len)
|
||||
.set_arg("pre", descr_pre)
|
||||
.set_arg("post", descr_post)
|
||||
.note(fluent::note)
|
||||
},
|
||||
UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post },
|
||||
);
|
||||
}
|
||||
MustUsePath::Def(span, def_id, reason) => {
|
||||
cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| {
|
||||
// FIXME(davidtwco): this isn't properly translatable because of the pre/post
|
||||
// strings
|
||||
lint.set_arg("pre", descr_pre);
|
||||
lint.set_arg("post", descr_post);
|
||||
lint.set_arg("def", cx.tcx.def_path_str(*def_id));
|
||||
if let Some(note) = reason {
|
||||
lint.note(note.as_str());
|
||||
}
|
||||
lint
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
UNUSED_MUST_USE,
|
||||
*span,
|
||||
UnusedDef {
|
||||
pre: descr_pre,
|
||||
post: descr_post,
|
||||
cx,
|
||||
def_id: *def_id,
|
||||
note: *reason,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,31 +464,15 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
|
||||
if let hir::ExprKind::Path(_) = expr.kind {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if ty.needs_drop(cx.tcx, cx.param_env) {
|
||||
cx.struct_span_lint(
|
||||
PATH_STATEMENTS,
|
||||
s.span,
|
||||
fluent::lint_path_statement_drop,
|
||||
|lint| {
|
||||
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
|
||||
lint.span_suggestion(
|
||||
s.span,
|
||||
fluent::suggestion,
|
||||
format!("drop({});", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
lint.span_help(s.span, fluent::suggestion);
|
||||
}
|
||||
lint
|
||||
},
|
||||
);
|
||||
let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span)
|
||||
{
|
||||
PathStatementDropSub::Suggestion { span: s.span, snippet }
|
||||
} else {
|
||||
PathStatementDropSub::Help { span: s.span }
|
||||
};
|
||||
cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
|
||||
} else {
|
||||
cx.struct_span_lint(
|
||||
PATH_STATEMENTS,
|
||||
s.span,
|
||||
fluent::lint_path_statement_no_effect,
|
||||
|lint| lint,
|
||||
);
|
||||
cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,36 +665,35 @@ fn emit_unused_delims(
|
||||
} else {
|
||||
MultiSpan::from(value_span)
|
||||
};
|
||||
cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| {
|
||||
lint.set_arg("delim", Self::DELIM_STR);
|
||||
lint.set_arg("item", msg);
|
||||
if let Some((lo, hi)) = spans {
|
||||
let sm = cx.sess().source_map();
|
||||
let lo_replace =
|
||||
let suggestion = spans.map(|(lo, hi)| {
|
||||
let sm = cx.sess().source_map();
|
||||
let lo_replace =
|
||||
if keep_space.0 &&
|
||||
let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') {
|
||||
" ".to_string()
|
||||
" "
|
||||
} else {
|
||||
"".to_string()
|
||||
""
|
||||
};
|
||||
|
||||
let hi_replace =
|
||||
let hi_replace =
|
||||
if keep_space.1 &&
|
||||
let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') {
|
||||
" ".to_string()
|
||||
" "
|
||||
} else {
|
||||
"".to_string()
|
||||
""
|
||||
};
|
||||
|
||||
let replacement = vec![(lo, lo_replace), (hi, hi_replace)];
|
||||
lint.multipart_suggestion(
|
||||
fluent::suggestion,
|
||||
replacement,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
UnusedDelimSuggestion {
|
||||
start_span: lo,
|
||||
start_replace: lo_replace,
|
||||
end_span: hi,
|
||||
end_replace: hi_replace,
|
||||
}
|
||||
lint
|
||||
});
|
||||
cx.emit_spanned_lint(
|
||||
self.lint(),
|
||||
primary_span,
|
||||
UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion },
|
||||
);
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
@@ -1297,11 +1266,10 @@ fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &
|
||||
ast::UseTreeKind::Nested(_) => return,
|
||||
};
|
||||
|
||||
cx.struct_span_lint(
|
||||
cx.emit_spanned_lint(
|
||||
UNUSED_IMPORT_BRACES,
|
||||
item.span,
|
||||
fluent::lint_unused_import_braces,
|
||||
|lint| lint.set_arg("node", node_name),
|
||||
UnusedImportBracesDiag { node: node_name },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1351,17 +1319,14 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
|
||||
|
||||
for adj in cx.typeck_results().expr_adjustments(e) {
|
||||
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
||||
cx.struct_span_lint(
|
||||
UNUSED_ALLOCATION,
|
||||
e.span,
|
||||
match m {
|
||||
adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation,
|
||||
adjustment::AutoBorrowMutability::Mut { .. } => {
|
||||
fluent::lint_unused_allocation_mut
|
||||
}
|
||||
},
|
||||
|lint| lint,
|
||||
);
|
||||
match m {
|
||||
adjustment::AutoBorrowMutability::Not => {
|
||||
cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag);
|
||||
}
|
||||
adjustment::AutoBorrowMutability::Mut { .. } => {
|
||||
cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user