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:
Mazdak Farrokhzad 2020-01-12 03:27:59 +01:00 committed by GitHub
commit cc51d0350e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 974 additions and 1017 deletions

View File

@ -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",

View File

@ -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;

View File

@ -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
View 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,
);
}

View File

@ -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);
}
}
}
})
}
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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" }
}

View File

@ -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

View File

@ -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(

View File

@ -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>> {

View File

@ -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};

View File

@ -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;

View File

@ -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" }

View File

@ -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

View File

@ -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.

View File

@ -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,

View File

@ -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(),

View File

@ -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());

View File

@ -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" }

View File

@ -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! {

View File

@ -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,

View File

@ -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,
}
}

View File

@ -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,

View File

@ -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};

View File

@ -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

View File

@ -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>,

View File

@ -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());

View File

@ -1,4 +1,4 @@
use rustc::lint::{EarlyContext, EarlyLintPass, LintContext};
use crate::{EarlyContext, EarlyLintPass, LintContext};
use syntax::ast;
declare_lint! {

View File

@ -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;

View File

@ -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
}

View File

@ -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};

View File

@ -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;

View File

@ -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};

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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" }

View File

@ -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;

View File

@ -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())

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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'");

View File

@ -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'");

View File

@ -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");