move rustc::lint::{context, passes} to rustc_lint.
Also do some cleanup of the interface.
This commit is contained in:
parent
8c12c424e2
commit
f58db20362
24 changed files with 505 additions and 513 deletions
|
@ -3789,6 +3789,7 @@ dependencies = [
|
|||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_lint",
|
||||
"rustc_metadata",
|
||||
"rustc_span",
|
||||
"syntax",
|
||||
|
|
|
@ -72,8 +72,6 @@ extern crate rustc_data_structures;
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate syntax;
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,30 +1,15 @@
|
|||
use std::cmp;
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::lint::context::CheckLintNameResult;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
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::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::print::pprust;
|
||||
use syntax::sess::feature_err;
|
||||
|
||||
use rustc_error_codes::*;
|
||||
|
||||
mod context;
|
||||
mod passes;
|
||||
|
||||
pub use context::add_elided_lifetime_in_path_suggestion;
|
||||
pub use context::{EarlyContext, LateContext, LintContext, LintStore};
|
||||
pub use passes::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
/// How a lint level was set.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
|
||||
|
@ -43,11 +28,11 @@ pub enum LintSource {
|
|||
pub type LevelSource = (Level, LintSource);
|
||||
|
||||
pub struct LintLevelSets {
|
||||
list: Vec<LintSet>,
|
||||
lint_cap: Level,
|
||||
pub list: Vec<LintSet>,
|
||||
pub lint_cap: Level,
|
||||
}
|
||||
|
||||
enum LintSet {
|
||||
pub enum LintSet {
|
||||
CommandLine {
|
||||
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
|
||||
// flag.
|
||||
|
@ -133,381 +118,9 @@ impl LintLevelSets {
|
|||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LintLevelMap {
|
||||
sets: LintLevelSets,
|
||||
id_to_set: FxHashMap<HirId, u32>,
|
||||
pub sets: LintLevelSets,
|
||||
pub id_to_set: FxHashMap<HirId, u32>,
|
||||
}
|
||||
|
||||
impl LintLevelMap {
|
||||
|
@ -712,3 +325,45 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
|||
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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustc::lint::{LateContext, LateLintPass, LintContext};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc::ty;
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment};
|
||||
use rustc_errors::Applicability;
|
||||
|
|
|
@ -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,17 +16,18 @@
|
|||
|
||||
use self::TargetLint::*;
|
||||
|
||||
use crate::hir::map::definitions::{DefPathData, DisambiguatedDefPathData};
|
||||
use crate::lint::passes::{EarlyLintPassObject, LateLintPassObject};
|
||||
use crate::lint::LintLevelsBuilder;
|
||||
use crate::middle::privacy::AccessLevels;
|
||||
use crate::middle::stability;
|
||||
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;
|
||||
|
@ -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;
|
||||
|
|
@ -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,8 +1,7 @@
|
|||
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
|
||||
//! Clippy.
|
||||
|
||||
use crate::lint::{EarlyContext, LateContext, LintContext};
|
||||
use crate::lint::{EarlyLintPass, LateLintPass};
|
||||
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,8 +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, LateLintPass, LateLintPassObject, LintStore};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
|
||||
use rustc_hir as hir;
|
||||
|
@ -347,7 +347,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>,
|
||||
|
|
|
@ -1,14 +1,27 @@
|
|||
use super::late::unerased_lint_store;
|
||||
use crate::context::{CheckLintNameResult, LintStore};
|
||||
use crate::late::unerased_lint_store;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint::{LintLevelMap, 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);
|
||||
|
@ -28,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>,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
@ -25,33 +26,29 @@ 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::*;
|
||||
|
@ -61,10 +58,15 @@ use redundant_semicolon::*;
|
|||
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);
|
||||
|
@ -181,8 +183,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 {
|
||||
|
@ -195,7 +197,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)),*]);
|
||||
|
@ -392,7 +394,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;
|
||||
|
|
|
@ -18,23 +18,15 @@
|
|||
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
||||
//! in `context.rs`.
|
||||
|
||||
pub use self::Level::*;
|
||||
pub use crate::lint::LintSource::{self, *};
|
||||
use crate::context::{EarlyContext, LateContext};
|
||||
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_hir as hir;
|
||||
use rustc_session::lint::builtin::HardwiredLints;
|
||||
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, LintArray, LintPass};
|
||||
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Level, Lint, LintId};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! late_lint_methods {
|
||||
($macro:path, $args:tt, [$hir:tt]) => (
|
||||
|
@ -169,6 +161,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!()
|
||||
|
@ -296,6 +289,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!()
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue