Rollup merge of #68045 - Centril:liberate-lints, r=Mark-Simulacrum
Move more of `rustc::lint` into `rustc_lint` Based on https://github.com/rust-lang/rust/pull/67806. Here we try to consolidate more of the linting infra into `rustc::lint`. Some high-level notes: - We now store an `Lrc<dyn Any + Send + Sync>` as opposed to `Lrc<LintStore>` in the `GlobalCtxt`. This enables us to avoid referring to the type, breaking a cyclic dependency, and so we can move things from `rustc::lint` to `rustc_lint`. - `in_derive_expansion` is, and needs to, be moved as a method on `Span`. - We reduce the number of ways on `tcx` to emit a lint so that the developer UX is more streamlined. - `LintLevelsBuilder` is moved to `rustc_lint::levels`, leaving behind `LintLevelMap/Set` in a purified form due to current constraints (hopefully fixable in the future after https://github.com/rust-lang/rust/pull/68133). - `struct_lint_level` is moved to `rustc::lint` due to current dependency constraints. - `rustc::lint::context` is moved to `rustc_lint::context`. - The visitors in `rustc::lint` are moved to `rustc_lint::passes`.
This commit is contained in:
commit
cc51d0350e
@ -3663,6 +3663,7 @@ dependencies = [
|
||||
"log",
|
||||
"rustc",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_hir",
|
||||
@ -3788,6 +3789,7 @@ dependencies = [
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_lint",
|
||||
"rustc_metadata",
|
||||
"rustc_span",
|
||||
"syntax",
|
||||
|
@ -5,7 +5,6 @@
|
||||
//! item.
|
||||
|
||||
use crate::hir::map::Map;
|
||||
use crate::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use crate::ty::query::Providers;
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
@ -16,6 +15,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::DUMMY_HIR_ID;
|
||||
use rustc_hir::{self, HirId, Item, ItemKind, TraitItem, TraitItemKind};
|
||||
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use syntax::ast::Attribute;
|
||||
|
@ -71,8 +71,6 @@ extern crate rustc_data_structures;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate syntax;
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
|
||||
#[cfg(test)]
|
||||
|
369
src/librustc/lint.rs
Normal file
369
src/librustc/lint.rs
Normal file
@ -0,0 +1,369 @@
|
||||
use std::cmp;
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use rustc_hir::HirId;
|
||||
pub use rustc_session::lint::{builtin, Level, Lint, LintId, LintPass};
|
||||
use rustc_session::{DiagnosticMessageId, Session};
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
/// How a lint level was set.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
|
||||
pub enum LintSource {
|
||||
/// Lint is at the default level as declared
|
||||
/// in rustc or a plugin.
|
||||
Default,
|
||||
|
||||
/// Lint level was set by an attribute.
|
||||
Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),
|
||||
|
||||
/// Lint level was set by a command-line flag.
|
||||
CommandLine(Symbol),
|
||||
}
|
||||
|
||||
pub type LevelSource = (Level, LintSource);
|
||||
|
||||
pub struct LintLevelSets {
|
||||
pub list: Vec<LintSet>,
|
||||
pub lint_cap: Level,
|
||||
}
|
||||
|
||||
pub enum LintSet {
|
||||
CommandLine {
|
||||
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
|
||||
// flag.
|
||||
specs: FxHashMap<LintId, LevelSource>,
|
||||
},
|
||||
|
||||
Node {
|
||||
specs: FxHashMap<LintId, LevelSource>,
|
||||
parent: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl LintLevelSets {
|
||||
pub fn new() -> Self {
|
||||
LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
|
||||
}
|
||||
|
||||
pub fn get_lint_level(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
idx: u32,
|
||||
aux: Option<&FxHashMap<LintId, LevelSource>>,
|
||||
sess: &Session,
|
||||
) -> LevelSource {
|
||||
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
|
||||
|
||||
// If `level` is none then we actually assume the default level for this
|
||||
// lint.
|
||||
let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
|
||||
|
||||
// If we're about to issue a warning, check at the last minute for any
|
||||
// directives against the warnings "lint". If, for example, there's an
|
||||
// `allow(warnings)` in scope then we want to respect that instead.
|
||||
if level == Level::Warn {
|
||||
let (warnings_level, warnings_src) =
|
||||
self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
|
||||
if let Some(configured_warning_level) = warnings_level {
|
||||
if configured_warning_level != Level::Warn {
|
||||
level = configured_warning_level;
|
||||
src = warnings_src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that we never exceed the `--cap-lints` argument.
|
||||
level = cmp::min(level, self.lint_cap);
|
||||
|
||||
if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
|
||||
// Ensure that we never exceed driver level.
|
||||
level = cmp::min(*driver_level, level);
|
||||
}
|
||||
|
||||
return (level, src);
|
||||
}
|
||||
|
||||
pub fn get_lint_id_level(
|
||||
&self,
|
||||
id: LintId,
|
||||
mut idx: u32,
|
||||
aux: Option<&FxHashMap<LintId, LevelSource>>,
|
||||
) -> (Option<Level>, LintSource) {
|
||||
if let Some(specs) = aux {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
}
|
||||
loop {
|
||||
match self.list[idx as usize] {
|
||||
LintSet::CommandLine { ref specs } => {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
return (None, LintSource::Default);
|
||||
}
|
||||
LintSet::Node { ref specs, parent } => {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
idx = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LintLevelMap {
|
||||
pub sets: LintLevelSets,
|
||||
pub id_to_set: FxHashMap<HirId, u32>,
|
||||
}
|
||||
|
||||
impl LintLevelMap {
|
||||
/// If the `id` was previously registered with `register_id` when building
|
||||
/// this `LintLevelMap` this returns the corresponding lint level and source
|
||||
/// of the lint level for the lint provided.
|
||||
///
|
||||
/// If the `id` was not previously registered, returns `None`. If `None` is
|
||||
/// returned then the parent of `id` should be acquired and this function
|
||||
/// should be called again.
|
||||
pub fn level_and_source(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
id: HirId,
|
||||
session: &Session,
|
||||
) -> Option<LevelSource> {
|
||||
self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||
let LintLevelMap { ref sets, ref id_to_set } = *self;
|
||||
|
||||
id_to_set.hash_stable(hcx, hasher);
|
||||
|
||||
let LintLevelSets { ref list, lint_cap } = *sets;
|
||||
|
||||
lint_cap.hash_stable(hcx, hasher);
|
||||
|
||||
hcx.while_hashing_spans(true, |hcx| {
|
||||
list.len().hash_stable(hcx, hasher);
|
||||
|
||||
// We are working under the assumption here that the list of
|
||||
// lint-sets is built in a deterministic order.
|
||||
for lint_set in list {
|
||||
::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);
|
||||
|
||||
match *lint_set {
|
||||
LintSet::CommandLine { ref specs } => {
|
||||
specs.hash_stable(hcx, hasher);
|
||||
}
|
||||
LintSet::Node { ref specs, parent } => {
|
||||
specs.hash_stable(hcx, hasher);
|
||||
parent.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_elided_lifetime_in_path_suggestion(
|
||||
sess: &Session,
|
||||
db: &mut DiagnosticBuilder<'_>,
|
||||
n: usize,
|
||||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
anon_lts: String,
|
||||
) {
|
||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||
(insertion_span, anon_lts)
|
||||
} else {
|
||||
// When possible, prefer a suggestion that replaces the whole
|
||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||
// at a point (which makes for an ugly/confusing label)
|
||||
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
||||
// But our spans can get out of whack due to macros; if the place we think
|
||||
// we want to insert `'_` isn't even within the path expression's span, we
|
||||
// should bail out of making any suggestion rather than panicking on a
|
||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||
// FIXME: can we do better?
|
||||
if insertion_span.lo().0 < path_span.lo().0 {
|
||||
return;
|
||||
}
|
||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||
if insertion_index > snippet.len() {
|
||||
return;
|
||||
}
|
||||
let (before, after) = snippet.split_at(insertion_index);
|
||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||
} else {
|
||||
(insertion_span, anon_lts)
|
||||
}
|
||||
};
|
||||
db.span_suggestion(
|
||||
replace_span,
|
||||
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
@ -1,550 +0,0 @@
|
||||
use std::cmp;
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::lint::builtin;
|
||||
use crate::lint::context::{CheckLintNameResult, LintStore};
|
||||
use crate::lint::{self, Level, Lint, LintId, LintSource};
|
||||
use crate::session::Session;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_span::source_map::MultiSpan;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::print::pprust;
|
||||
use syntax::sess::feature_err;
|
||||
|
||||
use rustc_error_codes::*;
|
||||
|
||||
pub struct LintLevelSets {
|
||||
list: Vec<LintSet>,
|
||||
lint_cap: Level,
|
||||
}
|
||||
|
||||
enum LintSet {
|
||||
CommandLine {
|
||||
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
|
||||
// flag.
|
||||
specs: FxHashMap<LintId, (Level, LintSource)>,
|
||||
},
|
||||
|
||||
Node {
|
||||
specs: FxHashMap<LintId, (Level, LintSource)>,
|
||||
parent: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl LintLevelSets {
|
||||
pub fn new(sess: &Session, lint_store: &LintStore) -> LintLevelSets {
|
||||
let mut me = LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid };
|
||||
me.process_command_line(sess, lint_store);
|
||||
return me;
|
||||
}
|
||||
|
||||
pub fn builder<'a>(
|
||||
sess: &'a Session,
|
||||
warn_about_weird_lints: bool,
|
||||
store: &LintStore,
|
||||
) -> LintLevelsBuilder<'a> {
|
||||
LintLevelsBuilder::new(sess, warn_about_weird_lints, LintLevelSets::new(sess, store))
|
||||
}
|
||||
|
||||
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
|
||||
let mut specs = FxHashMap::default();
|
||||
self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
|
||||
|
||||
for &(ref lint_name, level) in &sess.opts.lint_opts {
|
||||
store.check_lint_name_cmdline(sess, &lint_name, level);
|
||||
|
||||
// If the cap is less than this specified level, e.g., if we've got
|
||||
// `--cap-lints allow` but we've also got `-D foo` then we ignore
|
||||
// this specification as the lint cap will set it to allow anyway.
|
||||
let level = cmp::min(level, self.lint_cap);
|
||||
|
||||
let lint_flag_val = Symbol::intern(lint_name);
|
||||
let ids = match store.find_lints(&lint_name) {
|
||||
Ok(ids) => ids,
|
||||
Err(_) => continue, // errors handled in check_lint_name_cmdline above
|
||||
};
|
||||
for id in ids {
|
||||
let src = LintSource::CommandLine(lint_flag_val);
|
||||
specs.insert(id, (level, src));
|
||||
}
|
||||
}
|
||||
|
||||
self.list.push(LintSet::CommandLine { specs: specs });
|
||||
}
|
||||
|
||||
fn get_lint_level(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
idx: u32,
|
||||
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
|
||||
sess: &Session,
|
||||
) -> (Level, LintSource) {
|
||||
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
|
||||
|
||||
// If `level` is none then we actually assume the default level for this
|
||||
// lint.
|
||||
let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
|
||||
|
||||
// If we're about to issue a warning, check at the last minute for any
|
||||
// directives against the warnings "lint". If, for example, there's an
|
||||
// `allow(warnings)` in scope then we want to respect that instead.
|
||||
if level == Level::Warn {
|
||||
let (warnings_level, warnings_src) =
|
||||
self.get_lint_id_level(LintId::of(lint::builtin::WARNINGS), idx, aux);
|
||||
if let Some(configured_warning_level) = warnings_level {
|
||||
if configured_warning_level != Level::Warn {
|
||||
level = configured_warning_level;
|
||||
src = warnings_src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that we never exceed the `--cap-lints` argument.
|
||||
level = cmp::min(level, self.lint_cap);
|
||||
|
||||
if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
|
||||
// Ensure that we never exceed driver level.
|
||||
level = cmp::min(*driver_level, level);
|
||||
}
|
||||
|
||||
return (level, src);
|
||||
}
|
||||
|
||||
fn get_lint_id_level(
|
||||
&self,
|
||||
id: LintId,
|
||||
mut idx: u32,
|
||||
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
|
||||
) -> (Option<Level>, LintSource) {
|
||||
if let Some(specs) = aux {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
}
|
||||
loop {
|
||||
match self.list[idx as usize] {
|
||||
LintSet::CommandLine { ref specs } => {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
return (None, LintSource::Default);
|
||||
}
|
||||
LintSet::Node { ref specs, parent } => {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
idx = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LintLevelsBuilder<'a> {
|
||||
sess: &'a Session,
|
||||
sets: LintLevelSets,
|
||||
id_to_set: FxHashMap<HirId, u32>,
|
||||
cur: u32,
|
||||
warn_about_weird_lints: bool,
|
||||
}
|
||||
|
||||
pub struct BuilderPush {
|
||||
prev: u32,
|
||||
pub changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> LintLevelsBuilder<'a> {
|
||||
pub fn new(
|
||||
sess: &'a Session,
|
||||
warn_about_weird_lints: bool,
|
||||
sets: LintLevelSets,
|
||||
) -> LintLevelsBuilder<'a> {
|
||||
assert_eq!(sets.list.len(), 1);
|
||||
LintLevelsBuilder {
|
||||
sess,
|
||||
sets,
|
||||
cur: 0,
|
||||
id_to_set: Default::default(),
|
||||
warn_about_weird_lints,
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a list of AST lint attributes onto this context.
|
||||
///
|
||||
/// This function will return a `BuilderPush` object which should be passed
|
||||
/// to `pop` when this scope for the attributes provided is exited.
|
||||
///
|
||||
/// This function will perform a number of tasks:
|
||||
///
|
||||
/// * It'll validate all lint-related attributes in `attrs`
|
||||
/// * It'll mark all lint-related attributes as used
|
||||
/// * Lint levels will be updated based on the attributes provided
|
||||
/// * Lint attributes are validated, e.g., a #[forbid] can't be switched to
|
||||
/// #[allow]
|
||||
///
|
||||
/// Don't forget to call `pop`!
|
||||
pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
|
||||
let mut specs = FxHashMap::default();
|
||||
let sess = self.sess;
|
||||
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
|
||||
for attr in attrs {
|
||||
let level = match Level::from_symbol(attr.name_or_empty()) {
|
||||
None => continue,
|
||||
Some(lvl) => lvl,
|
||||
};
|
||||
|
||||
let meta = unwrap_or!(attr.meta(), continue);
|
||||
attr::mark_used(attr);
|
||||
|
||||
let mut metas = unwrap_or!(meta.meta_item_list(), continue);
|
||||
|
||||
if metas.is_empty() {
|
||||
// FIXME (#55112): issue unused-attributes lint for `#[level()]`
|
||||
continue;
|
||||
}
|
||||
|
||||
// Before processing the lint names, look for a reason (RFC 2383)
|
||||
// at the end.
|
||||
let mut reason = None;
|
||||
let tail_li = &metas[metas.len() - 1];
|
||||
if let Some(item) = tail_li.meta_item() {
|
||||
match item.kind {
|
||||
ast::MetaItemKind::Word => {} // actual lint names handled later
|
||||
ast::MetaItemKind::NameValue(ref name_value) => {
|
||||
if item.path == sym::reason {
|
||||
// found reason, reslice meta list to exclude it
|
||||
metas = &metas[0..metas.len() - 1];
|
||||
// FIXME (#55112): issue unused-attributes lint if we thereby
|
||||
// don't have any lint names (`#[level(reason = "foo")]`)
|
||||
if let ast::LitKind::Str(rationale, _) = name_value.kind {
|
||||
if !self.sess.features_untracked().lint_reasons {
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::lint_reasons,
|
||||
item.span,
|
||||
"lint reasons are experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
reason = Some(rationale);
|
||||
} else {
|
||||
bad_attr(name_value.span)
|
||||
.span_label(name_value.span, "reason must be a string literal")
|
||||
.emit();
|
||||
}
|
||||
} else {
|
||||
bad_attr(item.span)
|
||||
.span_label(item.span, "bad attribute argument")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
ast::MetaItemKind::List(_) => {
|
||||
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for li in metas {
|
||||
let meta_item = match li.meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => meta_item,
|
||||
_ => {
|
||||
let sp = li.span();
|
||||
let mut err = bad_attr(sp);
|
||||
let mut add_label = true;
|
||||
if let Some(item) = li.meta_item() {
|
||||
if let ast::MetaItemKind::NameValue(_) = item.kind {
|
||||
if item.path == sym::reason {
|
||||
err.span_label(sp, "reason in lint attribute must come last");
|
||||
add_label = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if add_label {
|
||||
err.span_label(sp, "bad attribute argument");
|
||||
}
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let tool_name = if meta_item.path.segments.len() > 1 {
|
||||
let tool_ident = meta_item.path.segments[0].ident;
|
||||
if !attr::is_known_lint_tool(tool_ident) {
|
||||
struct_span_err!(
|
||||
sess,
|
||||
tool_ident.span,
|
||||
E0710,
|
||||
"an unknown tool name found in scoped lint: `{}`",
|
||||
pprust::path_to_string(&meta_item.path),
|
||||
)
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
|
||||
Some(tool_ident.name)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
|
||||
match store.check_lint_name(&name.as_str(), tool_name) {
|
||||
CheckLintNameResult::Ok(ids) => {
|
||||
let src = LintSource::Node(name, li.span(), reason);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
|
||||
CheckLintNameResult::Tool(result) => {
|
||||
match result {
|
||||
Ok(ids) => {
|
||||
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(complete_name),
|
||||
li.span(),
|
||||
reason,
|
||||
);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
Err((Some(ids), new_lint_name)) => {
|
||||
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
|
||||
);
|
||||
lint::struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
lvl,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
)
|
||||
.span_suggestion(
|
||||
li.span(),
|
||||
"change it to",
|
||||
new_lint_name.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(&new_lint_name),
|
||||
li.span(),
|
||||
reason,
|
||||
);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
Err((None, _)) => {
|
||||
// If Tool(Err(None, _)) is returned, then either the lint does not
|
||||
// exist in the tool or the code was not compiled with the tool and
|
||||
// therefore the lint was never added to the `LintStore`. To detect
|
||||
// this is the responsibility of the lint tool.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ if !self.warn_about_weird_lints => {}
|
||||
|
||||
CheckLintNameResult::Warning(msg, renamed) => {
|
||||
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(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
if let Some(new_name) = renamed {
|
||||
err.span_suggestion(
|
||||
li.span(),
|
||||
"use the new name",
|
||||
new_name,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
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 = lint::struct_lint_level(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
|
||||
if let Some(suggestion) = suggestion {
|
||||
db.span_suggestion(
|
||||
li.span(),
|
||||
"did you mean",
|
||||
suggestion.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
db.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (id, &(level, ref src)) in specs.iter() {
|
||||
if level == Level::Forbid {
|
||||
continue;
|
||||
}
|
||||
let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
|
||||
(Some(Level::Forbid), src) => src,
|
||||
_ => continue,
|
||||
};
|
||||
let forbidden_lint_name = match forbid_src {
|
||||
LintSource::Default => id.to_string(),
|
||||
LintSource::Node(name, _, _) => name.to_string(),
|
||||
LintSource::CommandLine(name) => name.to_string(),
|
||||
};
|
||||
let (lint_attr_name, lint_attr_span) = match *src {
|
||||
LintSource::Node(name, span, _) => (name, span),
|
||||
_ => continue,
|
||||
};
|
||||
let mut diag_builder = struct_span_err!(
|
||||
self.sess,
|
||||
lint_attr_span,
|
||||
E0453,
|
||||
"{}({}) overruled by outer forbid({})",
|
||||
level.as_str(),
|
||||
lint_attr_name,
|
||||
forbidden_lint_name
|
||||
);
|
||||
diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
|
||||
match forbid_src {
|
||||
LintSource::Default => {}
|
||||
LintSource::Node(_, forbid_source_span, reason) => {
|
||||
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
|
||||
if let Some(rationale) = reason {
|
||||
diag_builder.note(&rationale.as_str());
|
||||
}
|
||||
}
|
||||
LintSource::CommandLine(_) => {
|
||||
diag_builder.note("`forbid` lint level was set on command line");
|
||||
}
|
||||
}
|
||||
diag_builder.emit();
|
||||
// don't set a separate error for every lint in the group
|
||||
break;
|
||||
}
|
||||
|
||||
let prev = self.cur;
|
||||
if specs.len() > 0 {
|
||||
self.cur = self.sets.list.len() as u32;
|
||||
self.sets.list.push(LintSet::Node { specs: specs, parent: prev });
|
||||
}
|
||||
|
||||
BuilderPush { prev: prev, changed: prev != self.cur }
|
||||
}
|
||||
|
||||
/// Called after `push` when the scope of a set of attributes are exited.
|
||||
pub fn pop(&mut self, push: BuilderPush) {
|
||||
self.cur = push.prev;
|
||||
}
|
||||
|
||||
/// Used to emit a lint-related diagnostic based on the current state of
|
||||
/// this lint context.
|
||||
pub fn struct_lint(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<MultiSpan>,
|
||||
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)
|
||||
}
|
||||
|
||||
/// Registers the ID provided with the current set of lints stored in
|
||||
/// this context.
|
||||
pub fn register_id(&mut self, id: HirId) {
|
||||
self.id_to_set.insert(id, self.cur);
|
||||
}
|
||||
|
||||
pub fn build(self) -> LintLevelSets {
|
||||
self.sets
|
||||
}
|
||||
|
||||
pub fn build_map(self) -> LintLevelMap {
|
||||
LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LintLevelMap {
|
||||
sets: LintLevelSets,
|
||||
id_to_set: FxHashMap<HirId, u32>,
|
||||
}
|
||||
|
||||
impl LintLevelMap {
|
||||
/// If the `id` was previously registered with `register_id` when building
|
||||
/// this `LintLevelMap` this returns the corresponding lint level and source
|
||||
/// of the lint level for the lint provided.
|
||||
///
|
||||
/// If the `id` was not previously registered, returns `None`. If `None` is
|
||||
/// returned then the parent of `id` should be acquired and this function
|
||||
/// should be called again.
|
||||
pub fn level_and_source(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
id: HirId,
|
||||
session: &Session,
|
||||
) -> Option<(Level, LintSource)> {
|
||||
self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||
let LintLevelMap { ref sets, ref id_to_set } = *self;
|
||||
|
||||
id_to_set.hash_stable(hcx, hasher);
|
||||
|
||||
let LintLevelSets { ref list, lint_cap } = *sets;
|
||||
|
||||
lint_cap.hash_stable(hcx, hasher);
|
||||
|
||||
hcx.while_hashing_spans(true, |hcx| {
|
||||
list.len().hash_stable(hcx, hasher);
|
||||
|
||||
// We are working under the assumption here that the list of
|
||||
// lint-sets is built in a deterministic order.
|
||||
for lint_set in list {
|
||||
::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);
|
||||
|
||||
match *lint_set {
|
||||
LintSet::CommandLine { ref specs } => {
|
||||
specs.hash_stable(hcx, hasher);
|
||||
}
|
||||
LintSet::Node { ref specs, parent } => {
|
||||
specs.hash_stable(hcx, hasher);
|
||||
parent.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
|
||||
pub use self::StabilityLevel::*;
|
||||
|
||||
use crate::lint::{self, in_derive_expansion, Lint};
|
||||
use crate::session::{DiagnosticMessageId, Session};
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
@ -13,7 +12,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
||||
use rustc_hir::{self, HirId};
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::lint::{self, BuiltinLintDiagnostics, Lint, LintBuffer};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
use syntax::ast::CRATE_NODE_ID;
|
||||
@ -201,7 +200,7 @@ pub fn early_report_deprecation(
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
) {
|
||||
if in_derive_expansion(span) {
|
||||
if span.in_derive_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -218,7 +217,7 @@ fn late_report_deprecation(
|
||||
def_id: DefId,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
if in_derive_expansion(span) {
|
||||
if span.in_derive_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
||||
.next()
|
||||
.unwrap_or(lint_root);
|
||||
tcx.struct_span_lint_hir(
|
||||
crate::rustc::lint::builtin::CONST_ERR,
|
||||
rustc_session::lint::builtin::CONST_ERR,
|
||||
hir_id,
|
||||
tcx.span,
|
||||
message,
|
||||
|
@ -82,7 +82,7 @@ rustc_queries! {
|
||||
desc { "looking up the native libraries of a linked crate" }
|
||||
}
|
||||
|
||||
query lint_levels(_: CrateNum) -> &'tcx lint::LintLevelMap {
|
||||
query lint_levels(_: CrateNum) -> &'tcx LintLevelMap {
|
||||
eval_always
|
||||
desc { "computing the lint levels for items in this crate" }
|
||||
}
|
||||
|
@ -10,17 +10,18 @@
|
||||
|
||||
use super::elaborate_predicates;
|
||||
|
||||
use crate::lint;
|
||||
use crate::traits::{self, Obligation, ObligationCause};
|
||||
use crate::ty::subst::{InternalSubsts, Subst};
|
||||
use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use syntax::ast;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::iter::{self};
|
||||
use syntax::ast::{self};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ObjectSafetyViolation {
|
||||
@ -178,16 +179,17 @@ 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.
|
||||
tcx.lint_node_note(
|
||||
lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
|
||||
tcx.struct_span_lint_hir(
|
||||
WHERE_CLAUSES_OBJECT_SAFETY,
|
||||
hir::CRATE_HIR_ID,
|
||||
*span,
|
||||
&format!(
|
||||
"the trait `{}` cannot be made into an object",
|
||||
tcx.def_path_str(trait_def_id)
|
||||
),
|
||||
&violation.error_msg(),
|
||||
);
|
||||
)
|
||||
.note(&violation.error_msg())
|
||||
.emit();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
|
@ -12,7 +12,6 @@
|
||||
pub mod specialization_graph;
|
||||
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::lint;
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
|
||||
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
@ -20,6 +19,7 @@ use crate::ty::{self, TyCtxt, TypeFoldable};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use super::util::impl_trait_ref_and_oblig;
|
||||
@ -342,7 +342,7 @@ pub(super) fn specialization_graph_provider(
|
||||
unreachable!("converted to hard error above")
|
||||
}
|
||||
FutureCompatOverlapErrorKind::Issue33140 => {
|
||||
lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS
|
||||
ORDER_DEPENDENT_TRAIT_OBJECTS
|
||||
}
|
||||
};
|
||||
tcx.struct_span_lint_hir(
|
||||
|
@ -8,7 +8,7 @@ use crate::hir::map as hir_map;
|
||||
use crate::hir::map::DefPathHash;
|
||||
use crate::ich::{NodeIdHashingMode, StableHashingContext};
|
||||
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
||||
use crate::lint::{self, Lint};
|
||||
use crate::lint::{struct_lint_level, LintSource};
|
||||
use crate::middle;
|
||||
use crate::middle::cstore::CrateStoreDyn;
|
||||
use crate::middle::cstore::EncodedMetadata;
|
||||
@ -20,9 +20,6 @@ use crate::mir::interpret::{Allocation, ConstValue, Scalar};
|
||||
use crate::mir::{
|
||||
interpret, BodyAndCache, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
|
||||
};
|
||||
use crate::session::config::CrateType;
|
||||
use crate::session::config::{BorrowckMode, OutputFilenames};
|
||||
use crate::session::Session;
|
||||
use crate::traits;
|
||||
use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
|
||||
use crate::ty::free_region_map::FreeRegionMap;
|
||||
@ -44,11 +41,15 @@ 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_data_structures::sync;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE};
|
||||
use rustc_hir::{HirId, Node, TraitCandidate};
|
||||
use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::config::{BorrowckMode, OutputFilenames};
|
||||
use rustc_session::Session;
|
||||
|
||||
use arena::SyncDroplessArena;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
@ -61,6 +62,7 @@ use rustc_data_structures::sync::{Lock, Lrc, WorkerLocal};
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_session::lint::{Level, Lint};
|
||||
use rustc_session::node_id::NodeMap;
|
||||
use rustc_span::source_map::MultiSpan;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
@ -946,7 +948,11 @@ pub struct GlobalCtxt<'tcx> {
|
||||
|
||||
pub sess: &'tcx Session,
|
||||
|
||||
pub lint_store: Lrc<lint::LintStore>,
|
||||
/// This only ever stores a `LintStore` but we don't want a dependency on that type here.
|
||||
///
|
||||
/// FIXME(Centril): consider `dyn LintStoreMarker` once
|
||||
/// we can upcast to `Any` for some additional type safety.
|
||||
pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>,
|
||||
|
||||
pub dep_graph: DepGraph,
|
||||
|
||||
@ -1115,7 +1121,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
/// reference to the context, to allow formatting values that need it.
|
||||
pub fn create_global_ctxt(
|
||||
s: &'tcx Session,
|
||||
lint_store: Lrc<lint::LintStore>,
|
||||
lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
|
||||
local_providers: ty::query::Providers<'tcx>,
|
||||
extern_providers: ty::query::Providers<'tcx>,
|
||||
arenas: &'tcx AllArenas,
|
||||
@ -2551,57 +2557,29 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
iter.intern_with(|xs| self.intern_goals(xs))
|
||||
}
|
||||
|
||||
pub fn lint_hir<S: Into<MultiSpan>>(
|
||||
pub fn lint_hir(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: S,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
) {
|
||||
self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
|
||||
}
|
||||
|
||||
pub fn lint_hir_note<S: Into<MultiSpan>>(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: S,
|
||||
msg: &str,
|
||||
note: &str,
|
||||
) {
|
||||
let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg);
|
||||
err.note(note);
|
||||
err.emit()
|
||||
}
|
||||
|
||||
pub fn lint_node_note<S: Into<MultiSpan>>(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
id: hir::HirId,
|
||||
span: S,
|
||||
msg: &str,
|
||||
note: &str,
|
||||
) {
|
||||
let mut err = self.struct_span_lint_hir(lint, id, span.into(), msg);
|
||||
err.note(note);
|
||||
err.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: hir::HirId,
|
||||
bound: hir::HirId,
|
||||
) -> hir::HirId {
|
||||
pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
|
||||
let hir = self.hir();
|
||||
loop {
|
||||
if id == bound {
|
||||
return bound;
|
||||
}
|
||||
if lint::maybe_lint_level_root(self, id) {
|
||||
|
||||
if hir.attrs(id).iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) {
|
||||
return id;
|
||||
}
|
||||
let next = self.hir().get_parent_node(id);
|
||||
let next = hir.get_parent_node(id);
|
||||
if next == id {
|
||||
bug!("lint traversal reached the root of the crate");
|
||||
}
|
||||
@ -2613,7 +2591,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
mut id: hir::HirId,
|
||||
) -> (lint::Level, lint::LintSource) {
|
||||
) -> (Level, LintSource) {
|
||||
let sets = self.lint_levels(LOCAL_CRATE);
|
||||
loop {
|
||||
if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
|
||||
@ -2627,15 +2605,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_span_lint_hir<S: Into<MultiSpan>>(
|
||||
pub fn struct_span_lint_hir(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: S,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let (level, src) = self.lint_level_at_node(lint, hir_id);
|
||||
lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
|
||||
struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
|
||||
}
|
||||
|
||||
pub fn struct_lint_node(
|
||||
@ -2645,7 +2623,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let (level, src) = self.lint_level_at_node(lint, id);
|
||||
lint::struct_lint_level(self.sess, lint, level, src, None, msg)
|
||||
struct_lint_level(self.sess, lint, level, src, None, msg)
|
||||
}
|
||||
|
||||
pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::dep_graph::{self, DepNode};
|
||||
use crate::hir::exports::Export;
|
||||
use crate::infer::canonical::{self, Canonical};
|
||||
use crate::lint;
|
||||
use crate::lint::LintLevelMap;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind};
|
||||
use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary};
|
||||
|
@ -37,7 +37,6 @@ use rustc::arena::Arena;
|
||||
use rustc::dep_graph::DepGraph;
|
||||
use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::builtin;
|
||||
use rustc::{bug, span_bug};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -51,7 +50,7 @@ use rustc_hir::intravisit;
|
||||
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_session::config::nightly_options;
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::lint::{builtin, BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::node_id::NodeMap;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
|
@ -11,7 +11,7 @@ path = "lib.rs"
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_parse = { path = "../librustc_parse" }
|
||||
|
@ -23,9 +23,7 @@ extern crate lazy_static;
|
||||
|
||||
pub extern crate rustc_plugin_impl as plugin;
|
||||
|
||||
//use rustc_resolve as resolve;
|
||||
use rustc::lint;
|
||||
use rustc::lint::Lint;
|
||||
use rustc::lint::{Lint, LintId};
|
||||
use rustc::middle::cstore::MetadataLoader;
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::session::config::{ErrorOutputType, Input, OutputType, PrintRequest};
|
||||
@ -41,6 +39,7 @@ use rustc_feature::{find_gated_cfg, UnstableFeatures};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_interface::util::get_builtin_codegen_backend;
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_save_analysis as save;
|
||||
use rustc_save_analysis::DumpHandler;
|
||||
@ -811,7 +810,7 @@ the command line flag directly.
|
||||
);
|
||||
}
|
||||
|
||||
fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
|
||||
fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
|
||||
println!(
|
||||
"
|
||||
Available lint options:
|
||||
@ -832,8 +831,8 @@ Available lint options:
|
||||
}
|
||||
|
||||
fn sort_lint_groups(
|
||||
lints: Vec<(&'static str, Vec<lint::LintId>, bool)>,
|
||||
) -> Vec<(&'static str, Vec<lint::LintId>)> {
|
||||
lints: Vec<(&'static str, Vec<LintId>, bool)>,
|
||||
) -> Vec<(&'static str, Vec<LintId>)> {
|
||||
let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
|
||||
lints.sort_by_key(|l| l.0);
|
||||
lints
|
||||
@ -892,7 +891,7 @@ Available lint options:
|
||||
println!(" {} {}", padded("----"), "---------");
|
||||
println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings");
|
||||
|
||||
let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
|
||||
let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
|
||||
for (name, to) in lints {
|
||||
let name = name.to_lowercase().replace("_", "-");
|
||||
let desc = to
|
||||
|
@ -12,6 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::OnDrop;
|
||||
use rustc_errors::registry::Registry;
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_parse::new_parser_from_source_str;
|
||||
use rustc_span::edition;
|
||||
use rustc_span::source_map::{FileLoader, FileName, SourceMap};
|
||||
@ -36,7 +37,7 @@ pub struct Compiler {
|
||||
pub(crate) output_dir: Option<PathBuf>,
|
||||
pub(crate) output_file: Option<PathBuf>,
|
||||
pub(crate) crate_name: Option<String>,
|
||||
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
|
||||
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
|
||||
pub(crate) override_queries:
|
||||
Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>,
|
||||
}
|
||||
@ -136,7 +137,7 @@ pub struct Config {
|
||||
///
|
||||
/// Note that if you find a Some here you probably want to call that function in the new
|
||||
/// function being registered.
|
||||
pub register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
|
||||
pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
|
||||
|
||||
/// This is a callback from the driver that is called just after we have populated
|
||||
/// the list of queries.
|
||||
|
@ -27,6 +27,7 @@ use rustc_errors::PResult;
|
||||
use rustc_expand::base::ExtCtxt;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_incremental;
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_mir as mir;
|
||||
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
|
||||
use rustc_passes::{self, hir_stats, layout_test};
|
||||
@ -100,7 +101,7 @@ declare_box_region_type!(
|
||||
/// Returns `None` if we're aborting after handling -W help.
|
||||
pub fn configure_and_expand(
|
||||
sess: Lrc<Session>,
|
||||
lint_store: Lrc<lint::LintStore>,
|
||||
lint_store: Lrc<LintStore>,
|
||||
metadata_loader: Box<MetadataLoaderDyn>,
|
||||
krate: ast::Crate,
|
||||
crate_name: &str,
|
||||
@ -150,10 +151,10 @@ impl BoxedResolver {
|
||||
pub fn register_plugins<'a>(
|
||||
sess: &'a Session,
|
||||
metadata_loader: &'a dyn MetadataLoader,
|
||||
register_lints: impl Fn(&Session, &mut lint::LintStore),
|
||||
register_lints: impl Fn(&Session, &mut LintStore),
|
||||
mut krate: ast::Crate,
|
||||
crate_name: &str,
|
||||
) -> Result<(ast::Crate, Lrc<lint::LintStore>)> {
|
||||
) -> Result<(ast::Crate, Lrc<LintStore>)> {
|
||||
krate = sess.time("attributes_injection", || {
|
||||
rustc_builtin_macros::cmdline_attrs::inject(
|
||||
krate,
|
||||
@ -214,7 +215,7 @@ pub fn register_plugins<'a>(
|
||||
|
||||
fn configure_and_expand_inner<'a>(
|
||||
sess: &'a Session,
|
||||
lint_store: &'a lint::LintStore,
|
||||
lint_store: &'a LintStore,
|
||||
mut krate: ast::Crate,
|
||||
crate_name: &str,
|
||||
resolver_arenas: &'a ResolverArenas<'a>,
|
||||
@ -420,7 +421,7 @@ fn configure_and_expand_inner<'a>(
|
||||
|
||||
pub fn lower_to_hir<'res, 'tcx>(
|
||||
sess: &'tcx Session,
|
||||
lint_store: &lint::LintStore,
|
||||
lint_store: &LintStore,
|
||||
resolver: &'res mut Resolver<'_>,
|
||||
dep_graph: &'res DepGraph,
|
||||
krate: &'res ast::Crate,
|
||||
@ -705,7 +706,7 @@ impl<'tcx> QueryContext<'tcx> {
|
||||
|
||||
pub fn create_global_ctxt<'tcx>(
|
||||
compiler: &'tcx Compiler,
|
||||
lint_store: Lrc<lint::LintStore>,
|
||||
lint_store: Lrc<LintStore>,
|
||||
hir_forest: &'tcx map::Forest<'tcx>,
|
||||
mut resolver_outputs: ResolverOutputs,
|
||||
outputs: OutputFilenames,
|
||||
|
@ -4,8 +4,6 @@ use crate::passes::{self, BoxedResolver, QueryContext};
|
||||
use rustc::arena::Arena;
|
||||
use rustc::dep_graph::DepGraph;
|
||||
use rustc::hir::map;
|
||||
use rustc::lint;
|
||||
use rustc::lint::LintStore;
|
||||
use rustc::session::config::{OutputFilenames, OutputType};
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::steal::Steal;
|
||||
@ -15,6 +13,7 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_incremental::DepGraphFuture;
|
||||
use rustc_lint::LintStore;
|
||||
use std::any::Any;
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::mem;
|
||||
@ -133,7 +132,7 @@ impl<'tcx> Queries<'tcx> {
|
||||
let crate_name = self.crate_name()?.peek().clone();
|
||||
let krate = self.parse()?.take();
|
||||
|
||||
let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {};
|
||||
let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
|
||||
let result = passes::register_plugins(
|
||||
self.session(),
|
||||
&*self.codegen_backend().metadata_loader(),
|
||||
|
@ -2,7 +2,7 @@ extern crate getopts;
|
||||
|
||||
use crate::interface::parse_cfgspecs;
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::lint::Level;
|
||||
use rustc::middle::cstore;
|
||||
use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
|
||||
use rustc::session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
|
||||
@ -186,24 +186,24 @@ fn test_lints_tracking_hash_different_values() {
|
||||
let mut v3 = Options::default();
|
||||
|
||||
v1.lint_opts = vec![
|
||||
(String::from("a"), lint::Allow),
|
||||
(String::from("b"), lint::Warn),
|
||||
(String::from("c"), lint::Deny),
|
||||
(String::from("d"), lint::Forbid),
|
||||
(String::from("a"), Level::Allow),
|
||||
(String::from("b"), Level::Warn),
|
||||
(String::from("c"), Level::Deny),
|
||||
(String::from("d"), Level::Forbid),
|
||||
];
|
||||
|
||||
v2.lint_opts = vec![
|
||||
(String::from("a"), lint::Allow),
|
||||
(String::from("b"), lint::Warn),
|
||||
(String::from("X"), lint::Deny),
|
||||
(String::from("d"), lint::Forbid),
|
||||
(String::from("a"), Level::Allow),
|
||||
(String::from("b"), Level::Warn),
|
||||
(String::from("X"), Level::Deny),
|
||||
(String::from("d"), Level::Forbid),
|
||||
];
|
||||
|
||||
v3.lint_opts = vec![
|
||||
(String::from("a"), lint::Allow),
|
||||
(String::from("b"), lint::Warn),
|
||||
(String::from("c"), lint::Forbid),
|
||||
(String::from("d"), lint::Deny),
|
||||
(String::from("a"), Level::Allow),
|
||||
(String::from("b"), Level::Warn),
|
||||
(String::from("c"), Level::Forbid),
|
||||
(String::from("d"), Level::Deny),
|
||||
];
|
||||
|
||||
assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
|
||||
@ -222,17 +222,17 @@ fn test_lints_tracking_hash_different_construction_order() {
|
||||
let mut v2 = Options::default();
|
||||
|
||||
v1.lint_opts = vec![
|
||||
(String::from("a"), lint::Allow),
|
||||
(String::from("b"), lint::Warn),
|
||||
(String::from("c"), lint::Deny),
|
||||
(String::from("d"), lint::Forbid),
|
||||
(String::from("a"), Level::Allow),
|
||||
(String::from("b"), Level::Warn),
|
||||
(String::from("c"), Level::Deny),
|
||||
(String::from("d"), Level::Forbid),
|
||||
];
|
||||
|
||||
v2.lint_opts = vec![
|
||||
(String::from("a"), lint::Allow),
|
||||
(String::from("c"), lint::Deny),
|
||||
(String::from("b"), lint::Warn),
|
||||
(String::from("d"), lint::Forbid),
|
||||
(String::from("a"), Level::Allow),
|
||||
(String::from("c"), Level::Deny),
|
||||
(String::from("b"), Level::Warn),
|
||||
(String::from("d"), Level::Forbid),
|
||||
];
|
||||
|
||||
assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
|
||||
|
@ -13,6 +13,7 @@ log = "0.4"
|
||||
unicode-security = "0.0.2"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
@ -1,8 +1,9 @@
|
||||
use rustc::lint::{FutureIncompatibleInfo, LateContext, LateLintPass, LintContext};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc::ty;
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_session::lint::FutureIncompatibleInfo;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_lint! {
|
||||
|
@ -21,8 +21,8 @@
|
||||
//! If you define a new `LateLintPass`, you will also need to add it to the
|
||||
//! `late_lint_methods!` invocation in `lib.rs`.
|
||||
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::{self, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc::traits::misc::can_type_implement_copy;
|
||||
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -51,7 +51,7 @@ use log::debug;
|
||||
use std::fmt::Write;
|
||||
|
||||
// hardwired lints from librustc
|
||||
pub use lint::builtin::*;
|
||||
pub use rustc_session::lint::builtin::*;
|
||||
|
||||
declare_lint! {
|
||||
WHILE_TRUE,
|
||||
|
@ -16,22 +16,23 @@
|
||||
|
||||
use self::TargetLint::*;
|
||||
|
||||
use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
|
||||
use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
|
||||
use crate::lint::{EarlyLintPassObject, LateLintPassObject};
|
||||
use crate::middle::privacy::AccessLevels;
|
||||
use crate::middle::stability;
|
||||
use crate::session::Session;
|
||||
use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
|
||||
use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
|
||||
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::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_error_codes::*;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
|
||||
use syntax::ast;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
@ -467,48 +468,6 @@ impl LintPassObject for EarlyLintPassObject {}
|
||||
|
||||
impl LintPassObject for LateLintPassObject {}
|
||||
|
||||
pub fn add_elided_lifetime_in_path_suggestion(
|
||||
sess: &Session,
|
||||
db: &mut DiagnosticBuilder<'_>,
|
||||
n: usize,
|
||||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
anon_lts: String,
|
||||
) {
|
||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||
(insertion_span, anon_lts)
|
||||
} else {
|
||||
// When possible, prefer a suggestion that replaces the whole
|
||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||
// at a point (which makes for an ugly/confusing label)
|
||||
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
||||
// But our spans can get out of whack due to macros; if the place we think
|
||||
// we want to insert `'_` isn't even within the path expression's span, we
|
||||
// should bail out of making any suggestion rather than panicking on a
|
||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||
// FIXME: can we do better?
|
||||
if insertion_span.lo().0 < path_span.lo().0 {
|
||||
return;
|
||||
}
|
||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||
if insertion_index > snippet.len() {
|
||||
return;
|
||||
}
|
||||
let (before, after) = snippet.split_at(insertion_index);
|
||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||
} else {
|
||||
(insertion_span, anon_lts)
|
||||
}
|
||||
};
|
||||
db.span_suggestion(
|
||||
replace_span,
|
||||
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
pub trait LintContext: Sized {
|
||||
type PassObject: LintPassObject;
|
||||
|
||||
@ -674,7 +633,7 @@ impl<'a> EarlyContext<'a> {
|
||||
sess,
|
||||
krate,
|
||||
lint_store,
|
||||
builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store),
|
||||
builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store),
|
||||
buffered,
|
||||
}
|
||||
}
|
@ -14,10 +14,9 @@
|
||||
//! upon. As the ast is traversed, this keeps track of the current lint level
|
||||
//! for all lint attributes.
|
||||
|
||||
use rustc::lint::{EarlyContext, LintStore};
|
||||
use rustc::lint::{EarlyLintPass, EarlyLintPassObject};
|
||||
use rustc::lint::{LintContext, LintPass};
|
||||
use rustc_session::lint::LintBuffer;
|
||||
use crate::context::{EarlyContext, LintContext, LintStore};
|
||||
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
|
||||
use rustc_session::lint::{LintBuffer, LintPass};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Span;
|
||||
use syntax::ast;
|
||||
@ -291,7 +290,7 @@ macro_rules! early_lint_pass_impl {
|
||||
)
|
||||
}
|
||||
|
||||
early_lint_methods!(early_lint_pass_impl, []);
|
||||
crate::early_lint_methods!(early_lint_pass_impl, []);
|
||||
|
||||
fn early_lint_crate<T: EarlyLintPass>(
|
||||
sess: &Session,
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
|
||||
//! Clippy.
|
||||
|
||||
use crate::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
|
@ -14,9 +14,8 @@
|
||||
//! upon. As the ast is traversed, this keeps track of the current lint level
|
||||
//! for all lint attributes.
|
||||
|
||||
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::LateContext;
|
||||
use rustc::lint::{LateLintPass, LateLintPassObject};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
|
||||
use rustc_hir as hir;
|
||||
@ -29,8 +28,16 @@ use syntax::ast;
|
||||
use syntax::walk_list;
|
||||
|
||||
use log::debug;
|
||||
use std::any::Any;
|
||||
use std::slice;
|
||||
|
||||
/// Extract the `LintStore` from the query context.
|
||||
/// This function exists because we've erased `LintStore` as `dyn Any` in the context.
|
||||
crate fn unerased_lint_store<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx LintStore {
|
||||
let store: &dyn Any = &*tcx.lint_store;
|
||||
store.downcast_ref().unwrap()
|
||||
}
|
||||
|
||||
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
||||
$cx.pass.$f(&$cx.context, $($args),*);
|
||||
}) }
|
||||
@ -342,7 +349,7 @@ macro_rules! late_lint_pass_impl {
|
||||
)
|
||||
}
|
||||
|
||||
late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
|
||||
crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
|
||||
|
||||
fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -356,7 +363,7 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||
tables: &ty::TypeckTables::empty(None),
|
||||
param_env: ty::ParamEnv::empty(),
|
||||
access_levels,
|
||||
lint_store: &tcx.lint_store,
|
||||
lint_store: unerased_lint_store(tcx),
|
||||
last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
|
||||
generics: None,
|
||||
only_module: true,
|
||||
@ -386,7 +393,7 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||
late_lint_mod_pass(tcx, module_def_id, builtin_lints);
|
||||
|
||||
let mut passes: Vec<_> =
|
||||
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
|
||||
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
|
||||
|
||||
if !passes.is_empty() {
|
||||
late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
|
||||
@ -403,7 +410,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
|
||||
tables: &ty::TypeckTables::empty(None),
|
||||
param_env: ty::ParamEnv::empty(),
|
||||
access_levels,
|
||||
lint_store: &tcx.lint_store,
|
||||
lint_store: unerased_lint_store(tcx),
|
||||
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
|
||||
generics: None,
|
||||
only_module: false,
|
||||
@ -424,7 +431,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
|
||||
}
|
||||
|
||||
fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
|
||||
let mut passes = tcx.lint_store.late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
|
||||
let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
|
||||
|
||||
if !tcx.sess.opts.debugging_opts.no_interleave_lints {
|
||||
if !passes.is_empty() {
|
||||
@ -443,7 +450,7 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b
|
||||
}
|
||||
|
||||
let mut passes: Vec<_> =
|
||||
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
|
||||
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
|
||||
|
||||
for pass in &mut passes {
|
||||
tcx.sess
|
||||
|
@ -1,22 +1,33 @@
|
||||
use crate::context::{CheckLintNameResult, LintStore};
|
||||
use crate::late::unerased_lint_store;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::{LintLevelMap, LintLevelSets, LintLevelsBuilder, LintStore};
|
||||
use rustc::lint::struct_lint_level;
|
||||
use rustc::lint::{LintLevelMap, LintLevelSets, LintSet, LintSource};
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_error_codes::*;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_hir::hir_id::HirId;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_session::lint::{builtin, Level, Lint};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{sym, MultiSpan, Symbol};
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::print::pprust;
|
||||
use syntax::sess::feature_err;
|
||||
use syntax::unwrap_or;
|
||||
|
||||
pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId};
|
||||
use std::cmp;
|
||||
|
||||
fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
let store = &tcx.lint_store;
|
||||
let mut builder = LintLevelMapBuilder {
|
||||
levels: LintLevelSets::builder(tcx.sess, false, &store),
|
||||
tcx: tcx,
|
||||
store: store,
|
||||
};
|
||||
let store = unerased_lint_store(tcx);
|
||||
let levels = LintLevelsBuilder::new(tcx.sess, false, &store);
|
||||
let mut builder = LintLevelMapBuilder { levels, tcx, store };
|
||||
let krate = tcx.hir().krate();
|
||||
|
||||
let push = builder.levels.push(&krate.attrs, &store);
|
||||
@ -30,6 +41,378 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
||||
tcx.arena.alloc(builder.levels.build_map())
|
||||
}
|
||||
|
||||
pub struct LintLevelsBuilder<'a> {
|
||||
sess: &'a Session,
|
||||
sets: LintLevelSets,
|
||||
id_to_set: FxHashMap<HirId, u32>,
|
||||
cur: u32,
|
||||
warn_about_weird_lints: bool,
|
||||
}
|
||||
|
||||
pub struct BuilderPush {
|
||||
prev: u32,
|
||||
pub changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> LintLevelsBuilder<'a> {
|
||||
pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self {
|
||||
let mut builder = LintLevelsBuilder {
|
||||
sess,
|
||||
sets: LintLevelSets::new(),
|
||||
cur: 0,
|
||||
id_to_set: Default::default(),
|
||||
warn_about_weird_lints,
|
||||
};
|
||||
builder.process_command_line(sess, store);
|
||||
assert_eq!(builder.sets.list.len(), 1);
|
||||
builder
|
||||
}
|
||||
|
||||
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
|
||||
let mut specs = FxHashMap::default();
|
||||
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
|
||||
|
||||
for &(ref lint_name, level) in &sess.opts.lint_opts {
|
||||
store.check_lint_name_cmdline(sess, &lint_name, level);
|
||||
|
||||
// If the cap is less than this specified level, e.g., if we've got
|
||||
// `--cap-lints allow` but we've also got `-D foo` then we ignore
|
||||
// this specification as the lint cap will set it to allow anyway.
|
||||
let level = cmp::min(level, self.sets.lint_cap);
|
||||
|
||||
let lint_flag_val = Symbol::intern(lint_name);
|
||||
let ids = match store.find_lints(&lint_name) {
|
||||
Ok(ids) => ids,
|
||||
Err(_) => continue, // errors handled in check_lint_name_cmdline above
|
||||
};
|
||||
for id in ids {
|
||||
let src = LintSource::CommandLine(lint_flag_val);
|
||||
specs.insert(id, (level, src));
|
||||
}
|
||||
}
|
||||
|
||||
self.sets.list.push(LintSet::CommandLine { specs });
|
||||
}
|
||||
|
||||
/// Pushes a list of AST lint attributes onto this context.
|
||||
///
|
||||
/// This function will return a `BuilderPush` object which should be passed
|
||||
/// to `pop` when this scope for the attributes provided is exited.
|
||||
///
|
||||
/// This function will perform a number of tasks:
|
||||
///
|
||||
/// * It'll validate all lint-related attributes in `attrs`
|
||||
/// * It'll mark all lint-related attributes as used
|
||||
/// * Lint levels will be updated based on the attributes provided
|
||||
/// * Lint attributes are validated, e.g., a #[forbid] can't be switched to
|
||||
/// #[allow]
|
||||
///
|
||||
/// Don't forget to call `pop`!
|
||||
pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
|
||||
let mut specs = FxHashMap::default();
|
||||
let sess = self.sess;
|
||||
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
|
||||
for attr in attrs {
|
||||
let level = match Level::from_symbol(attr.name_or_empty()) {
|
||||
None => continue,
|
||||
Some(lvl) => lvl,
|
||||
};
|
||||
|
||||
let meta = unwrap_or!(attr.meta(), continue);
|
||||
attr::mark_used(attr);
|
||||
|
||||
let mut metas = unwrap_or!(meta.meta_item_list(), continue);
|
||||
|
||||
if metas.is_empty() {
|
||||
// FIXME (#55112): issue unused-attributes lint for `#[level()]`
|
||||
continue;
|
||||
}
|
||||
|
||||
// Before processing the lint names, look for a reason (RFC 2383)
|
||||
// at the end.
|
||||
let mut reason = None;
|
||||
let tail_li = &metas[metas.len() - 1];
|
||||
if let Some(item) = tail_li.meta_item() {
|
||||
match item.kind {
|
||||
ast::MetaItemKind::Word => {} // actual lint names handled later
|
||||
ast::MetaItemKind::NameValue(ref name_value) => {
|
||||
if item.path == sym::reason {
|
||||
// found reason, reslice meta list to exclude it
|
||||
metas = &metas[0..metas.len() - 1];
|
||||
// FIXME (#55112): issue unused-attributes lint if we thereby
|
||||
// don't have any lint names (`#[level(reason = "foo")]`)
|
||||
if let ast::LitKind::Str(rationale, _) = name_value.kind {
|
||||
if !self.sess.features_untracked().lint_reasons {
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::lint_reasons,
|
||||
item.span,
|
||||
"lint reasons are experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
reason = Some(rationale);
|
||||
} else {
|
||||
bad_attr(name_value.span)
|
||||
.span_label(name_value.span, "reason must be a string literal")
|
||||
.emit();
|
||||
}
|
||||
} else {
|
||||
bad_attr(item.span)
|
||||
.span_label(item.span, "bad attribute argument")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
ast::MetaItemKind::List(_) => {
|
||||
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for li in metas {
|
||||
let meta_item = match li.meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => meta_item,
|
||||
_ => {
|
||||
let sp = li.span();
|
||||
let mut err = bad_attr(sp);
|
||||
let mut add_label = true;
|
||||
if let Some(item) = li.meta_item() {
|
||||
if let ast::MetaItemKind::NameValue(_) = item.kind {
|
||||
if item.path == sym::reason {
|
||||
err.span_label(sp, "reason in lint attribute must come last");
|
||||
add_label = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if add_label {
|
||||
err.span_label(sp, "bad attribute argument");
|
||||
}
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let tool_name = if meta_item.path.segments.len() > 1 {
|
||||
let tool_ident = meta_item.path.segments[0].ident;
|
||||
if !attr::is_known_lint_tool(tool_ident) {
|
||||
struct_span_err!(
|
||||
sess,
|
||||
tool_ident.span,
|
||||
E0710,
|
||||
"an unknown tool name found in scoped lint: `{}`",
|
||||
pprust::path_to_string(&meta_item.path),
|
||||
)
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
|
||||
Some(tool_ident.name)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
|
||||
match store.check_lint_name(&name.as_str(), tool_name) {
|
||||
CheckLintNameResult::Ok(ids) => {
|
||||
let src = LintSource::Node(name, li.span(), reason);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
|
||||
CheckLintNameResult::Tool(result) => {
|
||||
match result {
|
||||
Ok(ids) => {
|
||||
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(complete_name),
|
||||
li.span(),
|
||||
reason,
|
||||
);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
Err((Some(ids), new_lint_name)) => {
|
||||
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,
|
||||
)
|
||||
.span_suggestion(
|
||||
li.span(),
|
||||
"change it to",
|
||||
new_lint_name.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(&new_lint_name),
|
||||
li.span(),
|
||||
reason,
|
||||
);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
Err((None, _)) => {
|
||||
// If Tool(Err(None, _)) is returned, then either the lint does not
|
||||
// exist in the tool or the code was not compiled with the tool and
|
||||
// therefore the lint was never added to the `LintStore`. To detect
|
||||
// this is the responsibility of the lint tool.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ if !self.warn_about_weird_lints => {}
|
||||
|
||||
CheckLintNameResult::Warning(msg, renamed) => {
|
||||
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(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
if let Some(new_name) = renamed {
|
||||
err.span_suggestion(
|
||||
li.span(),
|
||||
"use the new name",
|
||||
new_name,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
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(
|
||||
self.sess,
|
||||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
|
||||
if let Some(suggestion) = suggestion {
|
||||
db.span_suggestion(
|
||||
li.span(),
|
||||
"did you mean",
|
||||
suggestion.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
db.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (id, &(level, ref src)) in specs.iter() {
|
||||
if level == Level::Forbid {
|
||||
continue;
|
||||
}
|
||||
let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
|
||||
(Some(Level::Forbid), src) => src,
|
||||
_ => continue,
|
||||
};
|
||||
let forbidden_lint_name = match forbid_src {
|
||||
LintSource::Default => id.to_string(),
|
||||
LintSource::Node(name, _, _) => name.to_string(),
|
||||
LintSource::CommandLine(name) => name.to_string(),
|
||||
};
|
||||
let (lint_attr_name, lint_attr_span) = match *src {
|
||||
LintSource::Node(name, span, _) => (name, span),
|
||||
_ => continue,
|
||||
};
|
||||
let mut diag_builder = struct_span_err!(
|
||||
self.sess,
|
||||
lint_attr_span,
|
||||
E0453,
|
||||
"{}({}) overruled by outer forbid({})",
|
||||
level.as_str(),
|
||||
lint_attr_name,
|
||||
forbidden_lint_name
|
||||
);
|
||||
diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
|
||||
match forbid_src {
|
||||
LintSource::Default => {}
|
||||
LintSource::Node(_, forbid_source_span, reason) => {
|
||||
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
|
||||
if let Some(rationale) = reason {
|
||||
diag_builder.note(&rationale.as_str());
|
||||
}
|
||||
}
|
||||
LintSource::CommandLine(_) => {
|
||||
diag_builder.note("`forbid` lint level was set on command line");
|
||||
}
|
||||
}
|
||||
diag_builder.emit();
|
||||
// don't set a separate error for every lint in the group
|
||||
break;
|
||||
}
|
||||
|
||||
let prev = self.cur;
|
||||
if specs.len() > 0 {
|
||||
self.cur = self.sets.list.len() as u32;
|
||||
self.sets.list.push(LintSet::Node { specs: specs, parent: prev });
|
||||
}
|
||||
|
||||
BuilderPush { prev: prev, changed: prev != self.cur }
|
||||
}
|
||||
|
||||
/// Called after `push` when the scope of a set of attributes are exited.
|
||||
pub fn pop(&mut self, push: BuilderPush) {
|
||||
self.cur = push.prev;
|
||||
}
|
||||
|
||||
/// Used to emit a lint-related diagnostic based on the current state of
|
||||
/// this lint context.
|
||||
pub fn struct_lint(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<MultiSpan>,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'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)
|
||||
}
|
||||
|
||||
/// Registers the ID provided with the current set of lints stored in
|
||||
/// this context.
|
||||
pub fn register_id(&mut self, id: HirId) {
|
||||
self.id_to_set.insert(id, self.cur);
|
||||
}
|
||||
|
||||
pub fn build(self) -> LintLevelSets {
|
||||
self.sets
|
||||
}
|
||||
|
||||
pub fn build_map(self) -> LintLevelMap {
|
||||
LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
|
||||
}
|
||||
}
|
||||
|
||||
struct LintLevelMapBuilder<'a, 'tcx> {
|
||||
levels: LintLevelsBuilder<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -1,9 +1,25 @@
|
||||
//! # Lints in the Rust compiler
|
||||
//! Lints, aka compiler warnings.
|
||||
//!
|
||||
//! This currently only contains the definitions and implementations
|
||||
//! of most of the lints that `rustc` supports directly, it does not
|
||||
//! contain the infrastructure for defining/registering lints. That is
|
||||
//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
|
||||
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
|
||||
//! want to enforce, but might reasonably want to permit as well, on a
|
||||
//! module-by-module basis. They contrast with static constraints enforced by
|
||||
//! other phases of the compiler, which are generally required to hold in order
|
||||
//! to compile the program at all.
|
||||
//!
|
||||
//! Most lints can be written as `LintPass` instances. These run after
|
||||
//! all other analyses. The `LintPass`es built into rustc are defined
|
||||
//! within `rustc_session::lint::builtin`,
|
||||
//! which has further comments on how to add such a lint.
|
||||
//! rustc can also load user-defined lint plugins via the plugin mechanism.
|
||||
//!
|
||||
//! Some of rustc's lints are defined elsewhere in the compiler and work by
|
||||
//! calling `add_lint()` on the overall `Session` object. This works when
|
||||
//! it happens before the main lint pass, which emits the lints stored by
|
||||
//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
|
||||
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
||||
//! in `context.rs`.
|
||||
//!
|
||||
//! Some code also exists in `rustc_session::lint`, `rustc::lint`.
|
||||
//!
|
||||
//! ## Note
|
||||
//!
|
||||
@ -14,6 +30,8 @@
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
@ -24,45 +42,47 @@ extern crate rustc_session;
|
||||
|
||||
mod array_into_iter;
|
||||
pub mod builtin;
|
||||
mod context;
|
||||
mod early;
|
||||
mod internal;
|
||||
mod late;
|
||||
mod levels;
|
||||
mod non_ascii_idents;
|
||||
mod nonstandard_style;
|
||||
mod passes;
|
||||
mod redundant_semicolon;
|
||||
mod types;
|
||||
mod unused;
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::lint::builtin::{
|
||||
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
|
||||
};
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint::{LintArray, LintPass};
|
||||
|
||||
use rustc_session::lint::builtin::{
|
||||
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||
INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use syntax::ast;
|
||||
|
||||
use lint::LintId;
|
||||
|
||||
use array_into_iter::ArrayIntoIter;
|
||||
use builtin::*;
|
||||
use internal::*;
|
||||
use non_ascii_idents::*;
|
||||
use nonstandard_style::*;
|
||||
use redundant_semicolon::*;
|
||||
use rustc::lint::internal::*;
|
||||
use types::*;
|
||||
use unused::*;
|
||||
|
||||
/// Useful for other parts of the compiler.
|
||||
/// Useful for other parts of the compiler / Clippy.
|
||||
pub use builtin::SoftLints;
|
||||
pub use context::{EarlyContext, LateContext, LintContext, LintStore};
|
||||
pub use early::check_ast_crate;
|
||||
pub use late::check_crate;
|
||||
pub use passes::{EarlyLintPass, LateLintPass};
|
||||
pub use rustc_session::lint::Level::{self, *};
|
||||
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
|
||||
pub use rustc_session::lint::{LintArray, LintPass};
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
levels::provide(providers);
|
||||
@ -179,8 +199,8 @@ late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass])
|
||||
|
||||
late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
|
||||
|
||||
pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore {
|
||||
let mut lint_store = lint::LintStore::new();
|
||||
pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintStore {
|
||||
let mut lint_store = LintStore::new();
|
||||
|
||||
register_builtins(&mut lint_store, no_interleave_lints);
|
||||
if internal_lints {
|
||||
@ -193,7 +213,7 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::
|
||||
/// Tell the `LintStore` about all the built-in lints (the ones
|
||||
/// defined in this crate and the ones defined in
|
||||
/// `rustc::lint::builtin`).
|
||||
fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
|
||||
fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
|
||||
macro_rules! add_lint_group {
|
||||
($name:expr, $($lint:ident),*) => (
|
||||
store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
|
||||
@ -390,7 +410,7 @@ fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
|
||||
store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
|
||||
}
|
||||
|
||||
fn register_internals(store: &mut lint::LintStore) {
|
||||
fn register_internals(store: &mut LintStore) {
|
||||
store.register_lints(&DefaultHashTypes::get_lints());
|
||||
store.register_early_pass(|| box DefaultHashTypes::new());
|
||||
store.register_lints(&LintPassImpl::get_lints());
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use syntax::ast;
|
||||
|
||||
declare_lint! {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc::ty;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
@ -1,47 +1,12 @@
|
||||
//! Lints, aka compiler warnings.
|
||||
//!
|
||||
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
|
||||
//! want to enforce, but might reasonably want to permit as well, on a
|
||||
//! module-by-module basis. They contrast with static constraints enforced by
|
||||
//! other phases of the compiler, which are generally required to hold in order
|
||||
//! to compile the program at all.
|
||||
//!
|
||||
//! Most lints can be written as `LintPass` instances. These run after
|
||||
//! all other analyses. The `LintPass`es built into rustc are defined
|
||||
//! within `builtin.rs`, which has further comments on how to add such a lint.
|
||||
//! rustc can also load user-defined lint plugins via the plugin mechanism.
|
||||
//!
|
||||
//! Some of rustc's lints are defined elsewhere in the compiler and work by
|
||||
//! calling `add_lint()` on the overall `Session` object. This works when
|
||||
//! it happens before the main lint pass, which emits the lints stored by
|
||||
//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
|
||||
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
||||
//! in `context.rs`.
|
||||
use crate::context::{EarlyContext, LateContext};
|
||||
|
||||
pub use self::Level::*;
|
||||
pub use self::LintSource::*;
|
||||
|
||||
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::symbol::Symbol;
|
||||
use rustc_session::lint::LintPass;
|
||||
use rustc_span::Span;
|
||||
use syntax::ast;
|
||||
|
||||
pub use crate::lint::context::{
|
||||
add_elided_lifetime_in_path_suggestion, CheckLintNameResult, EarlyContext, LateContext,
|
||||
LintContext, LintStore,
|
||||
};
|
||||
|
||||
pub use rustc_session::lint::builtin;
|
||||
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Level, Lint, LintId};
|
||||
pub use rustc_session::lint::{LintArray, LintPass};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! late_lint_methods {
|
||||
($macro:path, $args:tt, [$hir:tt]) => (
|
||||
@ -176,6 +141,7 @@ macro_rules! declare_combined_late_lint_pass {
|
||||
expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
|
||||
}
|
||||
|
||||
#[allow(rustc::lint_pass_impl_without_macro)]
|
||||
impl LintPass for $name {
|
||||
fn name(&self) -> &'static str {
|
||||
panic!()
|
||||
@ -303,6 +269,7 @@ macro_rules! declare_combined_early_lint_pass {
|
||||
expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
|
||||
}
|
||||
|
||||
#[allow(rustc::lint_pass_impl_without_macro)]
|
||||
impl LintPass for $name {
|
||||
fn name(&self) -> &'static str {
|
||||
panic!()
|
||||
@ -315,190 +282,3 @@ macro_rules! declare_combined_early_lint_pass {
|
||||
pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
|
||||
pub type LateLintPassObject =
|
||||
Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>;
|
||||
|
||||
/// How a lint level was set.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
|
||||
pub enum LintSource {
|
||||
/// Lint is at the default level as declared
|
||||
/// in rustc or a plugin.
|
||||
Default,
|
||||
|
||||
/// Lint level was set by an attribute.
|
||||
Node(ast::Name, Span, Option<Symbol> /* RFC 2383 reason */),
|
||||
|
||||
/// Lint level was set by a command-line flag.
|
||||
CommandLine(Symbol),
|
||||
}
|
||||
|
||||
pub type LevelSource = (Level, LintSource);
|
||||
|
||||
mod context;
|
||||
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 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
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
||||
pub fn in_derive_expansion(span: Span) -> bool {
|
||||
if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_data().kind {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_errors::Applicability;
|
||||
use syntax::ast::{ExprKind, Stmt, StmtKind};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use rustc::lint::{LateContext, LateLintPass, LintContext};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc::mir::interpret::{sign_extend, truncate};
|
||||
use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx};
|
||||
use rustc::ty::subst::SubstsRef;
|
||||
|
@ -1,5 +1,4 @@
|
||||
use rustc::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc::ty::adjustment;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -8,6 +7,7 @@ use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
@ -637,17 +637,17 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
|
||||
tcx.unsafe_derive_on_repr_packed(impl_def_id);
|
||||
} else {
|
||||
tcx.lint_node_note(
|
||||
tcx.struct_span_lint_hir(
|
||||
SAFE_PACKED_BORROWS,
|
||||
lint_hir_id,
|
||||
source_info.span,
|
||||
&format!(
|
||||
"{} is unsafe and requires unsafe function or block \
|
||||
(error E0133)",
|
||||
"{} is unsafe and requires unsafe function or block (error E0133)",
|
||||
description
|
||||
),
|
||||
&details.as_str(),
|
||||
);
|
||||
)
|
||||
.note(&details.as_str())
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
// from live codes are live, and everything else is dead.
|
||||
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint;
|
||||
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc::middle::privacy;
|
||||
use rustc::ty::{self, DefIdTree, TyCtxt};
|
||||
@ -14,6 +13,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{Node, PatKind, TyKind};
|
||||
use rustc_session::lint;
|
||||
|
||||
use rustc_span;
|
||||
use rustc_span::symbol::sym;
|
||||
|
@ -1513,13 +1513,16 @@ 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.lint_hir_note(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans,
|
||||
&format!("variable `{}` is assigned to, but never used", name),
|
||||
&format!("consider using `_{}` instead", name),
|
||||
);
|
||||
self.ir
|
||||
.tcx
|
||||
.struct_span_lint_hir(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
hir_id,
|
||||
spans,
|
||||
&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(
|
||||
lint::builtin::UNUSED_VARIABLES,
|
||||
|
@ -14,6 +14,7 @@ doctest = false
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
rustc_lint = { path = "../librustc_lint" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
|
@ -9,7 +9,7 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![feature(nll)]
|
||||
|
||||
use rustc::lint::LintStore;
|
||||
use rustc_lint::LintStore;
|
||||
|
||||
pub mod build;
|
||||
pub mod load;
|
||||
|
@ -308,6 +308,11 @@ impl Span {
|
||||
self.ctxt() != SyntaxContext::root()
|
||||
}
|
||||
|
||||
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
||||
pub fn in_derive_expansion(self) -> bool {
|
||||
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
|
||||
Span::new(lo, hi, SyntaxContext::root())
|
||||
|
@ -1,4 +1,3 @@
|
||||
use rustc::lint;
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
use rustc::session::config::ErrorOutputType;
|
||||
@ -14,6 +13,7 @@ use rustc_hir::HirId;
|
||||
use rustc_interface::interface;
|
||||
use rustc_lint;
|
||||
use rustc_resolve as resolve;
|
||||
use rustc_session::lint;
|
||||
|
||||
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
|
@ -35,6 +35,7 @@ extern crate rustc_metadata;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_parse;
|
||||
extern crate rustc_resolve;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span as rustc_span;
|
||||
extern crate rustc_target;
|
||||
extern crate rustc_typeck;
|
||||
|
@ -1,17 +1,17 @@
|
||||
#![feature(box_syntax, plugin, plugin_registrar, rustc_private)]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Node;
|
||||
use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
|
||||
use rustc_lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_span::source_map;
|
||||
use syntax::print::pprust;
|
||||
|
@ -2,14 +2,14 @@
|
||||
|
||||
#![feature(plugin_registrar, rustc_private)]
|
||||
#![feature(box_syntax)]
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_span;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass};
|
||||
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use syntax::attr;
|
||||
|
@ -3,14 +3,14 @@
|
||||
#![feature(plugin_registrar, rustc_private)]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
#[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_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use syntax::attr;
|
||||
|
@ -4,12 +4,12 @@
|
||||
#![feature(box_syntax, rustc_private)]
|
||||
|
||||
// Load rustc as a plugin to get macros.
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_hir;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
|
||||
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
|
||||
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
|
||||
use rustc_driver::plugin::Registry;
|
||||
|
||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||
|
@ -6,11 +6,11 @@
|
||||
extern crate syntax;
|
||||
|
||||
// Load rustc as a plugin to get macros
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_driver;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
|
||||
use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
|
||||
use rustc_lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use syntax::ast;
|
||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||
|
@ -4,11 +4,11 @@
|
||||
extern crate syntax;
|
||||
|
||||
// Load rustc as a plugin to get macros
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
extern crate rustc_driver;
|
||||
#[macro_use] extern crate rustc_lint;
|
||||
#[macro_use] extern crate rustc_session;
|
||||
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
|
||||
use rustc_driver::plugin::Registry;
|
||||
use syntax::ast;
|
||||
declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
|
||||
|
Loading…
x
Reference in New Issue
Block a user