Auto merge of #68725 - jumbatm:invert-control-in-struct_lint_level, r=Centril
Invert control in struct_lint_level. Closes #67927 Changes the `struct_lint*` methods to take a `decorate` function instead of a message string. This decorate function is also responsible for eventually stashing, emitting or cancelling the diagnostic. If the lint was allowed after all, the decorate function is not run at all, saving us from spending time formatting messages (and potentially other expensive work) for lints that don't end up being emitted. r? @Centril
This commit is contained in:
commit
95e0a2c50d
59 changed files with 1803 additions and 1619 deletions
|
@ -1701,7 +1701,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
sub: Region<'tcx>,
|
||||
) {
|
||||
self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub)
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn construct_generic_bound_failure(
|
||||
|
|
|
@ -174,20 +174,49 @@ impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn struct_lint_level<'a>(
|
||||
sess: &'a Session,
|
||||
pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>);
|
||||
|
||||
impl<'a> LintDiagnosticBuilder<'a> {
|
||||
/// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
|
||||
pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.0.set_primary_message(msg);
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder.
|
||||
pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> {
|
||||
LintDiagnosticBuilder(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_lint_level<'s, 'd>(
|
||||
sess: &'s Session,
|
||||
lint: &'static Lint,
|
||||
level: Level,
|
||||
src: LintSource,
|
||||
span: Option<MultiSpan>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
|
||||
) {
|
||||
// Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
|
||||
// the "real" work.
|
||||
fn struct_lint_level_impl(
|
||||
sess: &'s Session,
|
||||
lint: &'static Lint,
|
||||
level: Level,
|
||||
src: LintSource,
|
||||
span: Option<MultiSpan>,
|
||||
decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
|
||||
) {
|
||||
let mut err = match (level, span) {
|
||||
(Level::Allow, _) => return sess.diagnostic().struct_dummy(),
|
||||
(Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
|
||||
(Level::Warn, None) => sess.struct_warn(msg),
|
||||
(Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
|
||||
(Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg),
|
||||
(Level::Allow, _) => {
|
||||
return;
|
||||
}
|
||||
(Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
|
||||
(Level::Warn, None) => sess.struct_warn(""),
|
||||
(Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => {
|
||||
sess.struct_span_err(span, "")
|
||||
}
|
||||
(Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(""),
|
||||
};
|
||||
|
||||
// Check for future incompatibility lints and issue a stronger warning.
|
||||
|
@ -209,7 +238,7 @@ pub fn struct_lint_level<'a>(
|
|||
err.cancel();
|
||||
// Don't continue further, since we don't want to have
|
||||
// `diag_span_note_once` called for a diagnostic that isn't emitted.
|
||||
return err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,7 +328,10 @@ pub fn struct_lint_level<'a>(
|
|||
err.note(&citation);
|
||||
}
|
||||
|
||||
return err;
|
||||
// Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
|
||||
decorate(LintDiagnosticBuilder::new(err));
|
||||
}
|
||||
struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
|
||||
}
|
||||
|
||||
/// Returns whether `span` originates in a foreign crate's external macro.
|
||||
|
|
|
@ -222,11 +222,13 @@ fn late_report_deprecation(
|
|||
return;
|
||||
}
|
||||
|
||||
let mut diag = tcx.struct_span_lint_hir(lint, hir_id, span, message);
|
||||
tcx.struct_span_lint_hir(lint, hir_id, span, |lint| {
|
||||
let mut diag = lint.build(message);
|
||||
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
|
||||
deprecation_suggestion(&mut diag, suggestion, span);
|
||||
}
|
||||
diag.emit();
|
||||
diag.emit()
|
||||
});
|
||||
if hir_id == hir::DUMMY_HIR_ID {
|
||||
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
|
||||
}
|
||||
|
@ -387,8 +389,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Additionally, this function will also check if the item is deprecated. If so, and `id` is
|
||||
/// not `None`, a deprecated lint attached to `id` will be emitted.
|
||||
pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
|
||||
let soft_handler =
|
||||
|lint, span, msg: &_| self.lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg);
|
||||
let soft_handler = |lint, span, msg: &_| {
|
||||
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
|
||||
lint.build(msg).emit()
|
||||
})
|
||||
};
|
||||
match self.eval_stability(def_id, id, span) {
|
||||
EvalResult::Allow => {}
|
||||
EvalResult::Deny { feature, reason, issue, is_soft } => {
|
||||
|
|
|
@ -83,18 +83,15 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
&self,
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
message: &str,
|
||||
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
|
||||
self.struct_generic(tcx, message, None)
|
||||
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
||||
) -> Result<(), ErrorHandled> {
|
||||
self.struct_generic(tcx, message, emit, None)
|
||||
}
|
||||
|
||||
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
|
||||
let err = self.struct_error(tcx, message);
|
||||
match err {
|
||||
Ok(mut err) => {
|
||||
err.emit();
|
||||
ErrorHandled::Reported
|
||||
}
|
||||
Err(err) => err,
|
||||
match self.struct_error(tcx, message, |mut e| e.emit()) {
|
||||
Ok(_) => ErrorHandled::Reported,
|
||||
Err(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,9 +102,11 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
lint_root: hir::HirId,
|
||||
span: Option<Span>,
|
||||
) -> ErrorHandled {
|
||||
let lint = self.struct_generic(tcx, message, Some(lint_root));
|
||||
match lint {
|
||||
Ok(mut lint) => {
|
||||
match self.struct_generic(
|
||||
tcx,
|
||||
message,
|
||||
|mut lint: DiagnosticBuilder<'_>| {
|
||||
// Apply the span.
|
||||
if let Some(span) = span {
|
||||
let primary_spans = lint.span.primary_spans().to_vec();
|
||||
// point at the actual error as the primary span
|
||||
|
@ -121,18 +120,25 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
}
|
||||
}
|
||||
lint.emit();
|
||||
ErrorHandled::Reported
|
||||
}
|
||||
},
|
||||
Some(lint_root),
|
||||
) {
|
||||
Ok(_) => ErrorHandled::Reported,
|
||||
Err(err) => err,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the message passed in via `message`, then adds the span labels for you, before applying
|
||||
/// further modifications in `emit`. It's up to you to call emit(), stash(..), etc. within the
|
||||
/// `emit` method. If you don't need to do any additional processing, just use
|
||||
/// struct_generic.
|
||||
fn struct_generic(
|
||||
&self,
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
message: &str,
|
||||
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
||||
lint_root: Option<hir::HirId>,
|
||||
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
|
||||
) -> Result<(), ErrorHandled> {
|
||||
let must_error = match self.error {
|
||||
InterpError::MachineStop(_) => bug!("CTFE does not stop"),
|
||||
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
||||
|
@ -143,25 +149,8 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
_ => false,
|
||||
};
|
||||
trace!("reporting const eval failure at {:?}", self.span);
|
||||
let mut err = if let (Some(lint_root), false) = (lint_root, must_error) {
|
||||
let hir_id = self
|
||||
.stacktrace
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|frame| frame.lint_root)
|
||||
.next()
|
||||
.unwrap_or(lint_root);
|
||||
tcx.struct_span_lint_hir(
|
||||
rustc_session::lint::builtin::CONST_ERR,
|
||||
hir_id,
|
||||
tcx.span,
|
||||
message,
|
||||
)
|
||||
} else if must_error {
|
||||
struct_error(tcx, &self.error.to_string())
|
||||
} else {
|
||||
struct_error(tcx, message)
|
||||
};
|
||||
|
||||
let add_span_labels = |err: &mut DiagnosticBuilder<'_>| {
|
||||
if !must_error {
|
||||
err.span_label(self.span, self.error.to_string());
|
||||
}
|
||||
|
@ -173,7 +162,36 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
err.span_label(frame_info.call_site, frame_info.to_string());
|
||||
}
|
||||
}
|
||||
Ok(err)
|
||||
};
|
||||
|
||||
if let (Some(lint_root), false) = (lint_root, must_error) {
|
||||
let hir_id = self
|
||||
.stacktrace
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|frame| frame.lint_root)
|
||||
.next()
|
||||
.unwrap_or(lint_root);
|
||||
tcx.struct_span_lint_hir(
|
||||
rustc_session::lint::builtin::CONST_ERR,
|
||||
hir_id,
|
||||
tcx.span,
|
||||
|lint| {
|
||||
let mut err = lint.build(message);
|
||||
add_span_labels(&mut err);
|
||||
emit(err);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let mut err = if must_error {
|
||||
struct_error(tcx, &self.error.to_string())
|
||||
} else {
|
||||
struct_error(tcx, message)
|
||||
};
|
||||
add_span_labels(&mut err);
|
||||
emit(err);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -227,18 +227,21 @@ fn object_safety_violations_for_trait(
|
|||
{
|
||||
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
|
||||
// It's also hard to get a use site span, so we use the method definition span.
|
||||
let mut err = tcx.struct_span_lint_hir(
|
||||
tcx.struct_span_lint_hir(
|
||||
WHERE_CLAUSES_OBJECT_SAFETY,
|
||||
hir::CRATE_HIR_ID,
|
||||
*span,
|
||||
&format!(
|
||||
|lint| {
|
||||
let mut err = lint.build(&format!(
|
||||
"the trait `{}` cannot be made into an object",
|
||||
tcx.def_path_str(trait_def_id)
|
||||
),
|
||||
);
|
||||
));
|
||||
let node = tcx.hir().get_if_local(trait_def_id);
|
||||
let msg = if let Some(hir::Node::Item(item)) = node {
|
||||
err.span_label(item.ident.span, "this trait cannot be made into an object...");
|
||||
err.span_label(
|
||||
item.ident.span,
|
||||
"this trait cannot be made into an object...",
|
||||
);
|
||||
format!("...because {}", violation.error_msg())
|
||||
} else {
|
||||
format!(
|
||||
|
@ -252,12 +255,19 @@ fn object_safety_violations_for_trait(
|
|||
err.help(¬e);
|
||||
}
|
||||
(Some(_), Some((note, Some((sugg, span))))) => {
|
||||
err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
¬e,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// Only provide the help if its a local trait, otherwise it's not actionable.
|
||||
_ => {}
|
||||
}
|
||||
err.emit();
|
||||
},
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::traits::select::IntercrateAmbiguityCause;
|
|||
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
|
||||
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::{self, TyCtxt, TypeFoldable};
|
||||
use rustc::lint::LintDiagnosticBuilder;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
@ -317,6 +318,13 @@ pub(super) fn specialization_graph_provider(
|
|||
};
|
||||
|
||||
if let Some(overlap) = overlap {
|
||||
let impl_span =
|
||||
tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
|
||||
|
||||
// Work to be done after we've built the DiagnosticBuilder. We have to define it
|
||||
// now because the struct_lint methods don't return back the DiagnosticBuilder
|
||||
// that's passed in.
|
||||
let decorate = |err: LintDiagnosticBuilder<'_>| {
|
||||
let msg = format!(
|
||||
"conflicting implementations of trait `{}`{}:{}",
|
||||
overlap.trait_desc,
|
||||
|
@ -329,32 +337,14 @@ pub(super) fn specialization_graph_provider(
|
|||
_ => "",
|
||||
}
|
||||
);
|
||||
let impl_span =
|
||||
tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
|
||||
let mut err = match used_to_be_allowed {
|
||||
None => struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg),
|
||||
Some(kind) => {
|
||||
let lint = match kind {
|
||||
FutureCompatOverlapErrorKind::Issue33140 => {
|
||||
ORDER_DEPENDENT_TRAIT_OBJECTS
|
||||
}
|
||||
FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
|
||||
};
|
||||
tcx.struct_span_lint_hir(
|
||||
lint,
|
||||
tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
|
||||
impl_span,
|
||||
&msg,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mut err = err.build(&msg);
|
||||
match tcx.span_of_impl(overlap.with_impl) {
|
||||
Ok(span) => {
|
||||
err.span_label(
|
||||
tcx.sess.source_map().def_span(span),
|
||||
"first implementation here".to_string(),
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
impl_span,
|
||||
format!(
|
||||
|
@ -367,9 +357,10 @@ pub(super) fn specialization_graph_provider(
|
|||
}
|
||||
Err(cname) => {
|
||||
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
|
||||
Some(s) => {
|
||||
format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
|
||||
}
|
||||
Some(s) => format!(
|
||||
"conflicting implementation in crate `{}`:\n- {}",
|
||||
cname, s
|
||||
),
|
||||
None => format!("conflicting implementation in crate `{}`", cname),
|
||||
};
|
||||
err.note(&msg);
|
||||
|
@ -383,8 +374,29 @@ pub(super) fn specialization_graph_provider(
|
|||
if overlap.involves_placeholder {
|
||||
coherence::add_placeholder_note(&mut err);
|
||||
}
|
||||
err.emit()
|
||||
};
|
||||
|
||||
err.emit();
|
||||
match used_to_be_allowed {
|
||||
None => {
|
||||
let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
|
||||
decorate(LintDiagnosticBuilder::new(err));
|
||||
}
|
||||
Some(kind) => {
|
||||
let lint = match kind {
|
||||
FutureCompatOverlapErrorKind::Issue33140 => {
|
||||
ORDER_DEPENDENT_TRAIT_OBJECTS
|
||||
}
|
||||
FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
|
||||
};
|
||||
tcx.struct_span_lint_hir(
|
||||
lint,
|
||||
tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
|
||||
impl_span,
|
||||
decorate,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
|
||||
|
|
|
@ -41,6 +41,7 @@ use crate::ty::{ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, Pr
|
|||
use crate::ty::{InferConst, ParamConst};
|
||||
use crate::ty::{List, TyKind, TyS};
|
||||
use crate::util::common::ErrorReported;
|
||||
use rustc::lint::LintDiagnosticBuilder;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
|
@ -49,7 +50,6 @@ use rustc_data_structures::stable_hasher::{
|
|||
hash_stable_hashmap, HashStable, StableHasher, StableVec,
|
||||
};
|
||||
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE};
|
||||
|
@ -2551,16 +2551,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
iter.intern_with(|xs| self.intern_goals(xs))
|
||||
}
|
||||
|
||||
pub fn lint_hir(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
) {
|
||||
self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
|
||||
}
|
||||
|
||||
/// Walks upwards from `id` to find a node which might change lint levels with attributes.
|
||||
/// It stops at `bound` and just returns it if reached.
|
||||
pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
|
||||
|
@ -2604,20 +2594,20 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
let (level, src) = self.lint_level_at_node(lint, hir_id);
|
||||
struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
|
||||
struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate);
|
||||
}
|
||||
|
||||
pub fn struct_lint_node(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
id: HirId,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
let (level, src) = self.lint_level_at_node(lint, id);
|
||||
struct_lint_level(self.sess, lint, level, src, None, msg)
|
||||
struct_lint_level(self.sess, lint, level, src, None, decorate);
|
||||
}
|
||||
|
||||
pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
|
||||
|
|
|
@ -37,7 +37,9 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
|||
.span_label(span, format!("expected one of {}", expected.join(", ")))
|
||||
.emit();
|
||||
}
|
||||
AttrError::MissingSince => struct_span_err!(diag, span, E0542, "missing 'since'").emit(),
|
||||
AttrError::MissingSince => {
|
||||
struct_span_err!(diag, span, E0542, "missing 'since'").emit();
|
||||
}
|
||||
AttrError::MissingFeature => {
|
||||
struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
|
||||
}
|
||||
|
@ -639,7 +641,7 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
|
|||
let (cfg, feature, has_feature) = gated_cfg;
|
||||
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
||||
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
|
||||
feature_err(sess, *feature, cfg_span, &explain).emit()
|
||||
feature_err(sess, *feature, cfg_span, &explain).emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -194,6 +194,7 @@ impl Diagnostic {
|
|||
found_extra: &dyn fmt::Display,
|
||||
) -> &mut Self {
|
||||
let expected_label = format!("expected {}", expected_label);
|
||||
|
||||
let found_label = format!("found {}", found_label);
|
||||
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
|
||||
(expected_label.len() - found_label.len(), 0)
|
||||
|
|
|
@ -106,7 +106,11 @@ impl<'a> DiagnosticBuilder<'a> {
|
|||
///
|
||||
/// See `emit` and `delay_as_bug` for details.
|
||||
pub fn emit_unless(&mut self, delay: bool) {
|
||||
if delay { self.delay_as_bug() } else { self.emit() }
|
||||
if delay {
|
||||
self.delay_as_bug();
|
||||
} else {
|
||||
self.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Stashes diagnostic for possible later improvement in a different,
|
||||
|
@ -369,6 +373,7 @@ impl<'a> DiagnosticBuilder<'a> {
|
|||
/// Creates a new `DiagnosticBuilder` with an already constructed
|
||||
/// diagnostic.
|
||||
crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
|
||||
debug!("Created new diagnostic");
|
||||
DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
|
||||
handler,
|
||||
diagnostic,
|
||||
|
|
|
@ -1113,7 +1113,11 @@ pub fn expr_to_string(
|
|||
err_msg: &str,
|
||||
) -> Option<(Symbol, ast::StrStyle)> {
|
||||
expr_to_spanned_string(cx, expr, err_msg)
|
||||
.map_err(|err| err.map(|mut err| err.emit()))
|
||||
.map_err(|err| {
|
||||
err.map(|mut err| {
|
||||
err.emit();
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
.map(|(symbol, style, _)| (symbol, style))
|
||||
}
|
||||
|
|
|
@ -77,13 +77,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter {
|
|||
// to an array or to a slice.
|
||||
_ => bug!("array type coerced to something other than array or slice"),
|
||||
};
|
||||
let msg = format!(
|
||||
cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
|
||||
lint.build(&format!(
|
||||
"this method call currently resolves to `<&{} as IntoIterator>::into_iter` (due \
|
||||
to autoref coercions), but that might change in the future when \
|
||||
`IntoIterator` impls for arrays are added.",
|
||||
target,
|
||||
);
|
||||
cx.struct_span_lint(ARRAY_INTO_ITER, *span, &msg)
|
||||
))
|
||||
.span_suggestion(
|
||||
call.ident.span,
|
||||
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
|
||||
|
@ -91,6 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter {
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::LintDiagnosticBuilder;
|
||||
use rustc::traits::misc::can_type_implement_copy;
|
||||
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
|
||||
use rustc_ast_pretty::pprust::{self, expr_to_string};
|
||||
|
@ -77,7 +78,8 @@ impl EarlyLintPass for WhileTrue {
|
|||
if !lit.span.from_expansion() {
|
||||
let msg = "denote infinite loops with `loop { ... }`";
|
||||
let condition_span = cx.sess.source_map().def_span(e.span);
|
||||
cx.struct_span_lint(WHILE_TRUE, condition_span, msg)
|
||||
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
|
||||
lint.build(msg)
|
||||
.span_suggestion_short(
|
||||
condition_span,
|
||||
"use `loop`",
|
||||
|
@ -85,6 +87,7 @@ impl EarlyLintPass for WhileTrue {
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +107,9 @@ impl BoxPointers {
|
|||
fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
|
||||
for leaf_ty in ty.walk() {
|
||||
if leaf_ty.is_box() {
|
||||
let m = format!("type uses owned (Box type) pointers: {}", ty);
|
||||
cx.span_lint(BOX_POINTERS, span, &m);
|
||||
cx.struct_span_lint(BOX_POINTERS, span, |lint| {
|
||||
lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,11 +178,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
|
|||
if cx.tcx.find_field_index(ident, &variant)
|
||||
== Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables))
|
||||
{
|
||||
let mut err = cx.struct_span_lint(
|
||||
NON_SHORTHAND_FIELD_PATTERNS,
|
||||
fieldpat.span,
|
||||
&format!("the `{}:` in this pattern is redundant", ident),
|
||||
);
|
||||
cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
|
||||
let mut err = lint
|
||||
.build(&format!("the `{}:` in this pattern is redundant", ident));
|
||||
let binding = match binding_annot {
|
||||
hir::BindingAnnotation::Unannotated => None,
|
||||
hir::BindingAnnotation::Mutable => Some("mut"),
|
||||
|
@ -197,6 +199,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,26 +216,32 @@ declare_lint! {
|
|||
declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
|
||||
|
||||
impl UnsafeCode {
|
||||
fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) {
|
||||
fn report_unsafe(
|
||||
&self,
|
||||
cx: &EarlyContext<'_>,
|
||||
span: Span,
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
// This comes from a macro that has `#[allow_internal_unsafe]`.
|
||||
if span.allows_unsafe() {
|
||||
return;
|
||||
}
|
||||
|
||||
cx.span_lint(UNSAFE_CODE, span, desc);
|
||||
cx.struct_span_lint(UNSAFE_CODE, span, decorate);
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for UnsafeCode {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
if attr.check_name(sym::allow_internal_unsafe) {
|
||||
self.report_unsafe(
|
||||
cx,
|
||||
attr.span,
|
||||
self.report_unsafe(cx, attr.span, |lint| {
|
||||
lint.build(
|
||||
"`allow_internal_unsafe` allows defining \
|
||||
macros using unsafe without triggering \
|
||||
the `unsafe_code` lint at their call site",
|
||||
);
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +249,9 @@ impl EarlyLintPass for UnsafeCode {
|
|||
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, "usage of an `unsafe` block");
|
||||
self.report_unsafe(cx, blk.span, |lint| {
|
||||
lint.build("usage of an `unsafe` block").emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,11 +259,15 @@ impl EarlyLintPass for UnsafeCode {
|
|||
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
|
||||
match it.kind {
|
||||
ast::ItemKind::Trait(_, ast::Unsafety::Unsafe, ..) => {
|
||||
self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
|
||||
self.report_unsafe(cx, it.span, |lint| {
|
||||
lint.build("declaration of an `unsafe` trait").emit()
|
||||
})
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl { unsafety: ast::Unsafety::Unsafe, .. } => {
|
||||
self.report_unsafe(cx, it.span, "implementation of an `unsafe` trait")
|
||||
self.report_unsafe(cx, it.span, |lint| {
|
||||
lint.build("implementation of an `unsafe` trait").emit()
|
||||
})
|
||||
}
|
||||
|
||||
_ => return,
|
||||
|
@ -274,7 +289,7 @@ impl EarlyLintPass for UnsafeCode {
|
|||
FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
|
||||
FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
|
||||
};
|
||||
self.report_unsafe(cx, span, msg);
|
||||
self.report_unsafe(cx, span, |lint| lint.build(msg).emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,11 +374,9 @@ impl MissingDoc {
|
|||
|
||||
let has_doc = attrs.iter().any(|a| has_doc(a));
|
||||
if !has_doc {
|
||||
cx.span_lint(
|
||||
MISSING_DOCS,
|
||||
cx.tcx.sess.source_map().def_span(sp),
|
||||
&format!("missing documentation for {}", desc),
|
||||
);
|
||||
cx.struct_span_lint(MISSING_DOCS, cx.tcx.sess.source_map().def_span(sp), |lint| {
|
||||
lint.build(&format!("missing documentation for {}", desc)).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -391,10 +404,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
|||
for macro_def in krate.exported_macros {
|
||||
let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
|
||||
if !has_doc {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
MISSING_DOCS,
|
||||
cx.tcx.sess.source_map().def_span(macro_def.span),
|
||||
"missing documentation for macro",
|
||||
|lint| lint.build("missing documentation for macro").emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -542,12 +555,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
|
|||
return;
|
||||
}
|
||||
if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
|
||||
cx.span_lint(
|
||||
MISSING_COPY_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
|
||||
lint.build(
|
||||
"type could implement `Copy`; consider adding `impl \
|
||||
Copy`",
|
||||
)
|
||||
.emit()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -596,15 +610,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
|
|||
}
|
||||
|
||||
if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) {
|
||||
cx.span_lint(
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
&format!(
|
||||
cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
|
||||
lint.build(&format!(
|
||||
"type does not implement `{}`; consider adding `#[derive(Debug)]` \
|
||||
or a manual implementation",
|
||||
cx.tcx.def_path_str(debug)
|
||||
),
|
||||
);
|
||||
))
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -632,17 +645,16 @@ impl EarlyLintPass for AnonymousParameters {
|
|||
match arg.pat.kind {
|
||||
ast::PatKind::Ident(_, ident, None) => {
|
||||
if ident.name == kw::Invalid {
|
||||
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
|
||||
let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
|
||||
|
||||
let (ty_snip, appl) = if let Ok(snip) = ty_snip {
|
||||
(snip, Applicability::MachineApplicable)
|
||||
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
|
||||
(snip.as_str(), Applicability::MachineApplicable)
|
||||
} else {
|
||||
("<type>".to_owned(), Applicability::HasPlaceholders)
|
||||
("<type>", Applicability::HasPlaceholders)
|
||||
};
|
||||
|
||||
cx.struct_span_lint(
|
||||
ANONYMOUS_PARAMETERS,
|
||||
arg.pat.span,
|
||||
lint.build(
|
||||
"anonymous parameters are deprecated and will be \
|
||||
removed in the next edition.",
|
||||
)
|
||||
|
@ -654,6 +666,7 @@ impl EarlyLintPass for AnonymousParameters {
|
|||
appl,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
@ -687,7 +700,8 @@ fn lint_deprecated_attr(
|
|||
msg: &str,
|
||||
suggestion: Option<&str>,
|
||||
) {
|
||||
cx.struct_span_lint(DEPRECATED, attr.span, &msg)
|
||||
cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
|
||||
lint.build(msg)
|
||||
.span_suggestion_short(
|
||||
attr.span,
|
||||
suggestion.unwrap_or("remove this attribute"),
|
||||
|
@ -695,6 +709,7 @@ fn lint_deprecated_attr(
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
|
||||
impl EarlyLintPass for DeprecatedAttr {
|
||||
|
@ -759,21 +774,20 @@ impl UnusedDocComment {
|
|||
let span = sugared_span.take().unwrap_or_else(|| attr.span);
|
||||
|
||||
if attr.is_doc_comment() || attr.check_name(sym::doc) {
|
||||
let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment");
|
||||
|
||||
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
|
||||
let mut err = lint.build("unused doc comment");
|
||||
err.span_label(
|
||||
node_span,
|
||||
format!("rustdoc does not generate documentation for {}", node_kind),
|
||||
);
|
||||
|
||||
if is_macro_expansion {
|
||||
err.help(
|
||||
"to document an item produced by a macro, \
|
||||
the macro must produce the documentation as part of its expansion",
|
||||
);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -831,20 +845,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
|
|||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
||||
let mut err = cx.struct_span_lint(
|
||||
NO_MANGLE_GENERIC_ITEMS,
|
||||
it.span,
|
||||
cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, it.span, |lint| {
|
||||
lint.build(
|
||||
"functions generic over types or consts must be mangled",
|
||||
);
|
||||
err.span_suggestion_short(
|
||||
)
|
||||
.span_suggestion_short(
|
||||
no_mangle_attr.span,
|
||||
"remove this attribute",
|
||||
String::new(),
|
||||
// Use of `#[no_mangle]` suggests FFI intent; correct
|
||||
// fix may be to monomorphize source by hand
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -855,8 +869,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
|
|||
if attr::contains_name(&it.attrs, sym::no_mangle) {
|
||||
// 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(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
|
||||
let msg = "const items should never be `#[no_mangle]`";
|
||||
let mut err = cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
|
||||
let mut err = lint.build(msg);
|
||||
|
||||
// account for "pub const" (#45562)
|
||||
let start = cx
|
||||
|
@ -875,6 +890,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -894,12 +910,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
|
|||
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
|
||||
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||
|
||||
let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
|
||||
consider instead using an UnsafeCell";
|
||||
match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind)) {
|
||||
Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => {
|
||||
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
|
||||
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
|
||||
let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
|
||||
consider instead using an UnsafeCell";
|
||||
cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
@ -949,7 +967,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
|
|||
if attr.check_name(sym::feature) {
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
|
||||
ctx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
|
||||
lint.build("unstable feature").emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -984,11 +1004,8 @@ impl UnreachablePub {
|
|||
applicability = Applicability::MaybeIncorrect;
|
||||
}
|
||||
let def_span = cx.tcx.sess.source_map().def_span(span);
|
||||
let mut err = cx.struct_span_lint(
|
||||
UNREACHABLE_PUB,
|
||||
def_span,
|
||||
&format!("unreachable `pub` {}", what),
|
||||
);
|
||||
cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
|
||||
let mut err = lint.build(&format!("unreachable `pub` {}", what));
|
||||
let replacement = if cx.tcx.features().crate_visibility_modifier {
|
||||
"crate"
|
||||
} else {
|
||||
|
@ -1006,6 +1023,7 @@ impl UnreachablePub {
|
|||
err.help("or consider exporting it for use by other crates");
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1114,17 +1132,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
|
|||
let mut suggested_changing_assoc_types = false;
|
||||
// There must not be a where clause
|
||||
if !type_alias_generics.where_clause.predicates.is_empty() {
|
||||
cx.lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
|lint| {
|
||||
let mut err = lint.build("where clauses are not enforced in type aliases");
|
||||
let spans: Vec<_> = type_alias_generics
|
||||
.where_clause
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|pred| pred.span())
|
||||
.collect();
|
||||
let mut err = cx.struct_span_lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
spans,
|
||||
"where clauses are not enforced in type aliases",
|
||||
);
|
||||
err.set_span(spans);
|
||||
err.span_suggestion(
|
||||
type_alias_generics.where_clause.span_for_predicates_or_empty_place(),
|
||||
"the clause will not be checked when the type alias is used, and should be removed",
|
||||
|
@ -1136,6 +1154,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
|
|||
suggested_changing_assoc_types = true;
|
||||
}
|
||||
err.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
// The parameters must not have bounds
|
||||
for param in type_alias_generics.params.iter() {
|
||||
|
@ -1148,11 +1168,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
|
|||
})
|
||||
.collect();
|
||||
if !spans.is_empty() {
|
||||
let mut err = cx.struct_span_lint(
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
spans,
|
||||
"bounds on generic parameters are not enforced in type aliases",
|
||||
);
|
||||
cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, |lint| {
|
||||
let mut err =
|
||||
lint.build("bounds on generic parameters are not enforced in type aliases");
|
||||
let msg = "the bound will not be checked when the type alias is used, \
|
||||
and should be removed";
|
||||
err.multipart_suggestion(&msg, suggestion, Applicability::MachineApplicable);
|
||||
|
@ -1161,6 +1179,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
|
|||
suggested_changing_assoc_types = true;
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1232,15 +1251,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
|||
ConstEvaluatable(..) => continue,
|
||||
};
|
||||
if predicate.is_global() {
|
||||
cx.span_lint(
|
||||
TRIVIAL_BOUNDS,
|
||||
span,
|
||||
&format!(
|
||||
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
|
||||
lint.build(&format!(
|
||||
"{} bound {} does not depend on any type \
|
||||
or lifetime parameters",
|
||||
predicate_kind_name, predicate
|
||||
),
|
||||
);
|
||||
))
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1317,28 +1335,32 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
|
|||
let suggestion = "use `..=` for an inclusive range";
|
||||
if parenthesise {
|
||||
self.node_id = Some(pat.id);
|
||||
cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
|
||||
let end = expr_to_string(&end);
|
||||
let replace = match start {
|
||||
Some(start) => format!("&({}..={})", expr_to_string(&start), end),
|
||||
None => format!("&(..={})", end),
|
||||
};
|
||||
let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg);
|
||||
err.span_suggestion(
|
||||
lint.build(msg)
|
||||
.span_suggestion(
|
||||
pat.span,
|
||||
suggestion,
|
||||
replace,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
} else {
|
||||
let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg);
|
||||
err.span_suggestion_short(
|
||||
cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
|
||||
lint.build(msg)
|
||||
.span_suggestion_short(
|
||||
join,
|
||||
suggestion,
|
||||
"..=".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1384,7 +1406,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems {
|
|||
}
|
||||
|
||||
if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) {
|
||||
cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, "cannot test inner items").emit();
|
||||
cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
|
||||
lint.build("cannot test inner items").emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1465,18 +1489,16 @@ impl KeywordIdents {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut lint = cx.struct_span_lint(
|
||||
KEYWORD_IDENTS,
|
||||
ident.span,
|
||||
&format!("`{}` is a keyword in the {} edition", ident, next_edition),
|
||||
);
|
||||
lint.span_suggestion(
|
||||
cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
|
||||
lint.build(&format!("`{}` is a keyword in the {} edition", ident, next_edition))
|
||||
.span_suggestion(
|
||||
ident.span,
|
||||
"you can use a raw identifier to stay compatible",
|
||||
format!("r#{}", ident),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
lint.emit()
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1780,17 +1802,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
|
|||
}
|
||||
|
||||
if !lint_spans.is_empty() {
|
||||
let mut err = cx.struct_span_lint(
|
||||
EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
lint_spans.clone(),
|
||||
"outlives requirements can be inferred",
|
||||
);
|
||||
err.multipart_suggestion(
|
||||
if bound_count == 1 { "remove this bound" } else { "remove these bounds" },
|
||||
lint_spans.into_iter().map(|span| (span, "".to_owned())).collect::<Vec<_>>(),
|
||||
cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
|
||||
lint.build("outlives requirements can be inferred")
|
||||
.multipart_suggestion(
|
||||
if bound_count == 1 {
|
||||
"remove this bound"
|
||||
} else {
|
||||
"remove these bounds"
|
||||
},
|
||||
lint_spans
|
||||
.into_iter()
|
||||
.map(|span| (span, "".to_owned()))
|
||||
.collect::<Vec<_>>(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1817,15 +1844,13 @@ impl EarlyLintPass for IncompleteFeatures {
|
|||
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
|
||||
.filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
|
||||
.for_each(|(name, &span)| {
|
||||
cx.struct_span_lint(
|
||||
INCOMPLETE_FEATURES,
|
||||
span,
|
||||
&format!(
|
||||
cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
|
||||
lint.build(&format!(
|
||||
"the feature `{}` is incomplete and may cause the compiler to crash",
|
||||
name,
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
))
|
||||
.emit()
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2015,18 +2040,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
|||
// We are extremely conservative with what we warn about.
|
||||
let conjured_ty = cx.tables.expr_ty(expr);
|
||||
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
|
||||
let mut err = cx.struct_span_lint(
|
||||
INVALID_VALUE,
|
||||
expr.span,
|
||||
&format!(
|
||||
cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
|
||||
let mut err = lint.build(&format!(
|
||||
"the type `{}` does not permit {}",
|
||||
conjured_ty,
|
||||
match init {
|
||||
InitKind::Zeroed => "zero-initialization",
|
||||
InitKind::Uninit => "being left uninitialized",
|
||||
},
|
||||
),
|
||||
);
|
||||
));
|
||||
err.span_label(expr.span, "this code causes undefined behavior when executed");
|
||||
err.span_label(
|
||||
expr.span,
|
||||
|
@ -2039,6 +2061,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
|||
err.note(&msg);
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,14 @@ use crate::levels::LintLevelsBuilder;
|
|||
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
|
||||
use rustc::hir::map::definitions::{DefPathData, DisambiguatedDefPathData};
|
||||
use rustc::lint::add_elided_lifetime_in_path_suggestion;
|
||||
use rustc::lint::LintDiagnosticBuilder;
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
use rustc::middle::stability;
|
||||
use rustc::ty::layout::{LayoutError, LayoutOf, TyLayout};
|
||||
use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
|
@ -473,19 +474,18 @@ pub trait LintContext: Sized {
|
|||
fn sess(&self) -> &Session;
|
||||
fn lints(&self) -> &LintStore;
|
||||
|
||||
fn lookup_and_emit<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: Option<S>, msg: &str) {
|
||||
self.lookup(lint, span, msg).emit();
|
||||
}
|
||||
|
||||
fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(
|
||||
fn lookup_with_diagnostics(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<S>,
|
||||
msg: &str,
|
||||
span: Option<impl Into<MultiSpan>>,
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
diagnostic: BuiltinLintDiagnostics,
|
||||
) {
|
||||
let mut db = self.lookup(lint, span, msg);
|
||||
self.lookup(lint, span, |lint| {
|
||||
// We first generate a blank diagnostic.
|
||||
let mut db = lint.build("");
|
||||
|
||||
// Now, set up surrounding context.
|
||||
let sess = self.sess();
|
||||
match diagnostic {
|
||||
BuiltinLintDiagnostics::Normal => (),
|
||||
|
@ -504,7 +504,8 @@ pub trait LintContext: Sized {
|
|||
Ok(ref s) => {
|
||||
// FIXME(Manishearth) ideally the emitting code
|
||||
// can tell us whether or not this is global
|
||||
let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
|
||||
let opt_colon =
|
||||
if s.trim_start().starts_with("::") { "" } else { "::" };
|
||||
|
||||
(format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable)
|
||||
}
|
||||
|
@ -518,7 +519,9 @@ pub trait LintContext: Sized {
|
|||
"names from parent modules are not accessible without an explicit import",
|
||||
);
|
||||
}
|
||||
BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
|
||||
BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(
|
||||
span_def,
|
||||
) => {
|
||||
db.span_note(span_def, "the macro is defined here");
|
||||
}
|
||||
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
|
@ -563,60 +566,31 @@ pub trait LintContext: Sized {
|
|||
stability::deprecation_suggestion(&mut db, suggestion, span)
|
||||
}
|
||||
}
|
||||
|
||||
db.emit();
|
||||
// Rewrap `db`, and pass control to the user.
|
||||
decorate(LintDiagnosticBuilder::new(db));
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
|
||||
// set the span in their `decorate` function (preferably using set_span).
|
||||
fn lookup<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<S>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'_>;
|
||||
|
||||
/// Emit a lint at the appropriate level, for a particular span.
|
||||
fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
|
||||
self.lookup_and_emit(lint, Some(span), msg);
|
||||
}
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
);
|
||||
|
||||
fn struct_span_lint<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.lookup(lint, Some(span), msg)
|
||||
}
|
||||
|
||||
/// Emit a lint and note at the appropriate level, for a particular span.
|
||||
fn span_lint_note(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
note_span: Span,
|
||||
note: &str,
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
let mut err = self.lookup(lint, Some(span), msg);
|
||||
if note_span == span {
|
||||
err.note(note);
|
||||
} else {
|
||||
err.span_note(note_span, note);
|
||||
self.lookup(lint, Some(span), decorate);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Emit a lint and help at the appropriate level, for a particular span.
|
||||
fn span_lint_help(&self, lint: &'static Lint, span: Span, msg: &str, help: &str) {
|
||||
let mut err = self.lookup(lint, Some(span), msg);
|
||||
self.span_lint(lint, span, msg);
|
||||
err.span_help(span, help);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Emit a lint at the appropriate level, with no associated span.
|
||||
fn lint(&self, lint: &'static Lint, msg: &str) {
|
||||
self.lookup_and_emit(lint, None as Option<Span>, msg);
|
||||
fn lint(&self, lint: &'static Lint, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>)) {
|
||||
self.lookup(lint, None as Option<Span>, decorate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -654,13 +628,13 @@ impl LintContext for LateContext<'_, '_> {
|
|||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<S>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
let hir_id = self.last_node_with_lint_attrs;
|
||||
|
||||
match span {
|
||||
Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg),
|
||||
None => self.tcx.struct_lint_node(lint, hir_id, msg),
|
||||
Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, decorate),
|
||||
None => self.tcx.struct_lint_node(lint, hir_id, decorate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -681,9 +655,9 @@ impl LintContext for EarlyContext<'_> {
|
|||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<S>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
self.builder.struct_lint(lint, span.map(|s| s.into()), decorate)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,11 +37,18 @@ struct EarlyContextAndPass<'a, T: EarlyLintPass> {
|
|||
impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
||||
fn check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
self.context.lookup_and_emit_with_diagnostics(
|
||||
early_lint.lint_id.lint,
|
||||
Some(early_lint.span.clone()),
|
||||
&early_lint.msg,
|
||||
early_lint.diagnostic,
|
||||
let rustc_session::lint::BufferedEarlyLint {
|
||||
span,
|
||||
msg,
|
||||
node_id: _,
|
||||
lint_id,
|
||||
diagnostic,
|
||||
} = early_lint;
|
||||
self.context.lookup_with_diagnostics(
|
||||
lint_id.lint,
|
||||
Some(span),
|
||||
|lint| lint.build(&msg).emit(),
|
||||
diagnostic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,16 +37,22 @@ impl_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);
|
|||
impl EarlyLintPass for DefaultHashTypes {
|
||||
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
|
||||
if let Some(replace) = self.map.get(&ident.name) {
|
||||
cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, |lint| {
|
||||
// FIXME: We can avoid a copy here. Would require us to take String instead of &str.
|
||||
let msg = format!("Prefer {} over {}, it has better performance", replace, ident);
|
||||
let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
|
||||
db.span_suggestion(
|
||||
lint.build(&msg)
|
||||
.span_suggestion(
|
||||
ident.span,
|
||||
"use",
|
||||
replace.to_string(),
|
||||
Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
|
||||
);
|
||||
db.note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
|
||||
)
|
||||
.note(&format!(
|
||||
"a `use rustc_data_structures::fx::{}` may be necessary",
|
||||
replace
|
||||
))
|
||||
.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +91,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
|||
if let Some(last) = segments.last() {
|
||||
let span = path.span.with_hi(last.ident.span.hi());
|
||||
if lint_ty_kind_usage(cx, last) {
|
||||
cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, "usage of `ty::TyKind::<kind>`")
|
||||
cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, |lint| {
|
||||
lint.build("usage of `ty::TyKind::<kind>`")
|
||||
.span_suggestion(
|
||||
span,
|
||||
"try using ty::<kind> directly",
|
||||
|
@ -93,6 +100,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
|||
Applicability::MaybeIncorrect, // ty maybe needs an import
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,24 +111,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
|||
if let QPath::Resolved(_, path) = qpath {
|
||||
if let Some(last) = path.segments.iter().last() {
|
||||
if lint_ty_kind_usage(cx, last) {
|
||||
cx.struct_span_lint(
|
||||
USAGE_OF_TY_TYKIND,
|
||||
path.span,
|
||||
"usage of `ty::TyKind`",
|
||||
)
|
||||
cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
|
||||
lint.build("usage of `ty::TyKind`")
|
||||
.help("try using `Ty` instead")
|
||||
.emit();
|
||||
})
|
||||
} else {
|
||||
if ty.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
|
||||
if path.segments.len() > 1 {
|
||||
cx.struct_span_lint(
|
||||
USAGE_OF_QUALIFIED_TY,
|
||||
path.span,
|
||||
&format!("usage of qualified `ty::{}`", t),
|
||||
)
|
||||
cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
|
||||
lint.build(&format!("usage of qualified `ty::{}`", t))
|
||||
.span_suggestion(
|
||||
path.span,
|
||||
"try using it unqualified",
|
||||
|
@ -129,6 +132,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
|||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,11 +146,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
|||
}
|
||||
}
|
||||
if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
|
||||
cx.struct_span_lint(
|
||||
TY_PASS_BY_REFERENCE,
|
||||
ty.span,
|
||||
&format!("passing `{}` by reference", t),
|
||||
)
|
||||
cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| {
|
||||
lint.build(&format!("passing `{}` by reference", t))
|
||||
.span_suggestion(
|
||||
ty.span,
|
||||
"try passing by value",
|
||||
|
@ -155,6 +156,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
|||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -234,10 +236,12 @@ impl EarlyLintPass for LintPassImpl {
|
|||
cx.struct_span_lint(
|
||||
LINT_PASS_IMPL_WITHOUT_MACRO,
|
||||
lint_pass.path.span,
|
||||
"implementing `LintPass` by hand",
|
||||
)
|
||||
|lint| {
|
||||
lint.build("implementing `LintPass` by hand")
|
||||
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use crate::context::{CheckLintNameResult, LintStore};
|
||||
use crate::late::unerased_lint_store;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::LintDiagnosticBuilder;
|
||||
use rustc::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_hir::{intravisit, HirId};
|
||||
|
@ -39,8 +40,8 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
|||
tcx.arena.alloc(builder.levels.build_map())
|
||||
}
|
||||
|
||||
pub struct LintLevelsBuilder<'a> {
|
||||
sess: &'a Session,
|
||||
pub struct LintLevelsBuilder<'s> {
|
||||
sess: &'s Session,
|
||||
sets: LintLevelSets,
|
||||
id_to_set: FxHashMap<HirId, u32>,
|
||||
cur: u32,
|
||||
|
@ -52,8 +53,8 @@ pub struct BuilderPush {
|
|||
pub changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> LintLevelsBuilder<'a> {
|
||||
pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self {
|
||||
impl<'s> LintLevelsBuilder<'s> {
|
||||
pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &LintStore) -> Self {
|
||||
let mut builder = LintLevelsBuilder {
|
||||
sess,
|
||||
sets: LintLevelSets::new(),
|
||||
|
@ -233,20 +234,20 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
||||
let (lvl, src) =
|
||||
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
|
||||
let msg = format!(
|
||||
"lint name `{}` is deprecated \
|
||||
and may not have an effect in the future. \
|
||||
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
|
||||
name
|
||||
);
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
lvl,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
)
|
||||
|lint| {
|
||||
let msg = format!(
|
||||
"lint name `{}` is deprecated \
|
||||
and may not have an effect in the future. \
|
||||
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
|
||||
name
|
||||
);
|
||||
lint.build(&msg)
|
||||
.span_suggestion(
|
||||
li.span(),
|
||||
"change it to",
|
||||
|
@ -254,6 +255,8 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(&new_lint_name),
|
||||
|
@ -279,14 +282,14 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
||||
let (level, src) =
|
||||
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
|
||||
let mut err = struct_lint_level(
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
|lint| {
|
||||
let mut err = lint.build(&msg);
|
||||
if let Some(new_name) = renamed {
|
||||
err.span_suggestion(
|
||||
li.span(),
|
||||
|
@ -296,21 +299,21 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
);
|
||||
}
|
||||
err.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
CheckLintNameResult::NoLint(suggestion) => {
|
||||
let lint = builtin::UNKNOWN_LINTS;
|
||||
let (level, src) =
|
||||
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
|
||||
let msg = format!("unknown lint: `{}`", name);
|
||||
let mut db = struct_lint_level(
|
||||
struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
|
||||
|lint| {
|
||||
let mut db = lint.build(&format!("unknown lint: `{}`", name));
|
||||
if let Some(suggestion) = suggestion {
|
||||
db.span_suggestion(
|
||||
li.span(),
|
||||
|
@ -319,8 +322,9 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
db.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,10 +394,10 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<MultiSpan>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
) {
|
||||
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
|
||||
struct_lint_level(self.sess, lint, level, src, span, msg)
|
||||
struct_lint_level(self.sess, lint, level, src, span, decorate)
|
||||
}
|
||||
|
||||
/// Registers the ID provided with the current set of lints stored in
|
||||
|
|
|
@ -22,19 +22,13 @@ impl EarlyLintPass for NonAsciiIdents {
|
|||
if name_str.is_ascii() {
|
||||
return;
|
||||
}
|
||||
cx.struct_span_lint(
|
||||
NON_ASCII_IDENTS,
|
||||
ident.span,
|
||||
"identifier contains non-ASCII characters",
|
||||
)
|
||||
.emit();
|
||||
cx.struct_span_lint(NON_ASCII_IDENTS, ident.span, |lint| {
|
||||
lint.build("identifier contains non-ASCII characters").emit()
|
||||
});
|
||||
if !name_str.chars().all(GeneralSecurityProfile::identifier_allowed) {
|
||||
cx.struct_span_lint(
|
||||
UNCOMMON_CODEPOINTS,
|
||||
ident.span,
|
||||
"identifier contains uncommon Unicode codepoints",
|
||||
)
|
||||
.emit();
|
||||
cx.struct_span_lint(UNCOMMON_CODEPOINTS, ident.span, |lint| {
|
||||
lint.build("identifier contains uncommon Unicode codepoints").emit()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,15 +107,17 @@ impl NonCamelCaseTypes {
|
|||
let name = &ident.name.as_str();
|
||||
|
||||
if !is_camel_case(name) {
|
||||
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
|
||||
let msg = format!("{} `{}` should have an upper camel case name", sort, name);
|
||||
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, &msg)
|
||||
lint.build(&msg)
|
||||
.span_suggestion(
|
||||
ident.span,
|
||||
"convert the identifier to upper camel case",
|
||||
to_camel_case(name),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
.emit()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,11 +225,10 @@ impl NonSnakeCase {
|
|||
let name = &ident.name.as_str();
|
||||
|
||||
if !is_snake_case(name) {
|
||||
cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| {
|
||||
let sc = NonSnakeCase::to_snake_case(name);
|
||||
|
||||
let msg = format!("{} `{}` should have a snake case name", sort, name);
|
||||
let mut err = cx.struct_span_lint(NON_SNAKE_CASE, ident.span, &msg);
|
||||
|
||||
let mut err = lint.build(&msg);
|
||||
// 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() {
|
||||
|
@ -242,6 +243,7 @@ impl NonSnakeCase {
|
|||
}
|
||||
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -386,12 +388,10 @@ declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]);
|
|||
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(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
|
||||
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
|
||||
|
||||
let msg = format!("{} `{}` should have an upper case name", sort, name);
|
||||
cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, &msg)
|
||||
lint.build(&format!("{} `{}` should have an upper case name", sort, name))
|
||||
.span_suggestion(
|
||||
ident.span,
|
||||
"convert the identifier to upper case",
|
||||
|
@ -399,6 +399,7 @@ impl NonUpperCaseGlobals {
|
|||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ impl EarlyLintPass for RedundantSemicolon {
|
|||
} else {
|
||||
"unnecessary trailing semicolon"
|
||||
};
|
||||
let mut err = cx.struct_span_lint(REDUNDANT_SEMICOLON, stmt.span, &msg);
|
||||
cx.struct_span_lint(REDUNDANT_SEMICOLON, stmt.span, |lint| {
|
||||
let mut err = lint.build(&msg);
|
||||
let suggest_msg = if multiple {
|
||||
"remove these semicolons"
|
||||
} else {
|
||||
|
@ -39,6 +40,7 @@ impl EarlyLintPass for RedundantSemicolon {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>(
|
|||
) -> bool {
|
||||
// We only want to handle exclusive (`..`) ranges,
|
||||
// which are represented as `ExprKind::Struct`.
|
||||
let mut overwritten = false;
|
||||
if let ExprKind::Struct(_, eps, _) = &parent_expr.kind {
|
||||
if eps.len() != 2 {
|
||||
return false;
|
||||
|
@ -75,11 +76,8 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>(
|
|||
// (`..=`) instead only if it is the `end` that is
|
||||
// overflowing and only by 1.
|
||||
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
|
||||
let mut err = cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
parent_expr.span,
|
||||
&format!("range endpoint is out of range for `{}`", ty),
|
||||
);
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| {
|
||||
let mut err = lint.build(&format!("range endpoint is out of range for `{}`", ty));
|
||||
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
|
||||
use ast::{LitIntType, LitKind};
|
||||
// We need to preserve the literal's suffix,
|
||||
|
@ -98,12 +96,12 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>(
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
return true;
|
||||
overwritten = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
overwritten
|
||||
}
|
||||
|
||||
// For `isize` & `usize`, be conservative with the warnings, so that the
|
||||
|
@ -153,6 +151,7 @@ fn report_bin_hex_error(
|
|||
negative: bool,
|
||||
) {
|
||||
let size = layout::Integer::from_attr(&cx.tcx, ty).size();
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, expr.span, |lint| {
|
||||
let (t, actually) = match ty {
|
||||
attr::IntType::SignedInt(t) => {
|
||||
let actually = sign_extend(val, size) as i128;
|
||||
|
@ -163,17 +162,14 @@ fn report_bin_hex_error(
|
|||
(t.name_str(), actually.to_string())
|
||||
}
|
||||
};
|
||||
let mut err = cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
expr.span,
|
||||
&format!("literal out of range for {}", t),
|
||||
);
|
||||
let mut err = lint.build(&format!("literal out of range for {}", t));
|
||||
err.note(&format!(
|
||||
"the literal `{}` (decimal `{}`) does not fit into \
|
||||
an `{}` and will become `{}{}`",
|
||||
repr_str, val, t, actually, t
|
||||
));
|
||||
if let Some(sugg_ty) = get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative) {
|
||||
if let Some(sugg_ty) = get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative)
|
||||
{
|
||||
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
|
||||
let (sans_suffix, _) = repr_str.split_at(pos);
|
||||
err.span_suggestion(
|
||||
|
@ -186,8 +182,8 @@ fn report_bin_hex_error(
|
|||
err.help(&format!("consider using `{}` instead", sugg_ty));
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
|
||||
// This function finds the next fitting type and generates a suggestion string.
|
||||
|
@ -270,11 +266,9 @@ fn lint_int_literal<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
cx.span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for `{}`", t.name_str()),
|
||||
);
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
|
||||
lint.build(&format!("literal out of range for `{}`", t.name_str())).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,18 +292,16 @@ fn lint_uint_literal<'a, 'tcx>(
|
|||
match par_e.kind {
|
||||
hir::ExprKind::Cast(..) => {
|
||||
if let ty::Char = cx.tables.expr_ty(par_e).kind {
|
||||
let mut err = cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
par_e.span,
|
||||
"only `u8` can be cast into `char`",
|
||||
);
|
||||
err.span_suggestion(
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
|
||||
lint.build("only `u8` can be cast into `char`")
|
||||
.span_suggestion(
|
||||
par_e.span,
|
||||
&"use a `char` literal instead",
|
||||
format!("'\\u{{{:X}}}'", lit_val),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -327,11 +319,9 @@ fn lint_uint_literal<'a, 'tcx>(
|
|||
report_bin_hex_error(cx, e, attr::IntType::UnsignedInt(t), repr_str, lit_val, false);
|
||||
return;
|
||||
}
|
||||
cx.span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for `{}`", t.name_str()),
|
||||
);
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
|
||||
lint.build(&format!("literal out of range for `{}`", t.name_str())).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,11 +351,9 @@ fn lint_literal<'a, 'tcx>(
|
|||
_ => bug!(),
|
||||
};
|
||||
if is_infinite == Ok(true) {
|
||||
cx.span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for `{}`", t.name_str()),
|
||||
);
|
||||
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
|
||||
lint.build(&format!("literal out of range for `{}`", t.name_str())).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -383,11 +371,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
|||
}
|
||||
hir::ExprKind::Binary(binop, ref l, ref r) => {
|
||||
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
|
||||
cx.span_lint(
|
||||
UNUSED_COMPARISONS,
|
||||
e.span,
|
||||
"comparison is useless due to type limits",
|
||||
);
|
||||
cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| {
|
||||
lint.build("comparison is useless due to type limits").emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
|
||||
|
@ -883,11 +869,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
note: &str,
|
||||
help: Option<&str>,
|
||||
) {
|
||||
let mut diag = self.cx.struct_span_lint(
|
||||
IMPROPER_CTYPES,
|
||||
sp,
|
||||
&format!("`extern` block uses type `{}`, which is not FFI-safe", ty),
|
||||
);
|
||||
self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
|
||||
let mut diag =
|
||||
lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
|
||||
diag.span_label(sp, "not FFI-safe");
|
||||
if let Some(help) = help {
|
||||
diag.help(help);
|
||||
|
@ -899,6 +883,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
diag.emit();
|
||||
});
|
||||
}
|
||||
|
||||
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
|
||||
|
@ -1062,14 +1047,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
|||
// We only warn if the largest variant is at least thrice as large as
|
||||
// the second-largest.
|
||||
if largest > slargest * 3 && slargest > 0 {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
VARIANT_SIZE_DIFFERENCES,
|
||||
enum_definition.variants[largest_index].span,
|
||||
&format!(
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"enum variant is more than three times \
|
||||
larger ({} bytes) than the next largest",
|
||||
largest
|
||||
),
|
||||
))
|
||||
.emit()
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,16 +104,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
|||
};
|
||||
|
||||
if let Some(must_use_op) = must_use_op {
|
||||
cx.span_lint(
|
||||
UNUSED_MUST_USE,
|
||||
expr.span,
|
||||
&format!("unused {} that must be used", must_use_op),
|
||||
);
|
||||
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
|
||||
lint.build(&format!("unused {} that must be used", must_use_op)).emit()
|
||||
});
|
||||
op_warned = true;
|
||||
}
|
||||
|
||||
if !(type_permits_lack_of_use || fn_warned || op_warned) {
|
||||
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
|
||||
cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| lint.build("unused result").emit());
|
||||
}
|
||||
|
||||
// Returns whether an error has been emitted (and thus another does not need to be later).
|
||||
|
@ -204,6 +202,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
|||
}
|
||||
|
||||
// Returns whether an error has been emitted (and thus another does not need to be later).
|
||||
// FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this
|
||||
// would make calling it a big awkward. Could also take String (so args are moved), but
|
||||
// this would still require a copy into the format string, which would only be executed
|
||||
// when needed.
|
||||
fn check_must_use_def(
|
||||
cx: &LateContext<'_, '_>,
|
||||
def_id: DefId,
|
||||
|
@ -213,18 +215,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
|||
) -> bool {
|
||||
for attr in cx.tcx.get_attrs(def_id).iter() {
|
||||
if attr.check_name(sym::must_use) {
|
||||
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
|
||||
let msg = format!(
|
||||
"unused {}`{}`{} that must be used",
|
||||
descr_pre_path,
|
||||
cx.tcx.def_path_str(def_id),
|
||||
descr_post_path
|
||||
);
|
||||
let mut err = cx.struct_span_lint(UNUSED_MUST_USE, span, &msg);
|
||||
let mut err = lint.build(&msg);
|
||||
// check for #[must_use = "..."]
|
||||
if let Some(note) = attr.value_str() {
|
||||
err.note(¬e.as_str());
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +249,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
|
|||
fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt<'_>) {
|
||||
if let hir::StmtKind::Semi(ref expr) = s.kind {
|
||||
if let hir::ExprKind::Path(_) = expr.kind {
|
||||
cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
|
||||
cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
|
||||
lint.build("path statement with no effect").emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,9 +292,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
|
|||
|
||||
if !attr::is_used(attr) {
|
||||
debug!("emitting warning for: {:?}", attr);
|
||||
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
|
||||
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
||||
lint.build("unused attribute").emit()
|
||||
});
|
||||
// Is it a builtin attribute that must be used at the crate level?
|
||||
if attr_info.map_or(false, |(_, ty, ..)| ty == &AttributeType::CrateLevel) {
|
||||
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
||||
let msg = match attr.style {
|
||||
ast::AttrStyle::Outer => {
|
||||
"crate-level attribute should be an inner attribute: add an exclamation \
|
||||
|
@ -296,7 +305,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
|
|||
}
|
||||
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
||||
};
|
||||
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
debug!("Attr was used: {:?}", attr);
|
||||
|
@ -406,8 +416,9 @@ impl UnusedParens {
|
|||
msg: &str,
|
||||
keep_space: (bool, bool),
|
||||
) {
|
||||
cx.struct_span_lint(UNUSED_PARENS, span, |lint| {
|
||||
let span_msg = format!("unnecessary parentheses around {}", msg);
|
||||
let mut err = cx.struct_span_lint(UNUSED_PARENS, span, &span_msg);
|
||||
let mut err = lint.build(&span_msg);
|
||||
let mut ate_left_paren = false;
|
||||
let mut ate_right_paren = false;
|
||||
let parens_removed = pattern.trim_matches(|c| match c {
|
||||
|
@ -452,6 +463,7 @@ impl UnusedParens {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,8 +643,9 @@ impl UnusedImportBraces {
|
|||
ast::UseTreeKind::Nested(_) => return,
|
||||
};
|
||||
|
||||
let msg = format!("braces around {} is unnecessary", node_name);
|
||||
cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
|
||||
cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
|
||||
lint.build(&format!("braces around {} is unnecessary", node_name)).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -662,6 +675,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
|||
|
||||
for adj in cx.tables.expr_adjustments(e) {
|
||||
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
||||
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
|
||||
let msg = match m {
|
||||
adjustment::AutoBorrowMutability::Not => {
|
||||
"unnecessary allocation, use `&` instead"
|
||||
|
@ -670,7 +684,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
|||
"unnecessary allocation, use `&mut` instead"
|
||||
}
|
||||
};
|
||||
cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,18 +319,20 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
};
|
||||
|
||||
// Span and message don't matter; we overwrite them below anyway
|
||||
let mut diag = mbcx.infcx.tcx.struct_span_lint_hir(
|
||||
mbcx.infcx.tcx.struct_span_lint_hir(
|
||||
MUTABLE_BORROW_RESERVATION_CONFLICT,
|
||||
lint_root,
|
||||
DUMMY_SP,
|
||||
"",
|
||||
);
|
||||
|lint| {
|
||||
let mut diag = lint.build("");
|
||||
|
||||
diag.message = initial_diag.styled_message().clone();
|
||||
diag.span = initial_diag.span.clone();
|
||||
|
||||
initial_diag.cancel();
|
||||
diag.buffer(&mut mbcx.errors_buffer);
|
||||
},
|
||||
);
|
||||
initial_diag.cancel();
|
||||
}
|
||||
|
||||
// For each non-user used mutable variable, check if it's been assigned from
|
||||
|
@ -376,13 +378,9 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
continue;
|
||||
}
|
||||
|
||||
tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| {
|
||||
let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
|
||||
tcx.struct_span_lint_hir(
|
||||
UNUSED_MUT,
|
||||
lint_root,
|
||||
span,
|
||||
"variable does not need to be mutable",
|
||||
)
|
||||
lint.build("variable does not need to be mutable")
|
||||
.span_suggestion_short(
|
||||
mut_span,
|
||||
"remove this `mut`",
|
||||
|
@ -390,6 +388,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
|
|
|
@ -209,12 +209,11 @@ fn validate_and_turn_into_const<'tcx>(
|
|||
|
||||
val.map_err(|error| {
|
||||
let err = error_to_const_error(&ecx, error);
|
||||
match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
|
||||
Ok(mut diag) => {
|
||||
match err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
|
||||
diag.note(note_on_undefined_behavior_error());
|
||||
diag.emit();
|
||||
ErrorHandled::Reported
|
||||
}
|
||||
}) {
|
||||
Ok(_) => ErrorHandled::Reported,
|
||||
Err(err) => err,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -326,12 +326,15 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
|||
// to read enum discriminants in order to find references in enum variant fields.
|
||||
if let err_unsup!(ValidationFailure(_)) = error.kind {
|
||||
let err = crate::const_eval::error_to_const_error(&ecx, error);
|
||||
match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
|
||||
Ok(mut diag) => {
|
||||
match err.struct_error(
|
||||
ecx.tcx,
|
||||
"it is undefined behavior to use this value",
|
||||
|mut diag| {
|
||||
diag.note(crate::const_eval::note_on_undefined_behavior_error());
|
||||
diag.emit();
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric) | Err(ErrorHandled::Reported) => {}
|
||||
},
|
||||
) {
|
||||
Ok(()) | Err(ErrorHandled::TooGeneric) | Err(ErrorHandled::Reported) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -516,6 +516,7 @@ fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
.as_local_hir_id(def_id)
|
||||
.unwrap_or_else(|| bug!("checking unsafety for non-local def id {:?}", def_id));
|
||||
|
||||
tcx.struct_span_lint_hir(SAFE_PACKED_BORROWS, lint_hir_id, tcx.def_span(def_id), |lint| {
|
||||
// FIXME: when we make this a hard error, this should have its
|
||||
// own error code.
|
||||
let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
|
||||
|
@ -527,7 +528,8 @@ fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
does not derive Copy (error E0133)"
|
||||
.to_string()
|
||||
};
|
||||
tcx.lint_hir(SAFE_PACKED_BORROWS, lint_hir_id, tcx.def_span(def_id), &message);
|
||||
lint.build(&message).emit()
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the `HirId` for an enclosing scope that is also `unsafe`.
|
||||
|
@ -558,8 +560,9 @@ fn is_enclosed(
|
|||
|
||||
fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet<hir::HirId>, id: hir::HirId) {
|
||||
let span = tcx.sess.source_map().def_span(tcx.hir().span(id));
|
||||
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| {
|
||||
let msg = "unnecessary `unsafe` block";
|
||||
let mut db = tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg);
|
||||
let mut db = lint.build(msg);
|
||||
db.span_label(span, msg);
|
||||
if let Some((kind, id)) = is_enclosed(tcx, used_unsafe, id) {
|
||||
db.span_label(
|
||||
|
@ -568,6 +571,7 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet<hir::HirId>, id
|
|||
);
|
||||
}
|
||||
db.emit();
|
||||
});
|
||||
}
|
||||
|
||||
fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
|
||||
|
@ -619,13 +623,15 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
SAFE_PACKED_BORROWS,
|
||||
lint_hir_id,
|
||||
source_info.span,
|
||||
&format!(
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} is unsafe and requires unsafe function or block (error E0133)",
|
||||
description
|
||||
),
|
||||
)
|
||||
))
|
||||
.note(&details.as_str())
|
||||
.emit();
|
||||
.emit()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -556,12 +556,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
|
||||
if r_bits.map_or(false, |b| b >= left_bits as u128) {
|
||||
let lint_root = self.lint_root(source_info)?;
|
||||
let dir = if op == BinOp::Shr { "right" } else { "left" };
|
||||
self.tcx.lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
|
||||
lint_root,
|
||||
source_info.span,
|
||||
&format!("attempt to shift {} with overflow", dir),
|
||||
|lint| {
|
||||
let dir = if op == BinOp::Shr { "right" } else { "left" };
|
||||
lint.build(&format!("attempt to shift {} with overflow", dir)).emit()
|
||||
},
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
@ -912,23 +914,35 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
.hir()
|
||||
.as_local_hir_id(self.source.def_id())
|
||||
.expect("some part of a failing const eval must be local");
|
||||
self.tcx.struct_span_lint_hir(
|
||||
::rustc::lint::builtin::CONST_ERR,
|
||||
hir_id,
|
||||
span,
|
||||
|lint| {
|
||||
let msg = match msg {
|
||||
PanicInfo::Overflow(_)
|
||||
| PanicInfo::OverflowNeg
|
||||
| PanicInfo::DivisionByZero
|
||||
| PanicInfo::RemainderByZero => msg.description().to_owned(),
|
||||
PanicInfo::BoundsCheck { ref len, ref index } => {
|
||||
let len =
|
||||
self.eval_operand(len, source_info).expect("len must be const");
|
||||
let len = self
|
||||
.eval_operand(len, source_info)
|
||||
.expect("len must be const");
|
||||
let len = match self.ecx.read_scalar(len) {
|
||||
Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { data, .. })) => data,
|
||||
Ok(ScalarMaybeUndef::Scalar(Scalar::Raw {
|
||||
data,
|
||||
..
|
||||
})) => data,
|
||||
other => bug!("const len not primitive: {:?}", other),
|
||||
};
|
||||
let index = self
|
||||
.eval_operand(index, source_info)
|
||||
.expect("index must be const");
|
||||
let index = match self.ecx.read_scalar(index) {
|
||||
Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { data, .. })) => data,
|
||||
Ok(ScalarMaybeUndef::Scalar(Scalar::Raw {
|
||||
data,
|
||||
..
|
||||
})) => data,
|
||||
other => bug!("const index not primitive: {:?}", other),
|
||||
};
|
||||
format!(
|
||||
|
@ -940,7 +954,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
// Need proper const propagator for these
|
||||
_ => return,
|
||||
};
|
||||
self.tcx.lint_hir(::rustc::lint::builtin::CONST_ERR, hir_id, span, &msg);
|
||||
lint.build(&msg).emit()
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if self.should_const_prop(value) {
|
||||
if let ScalarMaybeUndef::Scalar(scalar) = value_const {
|
||||
|
|
|
@ -2235,12 +2235,12 @@ fn lint_overlapping_patterns<'tcx>(
|
|||
overlaps: Vec<IntRange<'tcx>>,
|
||||
) {
|
||||
if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
|
||||
let mut err = tcx.struct_span_lint_hir(
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::OVERLAPPING_PATTERNS,
|
||||
hir_id,
|
||||
ctor_range.span,
|
||||
"multiple patterns covering the same range",
|
||||
);
|
||||
|lint| {
|
||||
let mut err = lint.build("multiple patterns covering the same range");
|
||||
err.span_label(ctor_range.span, "overlapping patterns");
|
||||
for int_range in overlaps {
|
||||
// Use the real type for user display of the ranges:
|
||||
|
@ -2253,6 +2253,8 @@ fn lint_overlapping_patterns<'tcx>(
|
|||
);
|
||||
}
|
||||
err.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -286,18 +286,17 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
|
|||
variant.ident == ident && variant.ctor_kind == CtorKind::Const
|
||||
})
|
||||
{
|
||||
let ty_path = cx.tcx.def_path_str(edef.did);
|
||||
cx.tcx
|
||||
.struct_span_lint_hir(
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
BINDINGS_WITH_VARIANT_NAME,
|
||||
p.hir_id,
|
||||
p.span,
|
||||
&format!(
|
||||
|lint| {
|
||||
let ty_path = cx.tcx.def_path_str(edef.did);
|
||||
lint.build(&format!(
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident, ty_path
|
||||
),
|
||||
)
|
||||
))
|
||||
.code(error_code!(E0170))
|
||||
.span_suggestion(
|
||||
p.span,
|
||||
|
@ -306,6 +305,8 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -325,22 +326,26 @@ fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
|
|||
}
|
||||
|
||||
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
|
||||
let mut err = tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern");
|
||||
tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| {
|
||||
let mut err = lint.build("unreachable pattern");
|
||||
if let Some(catchall) = catchall {
|
||||
// We had a catchall pattern, hint at that.
|
||||
err.span_label(span, "unreachable pattern");
|
||||
err.span_label(catchall, "matches any value");
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
|
||||
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
|
||||
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
|
||||
let msg = match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
|
||||
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
|
||||
_ => bug!(),
|
||||
};
|
||||
tcx.lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, msg);
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
|
||||
/// Check for unreachable patterns.
|
||||
|
|
|
@ -109,11 +109,14 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
let path = self.tcx().def_path_str(adt_def.did);
|
||||
let msg = format!(
|
||||
|
||||
let make_msg = || -> String {
|
||||
format!(
|
||||
"to use a constant of type `{}` in a pattern, \
|
||||
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
|
||||
path, path,
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
// double-check there even *is* a semantic `PartialEq` to dispatch to.
|
||||
//
|
||||
|
@ -143,13 +146,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
|
||||
if !ty_is_partial_eq {
|
||||
// span_fatal avoids ICE from resolution of non-existent method (rare case).
|
||||
self.tcx().sess.span_fatal(self.span, &msg);
|
||||
self.tcx().sess.span_fatal(self.span, &make_msg());
|
||||
} else {
|
||||
self.tcx().lint_hir(
|
||||
self.tcx().struct_span_lint_hir(
|
||||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
self.id,
|
||||
self.span,
|
||||
&msg,
|
||||
|lint| lint.build(&make_msg()).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -177,11 +180,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
|
||||
let kind = match cv.ty.kind {
|
||||
ty::Float(_) => {
|
||||
tcx.lint_hir(
|
||||
tcx.struct_span_lint_hir(
|
||||
::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
id,
|
||||
span,
|
||||
"floating-point types cannot be used in patterns",
|
||||
|lint| lint.build("floating-point types cannot be used in patterns").emit(),
|
||||
);
|
||||
PatKind::Constant { value: cv }
|
||||
}
|
||||
|
|
|
@ -124,12 +124,8 @@ fn check_fn_for_unconditional_recursion<'tcx>(
|
|||
if !reached_exit_without_self_call && !self_call_locations.is_empty() {
|
||||
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
let sp = tcx.sess.source_map().def_span(tcx.hir().span(hir_id));
|
||||
let mut db = tcx.struct_span_lint_hir(
|
||||
UNCONDITIONAL_RECURSION,
|
||||
hir_id,
|
||||
sp,
|
||||
"function cannot return without recursing",
|
||||
);
|
||||
tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
|
||||
let mut db = lint.build("function cannot return without recursing");
|
||||
db.span_label(sp, "cannot return without recursing");
|
||||
// offer some help to the programmer.
|
||||
for location in &self_call_locations {
|
||||
|
@ -137,5 +133,6 @@ fn check_fn_for_unconditional_recursion<'tcx>(
|
|||
}
|
||||
db.help("a `loop` may express intention better if this is on purpose");
|
||||
db.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -315,10 +315,11 @@ impl<'a> StripUnconfigured<'a> {
|
|||
validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
|
||||
match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
|
||||
Ok(r) => return Some(r),
|
||||
Err(mut e) => e
|
||||
.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
|
||||
Err(mut e) => {
|
||||
e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
|
||||
.note(CFG_ATTR_NOTE_REF)
|
||||
.emit(),
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => self.error_malformed_cfg_attr_missing(attr.span),
|
||||
|
|
|
@ -69,7 +69,7 @@ pub(crate) fn emit_unescape_error(
|
|||
format!("\"{}\"", lit),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
EscapeError::EscapeOnlyChar => {
|
||||
let (c, _span) = last_char();
|
||||
|
|
|
@ -149,7 +149,7 @@ impl<'a> Parser<'a> {
|
|||
source files. Outer attributes, like `#[test]`, annotate the \
|
||||
item following them.",
|
||||
)
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ impl<'a> Parser<'a> {
|
|||
(`1u8`, `1.0f32`, etc.), use an unsuffixed version \
|
||||
(`1`, `1.0`, etc.)",
|
||||
)
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
|
||||
Ok(lit)
|
||||
|
|
|
@ -1014,7 +1014,7 @@ impl<'a> Parser<'a> {
|
|||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1407,6 +1407,8 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &Pa
|
|||
*sess.reached_eof.borrow_mut() |=
|
||||
unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none());
|
||||
for unmatched in unclosed_delims.drain(..) {
|
||||
make_unclosed_delims_error(unmatched, sess).map(|mut e| e.emit());
|
||||
make_unclosed_delims_error(unmatched, sess).map(|mut e| {
|
||||
e.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -572,7 +572,7 @@ impl<'a> Parser<'a> {
|
|||
self.struct_span_err(span, problem)
|
||||
.span_suggestion(span, suggestion, fix, Applicability::MachineApplicable)
|
||||
.note("`mut` may be followed by `variable` and `variable @ pattern`")
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// Eat any extraneous `mut`s and error + recover if we ate any.
|
||||
|
|
|
@ -27,7 +27,11 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
|
|||
_ => {
|
||||
if let MacArgs::Eq(..) = attr.get_normal_item().args {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
parse_meta(sess, attr).map_err(|mut err| err.emit()).ok();
|
||||
parse_meta(sess, attr)
|
||||
.map_err(|mut err| {
|
||||
err.emit();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +156,8 @@ pub fn check_builtin_attribute(
|
|||
}
|
||||
}
|
||||
}
|
||||
Err(mut err) => err.emit(),
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,14 +92,9 @@ impl CheckAttrVisitor<'tcx> {
|
|||
| Target::Method(MethodKind::Trait { body: true })
|
||||
| Target::Method(MethodKind::Inherent) => true,
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
self.tcx
|
||||
.struct_span_lint_hir(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
"`#[inline]` is ignored on function prototypes",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[inline]` is ignored on function prototypes").emit()
|
||||
});
|
||||
true
|
||||
}
|
||||
// FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
|
||||
|
@ -107,13 +102,8 @@ impl CheckAttrVisitor<'tcx> {
|
|||
// accidentally, to to be compatible with crates depending on them, we can't throw an
|
||||
// error here.
|
||||
Target::AssocConst => {
|
||||
self.tcx
|
||||
.struct_span_lint_hir(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
"`#[inline]` is ignored on constants",
|
||||
)
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[inline]` is ignored on constants")
|
||||
.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
|
@ -124,6 +114,7 @@ impl CheckAttrVisitor<'tcx> {
|
|||
for more information",
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
|
@ -331,15 +322,16 @@ impl CheckAttrVisitor<'tcx> {
|
|||
|| (is_simd && is_c)
|
||||
|| (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item)))
|
||||
{
|
||||
self.tcx
|
||||
.struct_span_lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
CONFLICTING_REPR_HINTS,
|
||||
hir_id,
|
||||
hint_spans.collect::<Vec<Span>>(),
|
||||
"conflicting representation hints",
|
||||
)
|
||||
|lint| {
|
||||
lint.build("conflicting representation hints")
|
||||
.code(rustc_errors::error_code!(E0566))
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -554,12 +554,9 @@ impl DeadVisitor<'tcx> {
|
|||
participle: &str,
|
||||
) {
|
||||
if !name.as_str().starts_with("_") {
|
||||
self.tcx.lint_hir(
|
||||
lint::builtin::DEAD_CODE,
|
||||
id,
|
||||
span,
|
||||
&format!("{} is never {}: `{}`", node_type, participle, name),
|
||||
);
|
||||
self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
|
||||
lint.build(&format!("{} is never {}: `{}`", node_type, participle, name)).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1521,29 +1521,30 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
|||
if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() };
|
||||
|
||||
if is_assigned {
|
||||
self.ir
|
||||
.tcx
|
||||
.struct_span_lint_hir(
|
||||
self.ir.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans,
|
||||
&format!("variable `{}` is assigned to, but never used", name),
|
||||
)
|
||||
|lint| {
|
||||
lint.build(&format!("variable `{}` is assigned to, but never used", name))
|
||||
.note(&format!("consider using `_{}` instead", name))
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
} else {
|
||||
let mut err = self.ir.tcx.struct_span_lint_hir(
|
||||
self.ir.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans.clone(),
|
||||
&format!("unused variable: `{}`", name),
|
||||
);
|
||||
|
||||
|lint| {
|
||||
let mut err = lint.build(&format!("unused variable: `{}`", name));
|
||||
if self.ir.variable_is_shorthand(var) {
|
||||
if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) {
|
||||
// Handle `ref` and `ref mut`.
|
||||
let spans =
|
||||
spans.iter().map(|_span| (pat.span, format!("{}: _", name))).collect();
|
||||
let spans = spans
|
||||
.iter()
|
||||
.map(|_span| (pat.span, format!("{}: _", name)))
|
||||
.collect();
|
||||
|
||||
err.multipart_suggestion(
|
||||
"try ignoring the field",
|
||||
|
@ -1558,8 +1559,9 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
err.emit()
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1573,27 +1575,27 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
|||
fn report_dead_assign(&self, hir_id: HirId, spans: Vec<Span>, var: Variable, is_param: bool) {
|
||||
if let Some(name) = self.should_warn(var) {
|
||||
if is_param {
|
||||
self.ir
|
||||
.tcx
|
||||
.struct_span_lint_hir(
|
||||
self.ir.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_ASSIGNMENTS,
|
||||
hir_id,
|
||||
spans,
|
||||
&format!("value passed to `{}` is never read", name),
|
||||
)
|
||||
|lint| {
|
||||
lint.build(&format!("value passed to `{}` is never read", name))
|
||||
.help("maybe it is overwritten before being read?")
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
} else {
|
||||
self.ir
|
||||
.tcx
|
||||
.struct_span_lint_hir(
|
||||
self.ir.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_ASSIGNMENTS,
|
||||
hir_id,
|
||||
spans,
|
||||
&format!("value assigned to `{}` is never read", name),
|
||||
)
|
||||
|lint| {
|
||||
lint.build(&format!("value assigned to `{}` is never read", name))
|
||||
.help("maybe it is overwritten before being read?")
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -604,16 +604,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
|||
}
|
||||
|
||||
fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) {
|
||||
tcx.lint_hir(
|
||||
lint::builtin::STABLE_FEATURES,
|
||||
hir::CRATE_HIR_ID,
|
||||
span,
|
||||
&format!(
|
||||
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
|
||||
lint.build(&format!(
|
||||
"the feature `{}` has been stable since {} and no longer requires \
|
||||
an attribute to enable",
|
||||
feature, since
|
||||
),
|
||||
);
|
||||
))
|
||||
.emit();
|
||||
});
|
||||
}
|
||||
|
||||
fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
|
||||
|
|
|
@ -1781,17 +1781,20 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
|||
|
||||
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
if self.leaks_private_dep(def_id) {
|
||||
self.tcx.lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
|
||||
self.item_id,
|
||||
self.span,
|
||||
&format!(
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} `{}` from private dependency '{}' in public \
|
||||
interface",
|
||||
kind,
|
||||
descr,
|
||||
self.tcx.crate_name(def_id.krate)
|
||||
),
|
||||
))
|
||||
.emit()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1802,23 +1805,23 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
|||
|
||||
let (vis, vis_span, vis_descr) = def_id_visibility(self.tcx, def_id);
|
||||
if !vis.is_at_least(self.required_visibility, self.tcx) {
|
||||
let msg = format!("{} {} `{}` in public interface", vis_descr, kind, descr);
|
||||
let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
|
||||
if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
|
||||
let mut err = if kind == "trait" {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0445, "{}", msg)
|
||||
struct_span_err!(self.tcx.sess, self.span, E0445, "{}", make_msg())
|
||||
} else {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0446, "{}", msg)
|
||||
struct_span_err!(self.tcx.sess, self.span, E0446, "{}", make_msg())
|
||||
};
|
||||
err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
|
||||
err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
|
||||
err.emit();
|
||||
} else {
|
||||
let err_code = if kind == "trait" { "E0445" } else { "E0446" };
|
||||
self.tcx.lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
hir_id,
|
||||
self.span,
|
||||
&format!("{} (error {})", msg, err_code),
|
||||
|lint| lint.build(&format!("{} (error {})", make_msg(), err_code)).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1575,13 +1575,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut err = self.tcx.struct_span_lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::SINGLE_USE_LIFETIMES,
|
||||
id,
|
||||
span,
|
||||
&format!("lifetime parameter `{}` only used once", name),
|
||||
);
|
||||
|
||||
|lint| {
|
||||
let mut err = lint.build(&format!(
|
||||
"lifetime parameter `{}` only used once",
|
||||
name
|
||||
));
|
||||
if span == lifetime.span {
|
||||
// spans are the same for in-band lifetime declarations
|
||||
err.span_label(span, "this lifetime is only used here");
|
||||
|
@ -1589,8 +1591,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
err.span_label(span, "this lifetime...");
|
||||
err.span_label(lifetime.span, "...is used only here");
|
||||
}
|
||||
self.suggest_eliding_single_use_lifetime(&mut err, def_id, lifetime);
|
||||
self.suggest_eliding_single_use_lifetime(
|
||||
&mut err, def_id, lifetime,
|
||||
);
|
||||
err.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(LifetimeUseSet::Many) => {
|
||||
|
@ -1610,15 +1616,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
_ => None,
|
||||
} {
|
||||
debug!("id ={:?} span = {:?} name = {:?}", id, span, name);
|
||||
let mut err = self.tcx.struct_span_lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_LIFETIMES,
|
||||
id,
|
||||
span,
|
||||
&format!("lifetime parameter `{}` never used", name),
|
||||
);
|
||||
|lint| {
|
||||
let mut err = lint
|
||||
.build(&format!("lifetime parameter `{}` never used", name));
|
||||
if let Some(parent_def_id) = self.tcx.parent(def_id) {
|
||||
if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) {
|
||||
let unused_lt_span = self.lifetime_deletion_span(name, generics);
|
||||
if let Some(generics) =
|
||||
self.tcx.hir().get_generics(parent_def_id)
|
||||
{
|
||||
let unused_lt_span =
|
||||
self.lifetime_deletion_span(name, generics);
|
||||
if let Some(span) = unused_lt_span {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
|
@ -1630,6 +1640,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
err.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -331,11 +331,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
} else {
|
||||
let mut multispan = MultiSpan::from_span(span);
|
||||
multispan.push_span_label(span_late, note.to_string());
|
||||
tcx.lint_hir(
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
args.args[0].id(),
|
||||
multispan,
|
||||
msg,
|
||||
|lint| lint.build(msg).emit(),
|
||||
);
|
||||
reported_late_bound_region_err = Some(false);
|
||||
}
|
||||
|
@ -2216,13 +2216,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
tcx.check_stability(item.def_id, Some(hir_ref_id), span);
|
||||
|
||||
if let Some(variant_def_id) = variant_resolution {
|
||||
let mut err = tcx.struct_span_lint_hir(
|
||||
AMBIGUOUS_ASSOCIATED_ITEMS,
|
||||
hir_ref_id,
|
||||
span,
|
||||
"ambiguous associated item",
|
||||
);
|
||||
|
||||
tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
|
||||
let mut err = lint.build("ambiguous associated item");
|
||||
let mut could_refer_to = |kind: DefKind, def_id, also| {
|
||||
let note_msg = format!(
|
||||
"`{}` could{} refer to the {} defined here",
|
||||
|
@ -2232,6 +2227,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
);
|
||||
err.span_note(tcx.def_span(def_id), ¬e_msg);
|
||||
};
|
||||
|
||||
could_refer_to(DefKind::Variant, variant_def_id, "");
|
||||
could_refer_to(kind, item.def_id, " also");
|
||||
|
||||
|
@ -2240,10 +2236,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
"use fully-qualified syntax",
|
||||
format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
);
|
||||
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
Ok((ty, kind, item.def_id))
|
||||
}
|
||||
|
||||
|
|
|
@ -468,23 +468,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
} else {
|
||||
("", lint::builtin::TRIVIAL_CASTS)
|
||||
};
|
||||
let mut err = fcx.tcx.struct_span_lint_hir(
|
||||
lint,
|
||||
self.expr.hir_id,
|
||||
self.span,
|
||||
&format!(
|
||||
fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
|
||||
err.build(&format!(
|
||||
"trivial {}cast: `{}` as `{}`",
|
||||
adjective,
|
||||
fcx.ty_to_string(t_expr),
|
||||
fcx.ty_to_string(t_cast)
|
||||
),
|
||||
);
|
||||
err.help(&format!(
|
||||
))
|
||||
.help(&format!(
|
||||
"cast can be replaced by coercion; this might \
|
||||
require {}a temporary variable",
|
||||
type_asc_or
|
||||
));
|
||||
err.emit();
|
||||
))
|
||||
.emit();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
|
|
|
@ -382,11 +382,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
)
|
||||
.emit();
|
||||
} else {
|
||||
self.tcx.lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
|
||||
scope_expr_id,
|
||||
span,
|
||||
"type annotations needed",
|
||||
|lint| lint.build("type annotations needed").emit(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -1280,13 +1280,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
stable_pick: &Pick<'_>,
|
||||
unstable_candidates: &[(&Candidate<'tcx>, Symbol)],
|
||||
) {
|
||||
let mut diag = self.tcx.struct_span_lint_hir(
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNSTABLE_NAME_COLLISIONS,
|
||||
self.fcx.body_id,
|
||||
self.span,
|
||||
|lint| {
|
||||
let mut diag = lint.build(
|
||||
"a method with this name may be added to the standard library in the future",
|
||||
);
|
||||
|
||||
// FIXME: This should be a `span_suggestion` instead of `help`
|
||||
// However `self.span` only
|
||||
// highlights the method name, so we can't use it. Also consider reusing the code from
|
||||
|
@ -1307,6 +1308,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
diag.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn select_trait_candidate(
|
||||
|
|
|
@ -2895,15 +2895,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
|
||||
|
||||
self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
|
||||
let msg = format!("unreachable {}", kind);
|
||||
self.tcx()
|
||||
.struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg)
|
||||
lint.build(&msg)
|
||||
.span_label(span, &msg)
|
||||
.span_label(
|
||||
orig_span,
|
||||
custom_note.unwrap_or("any code following this expression is unreachable"),
|
||||
custom_note
|
||||
.unwrap_or("any code following this expression is unreachable"),
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,12 +55,14 @@ impl CheckVisitor<'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, id, span, |lint| {
|
||||
let msg = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
format!("unused import: `{}`", snippet)
|
||||
} else {
|
||||
"unused import".to_owned()
|
||||
};
|
||||
self.tcx.lint_hir(lint::builtin::UNUSED_IMPORTS, id, span, &msg);
|
||||
lint.build(&msg).emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,8 +123,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
|
|||
// We do this in any edition.
|
||||
if extern_crate.warn_if_unused {
|
||||
if let Some(&span) = unused_extern_crates.get(&extern_crate.def_id) {
|
||||
let msg = "unused extern crate";
|
||||
|
||||
tcx.struct_span_lint_hir(lint, id, span, |lint| {
|
||||
// Removal suggestion span needs to include attributes (Issue #54400)
|
||||
let span_with_attrs = tcx
|
||||
.get_attrs(extern_crate.def_id)
|
||||
|
@ -130,7 +131,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
|
|||
.map(|attr| attr.span)
|
||||
.fold(span, |acc, attr_span| acc.to(attr_span));
|
||||
|
||||
tcx.struct_span_lint_hir(lint, id, span, msg)
|
||||
lint.build("unused extern crate")
|
||||
.span_suggestion_short(
|
||||
span_with_attrs,
|
||||
"remove it",
|
||||
|
@ -138,6 +139,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -168,16 +170,18 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
|
|||
if !tcx.get_attrs(extern_crate.def_id).is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
|
||||
// Otherwise, we can convert it into a `use` of some kind.
|
||||
let msg = "`extern crate` is not idiomatic in the new edition";
|
||||
let help = format!("convert it to a `{}`", visibility_qualified(&item.vis, "use"));
|
||||
let base_replacement = match extern_crate.orig_name {
|
||||
Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name),
|
||||
None => format!("use {};", item.ident.name),
|
||||
};
|
||||
|
||||
let replacement = visibility_qualified(&item.vis, base_replacement);
|
||||
tcx.struct_span_lint_hir(lint, id, extern_crate.span, msg)
|
||||
let msg = "`extern crate` is not idiomatic in the new edition";
|
||||
let help = format!("convert it to a `{}`", visibility_qualified(&item.vis, "use"));
|
||||
|
||||
lint.build(msg)
|
||||
.span_suggestion_short(
|
||||
extern_crate.span,
|
||||
&help,
|
||||
|
@ -185,6 +189,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
|
|||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1151,14 +1151,17 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
|
|||
GenericParamKind::Type { ref default, synthetic, .. } => {
|
||||
if !allow_defaults && default.is_some() {
|
||||
if !tcx.features().default_type_parameter_fallback {
|
||||
tcx.lint_hir(
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
|
||||
param.hir_id,
|
||||
param.span,
|
||||
&format!(
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"defaults for type parameters are only allowed in \
|
||||
`struct`, `enum`, `type`, or `trait` definitions."
|
||||
),
|
||||
))
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2956,10 +2959,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||
lint::builtin::INLINE_NO_SANITIZE,
|
||||
hir_id,
|
||||
no_sanitize_span,
|
||||
"`no_sanitize` will have no effect after inlining",
|
||||
)
|
||||
|lint| {
|
||||
lint.build("`no_sanitize` will have no effect after inlining")
|
||||
.span_note(inline_span, "inlining requested here")
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -669,14 +669,15 @@ fn build_diagnostic(
|
|||
let attrs = &item.attrs;
|
||||
let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
|
||||
|
||||
let mut diag = cx.tcx.struct_span_lint_hir(
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
|
||||
hir_id,
|
||||
sp,
|
||||
&format!("`[{}]` {}", path_str, err_msg),
|
||||
);
|
||||
|lint| {
|
||||
let mut diag = lint.build(&format!("`[{}]` {}", path_str, err_msg));
|
||||
if let Some(link_range) = link_range {
|
||||
if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) {
|
||||
if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
|
||||
{
|
||||
diag.set_span(sp);
|
||||
diag.span_label(sp, short_err_msg);
|
||||
} else {
|
||||
|
@ -684,7 +685,8 @@ fn build_diagnostic(
|
|||
// ^ ~~~~
|
||||
// | link_range
|
||||
// last_new_line_offset
|
||||
let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
||||
let last_new_line_offset =
|
||||
dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
||||
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
|
||||
|
||||
// Print the line containing the `link_range` and manually mark it with '^'s.
|
||||
|
@ -702,6 +704,8 @@ fn build_diagnostic(
|
|||
diag.help(help_msg);
|
||||
}
|
||||
diag.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Reports a resolution failure diagnostic.
|
||||
|
@ -766,6 +770,11 @@ fn ambiguity_error(
|
|||
let attrs = &item.attrs;
|
||||
let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
|
||||
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
|
||||
hir_id,
|
||||
sp,
|
||||
|lint| {
|
||||
let mut msg = format!("`{}` is ", path_str);
|
||||
|
||||
let candidates = [TypeNS, ValueNS, MacroNS]
|
||||
|
@ -794,15 +803,11 @@ fn ambiguity_error(
|
|||
}
|
||||
}
|
||||
|
||||
let mut diag = cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
|
||||
hir_id,
|
||||
sp,
|
||||
&msg,
|
||||
);
|
||||
let mut diag = lint.build(&msg);
|
||||
|
||||
if let Some(link_range) = link_range {
|
||||
if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) {
|
||||
if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
|
||||
{
|
||||
diag.set_span(sp);
|
||||
diag.span_label(sp, "ambiguous link");
|
||||
|
||||
|
@ -849,7 +854,8 @@ fn ambiguity_error(
|
|||
// ^ ~~~~
|
||||
// | link_range
|
||||
// last_new_line_offset
|
||||
let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
||||
let last_new_line_offset =
|
||||
dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
||||
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
|
||||
|
||||
// Print the line containing the `link_range` and manually mark it with '^'s.
|
||||
|
@ -863,8 +869,9 @@ fn ambiguity_error(
|
|||
));
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Given an enum variant's res, return the res of its enum and the associated fragment.
|
||||
|
|
|
@ -342,24 +342,19 @@ pub fn look_for_tests<'tcx>(
|
|||
|
||||
if check_missing_code == true && tests.found_tests == 0 {
|
||||
let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
|
||||
let mut diag = cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::MISSING_DOC_CODE_EXAMPLES,
|
||||
hir_id,
|
||||
sp,
|
||||
"missing code example in this documentation",
|
||||
);
|
||||
diag.emit();
|
||||
cx.tcx.struct_span_lint_hir(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| {
|
||||
lint.build("missing code example in this documentation").emit()
|
||||
});
|
||||
} else if check_missing_code == false
|
||||
&& tests.found_tests > 0
|
||||
&& !cx.renderinfo.borrow().access_levels.is_public(item.def_id)
|
||||
{
|
||||
let mut diag = cx.tcx.struct_span_lint_hir(
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::PRIVATE_DOC_TESTS,
|
||||
hir_id,
|
||||
span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
|
||||
"documentation test in private item",
|
||||
|lint| lint.build("documentation test in private item").emit(),
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,17 +4,19 @@
|
|||
extern crate rustc_ast_pretty;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
#[macro_use]
|
||||
extern crate rustc_lint;
|
||||
#[macro_use]
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Node;
|
||||
use rustc_lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::Node;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
|
||||
use rustc_span::source_map;
|
||||
|
||||
#[plugin_registrar]
|
||||
|
@ -32,14 +34,15 @@ declare_lint! {
|
|||
declare_lint_pass!(MissingWhitelistedAttrPass => [MISSING_WHITELISTED_ATTR]);
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass {
|
||||
fn check_fn(&mut self,
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
_: intravisit::FnKind<'tcx>,
|
||||
_: &'tcx hir::FnDecl,
|
||||
_: &'tcx hir::Body,
|
||||
span: source_map::Span,
|
||||
id: hir::HirId) {
|
||||
|
||||
id: hir::HirId,
|
||||
) {
|
||||
let item = match cx.tcx.hir().get(id) {
|
||||
Node::Item(item) => item,
|
||||
_ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)),
|
||||
|
@ -47,8 +50,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass {
|
|||
|
||||
let whitelisted = |attr| pprust::attribute_to_string(attr).contains("whitelisted_attr");
|
||||
if !item.attrs.iter().any(whitelisted) {
|
||||
cx.span_lint(MISSING_WHITELISTED_ATTR, span,
|
||||
"Missing 'whitelisted_attr' attribute");
|
||||
cx.lint(MISSING_WHITELISTED_ATTR, |lint| {
|
||||
lint.build("Missing 'whitelisted_attr' attribute").set_span(span).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_span;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
#[macro_use]
|
||||
extern crate rustc_lint;
|
||||
#[macro_use]
|
||||
extern crate rustc_session;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use syntax::attr;
|
||||
|
||||
|
@ -28,8 +30,10 @@ macro_rules! fake_lint_pass {
|
|||
fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
|
||||
$(
|
||||
if !attr::contains_name(&krate.attrs, $attr) {
|
||||
cx.span_lint(CRATE_NOT_OKAY, krate.span,
|
||||
&format!("crate is not marked with #![{}]", $attr));
|
||||
cx.lint(CRATE_NOT_OKAY, |lint| {
|
||||
let msg = format!("crate is not marked with #![{}]", $attr);
|
||||
lint.build(&msg).set_span(krate.span).emit()
|
||||
});
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
#[macro_use]
|
||||
extern crate rustc_lint;
|
||||
#[macro_use]
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use syntax::attr;
|
||||
|
||||
|
@ -26,8 +28,11 @@ declare_lint_pass!(Pass => [CRATE_NOT_OKAY]);
|
|||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
|
||||
if !attr::contains_name(&krate.attrs, Symbol::intern("crate_okay")) {
|
||||
cx.span_lint(CRATE_NOT_OKAY, krate.span,
|
||||
"crate is not marked with #![crate_okay]");
|
||||
cx.lint(CRATE_NOT_OKAY, |lint| {
|
||||
lint.build("crate is not marked with #![crate_okay]")
|
||||
.set_span(krate.span)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
// Load rustc as a plugin to get macros.
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
#[macro_use]
|
||||
extern crate rustc_lint;
|
||||
#[macro_use]
|
||||
extern crate rustc_session;
|
||||
|
||||
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintArray, LintContext, LintId, LintPass};
|
||||
|
||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||
|
||||
|
@ -21,8 +23,12 @@ declare_lint_pass!(Pass => [TEST_LINT, PLEASE_LINT]);
|
|||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
fn check_item(&mut self, cx: &LateContext, it: &rustc_hir::Item) {
|
||||
match &*it.ident.as_str() {
|
||||
"lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"),
|
||||
"pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"),
|
||||
"lintme" => cx.lint(TEST_LINT, |lint| {
|
||||
lint.build("item is named 'lintme'").set_span(it.span).emit()
|
||||
}),
|
||||
"pleaselintme" => cx.lint(PLEASE_LINT, |lint| {
|
||||
lint.build("item is named 'pleaselintme'").set_span(it.span).emit()
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +38,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]);
|
||||
reg.lint_store.register_late_pass(|| box Pass);
|
||||
reg.lint_store.register_group(true, "lint_me", None,
|
||||
vec![LintId::of(&TEST_LINT), LintId::of(&PLEASE_LINT)]);
|
||||
reg.lint_store.register_group(
|
||||
true,
|
||||
"lint_me",
|
||||
None,
|
||||
vec![LintId::of(&TEST_LINT), LintId::of(&PLEASE_LINT)],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@ extern crate syntax;
|
|||
|
||||
// Load rustc as a plugin to get macros
|
||||
extern crate rustc_driver;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
#[macro_use]
|
||||
extern crate rustc_lint;
|
||||
#[macro_use]
|
||||
extern crate rustc_session;
|
||||
|
||||
use rustc_lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
|
||||
use syntax::ast;
|
||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||
|
||||
|
@ -20,7 +22,9 @@ declare_lint_pass!(Pass => [TEST_LINT]);
|
|||
impl EarlyLintPass for Pass {
|
||||
fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
|
||||
if it.ident.name.as_str() == "lintme" {
|
||||
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
|
||||
cx.lint(TEST_LINT, |lint| {
|
||||
lint.build("item is named 'lintme'").set_span(it.span).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@ extern crate syntax;
|
|||
|
||||
// Load rustc as a plugin to get macros
|
||||
extern crate rustc_driver;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
#[macro_use]
|
||||
extern crate rustc_lint;
|
||||
#[macro_use]
|
||||
extern crate rustc_session;
|
||||
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintId, LintPass};
|
||||
use syntax::ast;
|
||||
declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
|
||||
declare_tool_lint!(
|
||||
|
@ -30,10 +32,14 @@ declare_lint_pass!(Pass => [TEST_LINT, TEST_GROUP, TEST_RUSTC_TOOL_LINT]);
|
|||
impl EarlyLintPass for Pass {
|
||||
fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
|
||||
if it.ident.name.as_str() == "lintme" {
|
||||
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
|
||||
cx.lint(TEST_LINT, |lint| {
|
||||
lint.build("item is named 'lintme'").set_span(it.span).emit()
|
||||
});
|
||||
}
|
||||
if it.ident.name.as_str() == "lintmetoo" {
|
||||
cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'");
|
||||
cx.lint(TEST_GROUP, |lint| {
|
||||
lint.build("item is named 'lintmetoo'").set_span(it.span).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +48,10 @@ impl EarlyLintPass for Pass {
|
|||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]);
|
||||
reg.lint_store.register_early_pass(|| box Pass);
|
||||
reg.lint_store.register_group(true, "clippy::group", Some("clippy_group"),
|
||||
vec![LintId::of(&TEST_LINT), LintId::of(&TEST_GROUP)]);
|
||||
reg.lint_store.register_group(
|
||||
true,
|
||||
"clippy::group",
|
||||
Some("clippy_group"),
|
||||
vec![LintId::of(&TEST_LINT), LintId::of(&TEST_GROUP)],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ impl Tr for E {
|
|||
fn f() -> Self::V { 0 }
|
||||
//~^ ERROR ambiguous associated item
|
||||
//~| WARN this was previously accepted
|
||||
//~| HELP use fully-qualified syntax
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue