use std::cmp;
use crate::ich::StableHashingContext;
-use crate::lint;
use crate::lint::context::{CheckLintNameResult, LintStore};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
use rustc_session::lint::{builtin, Level, Lint, LintId};
-use rustc_session::Session;
-use rustc_span::source_map::MultiSpan;
+use rustc_session::{DiagnosticMessageId, Session};
+use rustc_span::hygiene::MacroKind;
+use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use syntax::ast;
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
name
);
- lint::struct_lint_level(
+ struct_lint_level(
self.sess,
lint,
lvl,
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
let (level, src) =
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
- let mut err = lint::struct_lint_level(
+ let mut err = struct_lint_level(
self.sess,
lint,
level,
let (level, src) =
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
let msg = format!("unknown lint: `{}`", name);
- let mut db = lint::struct_lint_level(
+ let mut db = struct_lint_level(
self.sess,
lint,
level,
msg: &str,
) -> DiagnosticBuilder<'a> {
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
- lint::struct_lint_level(self.sess, lint, level, src, span, msg)
+ struct_lint_level(self.sess, lint, level, src, span, msg)
}
/// Registers the ID provided with the current set of lints stored in
})
}
}
+
+pub fn struct_lint_level<'a>(
+ sess: &'a Session,
+ lint: &'static Lint,
+ level: Level,
+ src: LintSource,
+ span: Option<MultiSpan>,
+ msg: &str,
+) -> DiagnosticBuilder<'a> {
+ 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),
+ };
+
+ // Check for future incompatibility lints and issue a stronger warning.
+ let lint_id = LintId::of(lint);
+ let future_incompatible = lint.future_incompatible;
+
+ // If this code originates in a foreign macro, aka something that this crate
+ // did not itself author, then it's likely that there's nothing this crate
+ // can do about it. We probably want to skip the lint entirely.
+ if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
+ // Any suggestions made here are likely to be incorrect, so anything we
+ // emit shouldn't be automatically fixed by rustfix.
+ err.allow_suggestions(false);
+
+ // If this is a future incompatible lint it'll become a hard error, so
+ // we have to emit *something*. Also allow lints to whitelist themselves
+ // on a case-by-case basis for emission in a foreign macro.
+ if future_incompatible.is_none() && !lint.report_in_external_macro {
+ 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;
+ }
+ }
+
+ let name = lint.name_lower();
+ match src {
+ LintSource::Default => {
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ &format!("`#[{}({})]` on by default", level.as_str(), name),
+ );
+ }
+ LintSource::CommandLine(lint_flag_val) => {
+ let flag = match level {
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ Level::Allow => panic!(),
+ };
+ let hyphen_case_lint_name = name.replace("_", "-");
+ if lint_flag_val.as_str() == name {
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ &format!(
+ "requested on the command line with `{} {}`",
+ flag, hyphen_case_lint_name
+ ),
+ );
+ } else {
+ let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ &format!(
+ "`{} {}` implied by `{} {}`",
+ flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
+ ),
+ );
+ }
+ }
+ LintSource::Node(lint_attr_name, src, reason) => {
+ if let Some(rationale) = reason {
+ err.note(&rationale.as_str());
+ }
+ sess.diag_span_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ src,
+ "lint level defined here",
+ );
+ if lint_attr_name.as_str() != name {
+ let level_str = level.as_str();
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ &format!(
+ "`#[{}({})]` implied by `#[{}({})]`",
+ level_str, name, level_str, lint_attr_name
+ ),
+ );
+ }
+ }
+ }
+
+ err.code(DiagnosticId::Lint(name));
+
+ if let Some(future_incompatible) = future_incompatible {
+ const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
+ it will become a hard error";
+
+ let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
+ "once this method is added to the standard library, \
+ the ambiguity may cause an error or change in behavior!"
+ .to_owned()
+ } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
+ "this borrowing pattern was not meant to be accepted, \
+ and may become a hard error in the future"
+ .to_owned()
+ } else if let Some(edition) = future_incompatible.edition {
+ format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
+ } else {
+ format!("{} in a future release!", STANDARD_MESSAGE)
+ };
+ let citation = format!("for more information, see {}", future_incompatible.reference);
+ err.warn(&explanation);
+ err.note(&citation);
+ }
+
+ return err;
+}
+
+/// Returns whether `span` originates in a foreign crate's external macro.
+///
+/// This is used to test whether a lint should not even begin to figure out whether it should
+/// be reported on the current node.
+pub fn in_external_macro(sess: &Session, span: Span) -> bool {
+ let expn_data = span.ctxt().outer_expn_data();
+ match expn_data.kind {
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
+ ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
+ ExpnKind::Macro(MacroKind::Bang, _) => {
+ if expn_data.def_site.is_dummy() {
+ // Dummy span for the `def_site` means it's an external macro.
+ return true;
+ }
+ match sess.source_map().span_to_snippet(expn_data.def_site) {
+ Ok(code) => !code.starts_with("macro_rules"),
+ // No snippet means external macro or compiler-builtin expansion.
+ Err(_) => true,
+ }
+ }
+ ExpnKind::Macro(..) => true, // definitely a plugin
+ }
+}
use crate::ty::TyCtxt;
use rustc_data_structures::sync;
-use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir as hir;
use rustc_session::lint::builtin::HardwiredLints;
-use rustc_session::{DiagnosticMessageId, Session};
-use rustc_span::hygiene::MacroKind;
-use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::Span;
use syntax::ast;
pub mod internal;
mod levels;
-pub use self::levels::{LintLevelMap, LintLevelSets, LintLevelsBuilder};
-
-pub fn struct_lint_level<'a>(
- sess: &'a Session,
- lint: &'static Lint,
- level: Level,
- src: LintSource,
- span: Option<MultiSpan>,
- msg: &str,
-) -> DiagnosticBuilder<'a> {
- 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),
- };
-
- // Check for future incompatibility lints and issue a stronger warning.
- let lint_id = LintId::of(lint);
- let future_incompatible = lint.future_incompatible;
-
- // If this code originates in a foreign macro, aka something that this crate
- // did not itself author, then it's likely that there's nothing this crate
- // can do about it. We probably want to skip the lint entirely.
- if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
- // Any suggestions made here are likely to be incorrect, so anything we
- // emit shouldn't be automatically fixed by rustfix.
- err.allow_suggestions(false);
-
- // If this is a future incompatible lint it'll become a hard error, so
- // we have to emit *something*. Also allow lints to whitelist themselves
- // on a case-by-case basis for emission in a foreign macro.
- if future_incompatible.is_none() && !lint.report_in_external_macro {
- 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;
- }
- }
-
- let name = lint.name_lower();
- match src {
- LintSource::Default => {
- sess.diag_note_once(
- &mut err,
- DiagnosticMessageId::from(lint),
- &format!("`#[{}({})]` on by default", level.as_str(), name),
- );
- }
- LintSource::CommandLine(lint_flag_val) => {
- let flag = match level {
- Level::Warn => "-W",
- Level::Deny => "-D",
- Level::Forbid => "-F",
- Level::Allow => panic!(),
- };
- let hyphen_case_lint_name = name.replace("_", "-");
- if lint_flag_val.as_str() == name {
- sess.diag_note_once(
- &mut err,
- DiagnosticMessageId::from(lint),
- &format!(
- "requested on the command line with `{} {}`",
- flag, hyphen_case_lint_name
- ),
- );
- } else {
- let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
- sess.diag_note_once(
- &mut err,
- DiagnosticMessageId::from(lint),
- &format!(
- "`{} {}` implied by `{} {}`",
- flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
- ),
- );
- }
- }
- LintSource::Node(lint_attr_name, src, reason) => {
- if let Some(rationale) = reason {
- err.note(&rationale.as_str());
- }
- sess.diag_span_note_once(
- &mut err,
- DiagnosticMessageId::from(lint),
- src,
- "lint level defined here",
- );
- if lint_attr_name.as_str() != name {
- let level_str = level.as_str();
- sess.diag_note_once(
- &mut err,
- DiagnosticMessageId::from(lint),
- &format!(
- "`#[{}({})]` implied by `#[{}({})]`",
- level_str, name, level_str, lint_attr_name
- ),
- );
- }
- }
- }
-
- err.code(DiagnosticId::Lint(name));
-
- if let Some(future_incompatible) = future_incompatible {
- const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
- it will become a hard error";
-
- let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
- "once this method is added to the standard library, \
- the ambiguity may cause an error or change in behavior!"
- .to_owned()
- } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
- "this borrowing pattern was not meant to be accepted, \
- and may become a hard error in the future"
- .to_owned()
- } else if let Some(edition) = future_incompatible.edition {
- format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
- } else {
- format!("{} in a future release!", STANDARD_MESSAGE)
- };
- let citation = format!("for more information, see {}", future_incompatible.reference);
- err.warn(&explanation);
- err.note(&citation);
- }
-
- return err;
-}
+pub use self::levels::{struct_lint_level, LintLevelMap, LintLevelSets, LintLevelsBuilder};
pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
let attrs = tcx.hir().attrs(id);
attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some())
}
-
-/// Returns whether `span` originates in a foreign crate's external macro.
-///
-/// This is used to test whether a lint should not even begin to figure out whether it should
-/// be reported on the current node.
-pub fn in_external_macro(sess: &Session, span: Span) -> bool {
- let expn_data = span.ctxt().outer_expn_data();
- match expn_data.kind {
- ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
- ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
- ExpnKind::Macro(MacroKind::Bang, _) => {
- if expn_data.def_site.is_dummy() {
- // Dummy span for the `def_site` means it's an external macro.
- return true;
- }
- match sess.source_map().span_to_snippet(expn_data.def_site) {
- Ok(code) => !code.starts_with("macro_rules"),
- // No snippet means external macro or compiler-builtin expansion.
- Err(_) => true,
- }
- }
- ExpnKind::Macro(..) => true, // definitely a plugin
- }
-}