2015-02-19 10:04:56 -08:00
|
|
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
2014-06-06 15:49:48 -07:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Implementation of lint checking.
|
|
|
|
//!
|
|
|
|
//! The lint checking is mostly consolidated into one pass which runs just
|
|
|
|
//! before translation to LLVM bytecode. Throughout compilation, lint warnings
|
|
|
|
//! can be added via the `add_lint` method on the Session structure. This
|
|
|
|
//! requires a span and an id of the node that the lint is being added to. The
|
|
|
|
//! lint isn't actually emitted at that time because it is unknown what the
|
|
|
|
//! actual lint level at that location is.
|
|
|
|
//!
|
|
|
|
//! To actually emit lint warnings/errors, a separate pass is used just before
|
|
|
|
//! translation. A context keeps track of the current state of all lint levels.
|
|
|
|
//! Upon entering a node of the ast which can modify the lint settings, the
|
|
|
|
//! previous lint state is pushed onto a stack and the ast is then recursed
|
|
|
|
//! upon. As the ast is traversed, this keeps track of the current lint level
|
|
|
|
//! for all lint attributes.
|
2014-11-06 00:05:53 -08:00
|
|
|
use self::TargetLint::*;
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2015-12-22 16:35:02 -05:00
|
|
|
use dep_graph::DepNode;
|
2015-11-19 14:16:35 +03:00
|
|
|
use middle::privacy::AccessLevels;
|
2017-01-06 21:54:24 +02:00
|
|
|
use ty::{self, TyCtxt};
|
2015-12-31 16:50:06 +13:00
|
|
|
use session::{config, early_error, Session};
|
2016-06-12 17:46:43 -07:00
|
|
|
use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
|
2016-06-02 23:43:16 +02:00
|
|
|
use lint::{EarlyLintPassObject, LateLintPassObject};
|
2015-06-17 17:48:16 -07:00
|
|
|
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
|
2014-06-06 15:49:48 -07:00
|
|
|
use lint::builtin;
|
2017-01-28 18:13:21 -05:00
|
|
|
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
|
2016-11-08 14:02:55 +11:00
|
|
|
use util::nodemap::FxHashMap;
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2015-07-23 22:19:12 -07:00
|
|
|
use std::cmp;
|
2015-12-31 16:50:06 +13:00
|
|
|
use std::default::Default as StdDefault;
|
2014-06-06 15:49:48 -07:00
|
|
|
use std::mem;
|
2016-10-06 04:56:13 -04:00
|
|
|
use std::fmt;
|
2017-01-05 18:55:36 -08:00
|
|
|
use std::ops::Deref;
|
2016-08-23 03:54:53 +00:00
|
|
|
use syntax::attr;
|
2015-11-15 17:17:50 +01:00
|
|
|
use syntax::ast;
|
2017-01-05 18:55:43 -08:00
|
|
|
use syntax::symbol::Symbol;
|
2016-10-12 16:38:58 -04:00
|
|
|
use syntax_pos::{MultiSpan, Span};
|
2016-10-11 14:02:06 -04:00
|
|
|
use errors::{self, Diagnostic, DiagnosticBuilder};
|
2016-03-29 08:50:44 +03:00
|
|
|
use hir;
|
|
|
|
use hir::intravisit as hir_visit;
|
2015-09-10 16:40:59 +12:00
|
|
|
use syntax::visit as ast_visit;
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
/// Information about the registered lints.
|
|
|
|
///
|
|
|
|
/// This is basically the subset of `Context` that we can
|
|
|
|
/// build early in the compile pipeline.
|
|
|
|
pub struct LintStore {
|
|
|
|
/// Registered lints. The bool is true if the lint was
|
|
|
|
/// added by a plugin.
|
|
|
|
lints: Vec<(&'static Lint, bool)>,
|
|
|
|
|
|
|
|
/// Trait objects for each lint pass.
|
2014-06-13 00:00:49 -07:00
|
|
|
/// This is only `None` while iterating over the objects. See the definition
|
|
|
|
/// of run_lints.
|
2015-09-15 11:35:25 +12:00
|
|
|
early_passes: Option<Vec<EarlyLintPassObject>>,
|
|
|
|
late_passes: Option<Vec<LateLintPassObject>>,
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
/// Lints indexed by name.
|
2016-11-08 14:02:55 +11:00
|
|
|
by_name: FxHashMap<String, TargetLint>,
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
/// Current levels of each lint, and where they were set.
|
2016-11-08 14:02:55 +11:00
|
|
|
levels: FxHashMap<LintId, LevelSource>,
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
/// Map of registered lint groups to what lints they expand to. The bool
|
|
|
|
/// is true if the lint group was added by a plugin.
|
2016-11-08 14:02:55 +11:00
|
|
|
lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool)>,
|
2015-07-23 22:19:12 -07:00
|
|
|
|
2016-01-08 17:53:44 -05:00
|
|
|
/// Extra info for future incompatibility lints, descibing the
|
|
|
|
/// issue or RFC that caused the incompatibility.
|
2016-11-08 14:02:55 +11:00
|
|
|
future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
|
2016-01-08 17:53:44 -05:00
|
|
|
|
2015-07-23 22:19:12 -07:00
|
|
|
/// Maximum level a lint can be
|
|
|
|
lint_cap: Option<Level>,
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-10-06 04:56:13 -04:00
|
|
|
/// When you call `add_lint` on the session, you wind up storing one
|
|
|
|
/// of these, which records a "potential lint" at a particular point.
|
2017-01-28 18:13:21 -05:00
|
|
|
#[derive(PartialEq, RustcEncodable, RustcDecodable)]
|
2016-10-06 04:56:13 -04:00
|
|
|
pub struct EarlyLint {
|
|
|
|
/// what lint is this? (e.g., `dead_code`)
|
|
|
|
pub id: LintId,
|
|
|
|
|
|
|
|
/// the main message
|
2016-10-11 14:02:06 -04:00
|
|
|
pub diagnostic: Diagnostic,
|
2016-10-06 04:56:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for EarlyLint {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_struct("EarlyLint")
|
|
|
|
.field("id", &self.id)
|
2016-10-11 14:02:06 -04:00
|
|
|
.field("span", &self.diagnostic.span)
|
|
|
|
.field("diagnostic", &self.diagnostic)
|
2016-10-06 04:56:13 -04:00
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-13 12:08:50 -04:00
|
|
|
pub trait IntoEarlyLint {
|
|
|
|
fn into_early_lint(self, id: LintId) -> EarlyLint;
|
2016-10-12 16:38:58 -04:00
|
|
|
}
|
2016-10-06 04:56:13 -04:00
|
|
|
|
2016-10-25 23:24:09 -07:00
|
|
|
impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) {
|
2016-10-13 12:08:50 -04:00
|
|
|
fn into_early_lint(self, id: LintId) -> EarlyLint {
|
|
|
|
let (span, msg) = self;
|
|
|
|
let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg);
|
2016-10-12 16:38:58 -04:00
|
|
|
diagnostic.set_span(span);
|
2016-10-13 12:08:50 -04:00
|
|
|
EarlyLint { id: id, diagnostic: diagnostic }
|
2016-10-12 16:38:58 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-13 12:08:50 -04:00
|
|
|
impl IntoEarlyLint for Diagnostic {
|
|
|
|
fn into_early_lint(self, id: LintId) -> EarlyLint {
|
|
|
|
EarlyLint { id: id, diagnostic: self }
|
2016-10-12 16:38:58 -04:00
|
|
|
}
|
|
|
|
}
|
2016-10-06 04:56:13 -04:00
|
|
|
|
2016-01-08 17:53:44 -05:00
|
|
|
/// Extra information for a future incompatibility lint. See the call
|
|
|
|
/// to `register_future_incompatible` in `librustc_lint/lib.rs` for
|
|
|
|
/// guidelines.
|
|
|
|
pub struct FutureIncompatibleInfo {
|
|
|
|
pub id: LintId,
|
|
|
|
pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
|
|
|
|
}
|
|
|
|
|
2014-10-14 11:32:31 -07:00
|
|
|
/// The targed of the `by_name` map, which accounts for renaming/deprecation.
|
|
|
|
enum TargetLint {
|
|
|
|
/// A direct lint target
|
|
|
|
Id(LintId),
|
|
|
|
|
|
|
|
/// Temporary renaming, used for easing migration pain; see #16545
|
|
|
|
Renamed(String, LintId),
|
2015-07-15 20:12:30 +03:00
|
|
|
|
|
|
|
/// Lint with this name existed previously, but has been removed/deprecated.
|
|
|
|
/// The string argument is the reason for removal.
|
|
|
|
Removed(String),
|
|
|
|
}
|
|
|
|
|
|
|
|
enum FindLintError {
|
|
|
|
NotFound,
|
|
|
|
Removed
|
2014-10-14 11:32:31 -07:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
impl LintStore {
|
|
|
|
fn get_level_source(&self, lint: LintId) -> LevelSource {
|
2014-11-06 12:25:16 -05:00
|
|
|
match self.levels.get(&lint) {
|
2014-06-06 15:49:48 -07:00
|
|
|
Some(&s) => s,
|
|
|
|
None => (Allow, Default),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-23 22:19:12 -07:00
|
|
|
fn set_level(&mut self, lint: LintId, mut lvlsrc: LevelSource) {
|
|
|
|
if let Some(cap) = self.lint_cap {
|
|
|
|
lvlsrc.0 = cmp::min(lvlsrc.0, cap);
|
|
|
|
}
|
2014-12-09 12:21:18 -05:00
|
|
|
if lvlsrc.0 == Allow {
|
2014-06-06 15:49:48 -07:00
|
|
|
self.levels.remove(&lint);
|
|
|
|
} else {
|
|
|
|
self.levels.insert(lint, lvlsrc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new() -> LintStore {
|
|
|
|
LintStore {
|
2016-10-29 22:54:04 +01:00
|
|
|
lints: vec![],
|
|
|
|
early_passes: Some(vec![]),
|
|
|
|
late_passes: Some(vec![]),
|
2016-11-08 14:02:55 +11:00
|
|
|
by_name: FxHashMap(),
|
|
|
|
levels: FxHashMap(),
|
|
|
|
future_incompatible: FxHashMap(),
|
|
|
|
lint_groups: FxHashMap(),
|
2015-07-23 22:19:12 -07:00
|
|
|
lint_cap: None,
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
|
2015-02-20 14:08:14 -05:00
|
|
|
&self.lints
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-07-21 15:27:59 +12:00
|
|
|
pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
|
2014-09-05 01:24:04 +01:00
|
|
|
self.lint_groups.iter().map(|(k, v)| (*k,
|
2014-12-09 12:21:18 -05:00
|
|
|
v.0.clone(),
|
|
|
|
v.1)).collect()
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
|
|
|
|
2015-09-15 11:35:25 +12:00
|
|
|
pub fn register_early_pass(&mut self,
|
|
|
|
sess: Option<&Session>,
|
|
|
|
from_plugin: bool,
|
|
|
|
pass: EarlyLintPassObject) {
|
|
|
|
self.push_pass(sess, from_plugin, &pass);
|
|
|
|
self.early_passes.as_mut().unwrap().push(pass);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn register_late_pass(&mut self,
|
|
|
|
sess: Option<&Session>,
|
|
|
|
from_plugin: bool,
|
|
|
|
pass: LateLintPassObject) {
|
|
|
|
self.push_pass(sess, from_plugin, &pass);
|
|
|
|
self.late_passes.as_mut().unwrap().push(pass);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper method for register_early/late_pass
|
|
|
|
fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
|
|
|
|
sess: Option<&Session>,
|
|
|
|
from_plugin: bool,
|
|
|
|
pass: &Box<P>) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for &lint in pass.get_lints() {
|
2014-10-06 17:30:54 -07:00
|
|
|
self.lints.push((*lint, from_plugin));
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-10-06 17:30:54 -07:00
|
|
|
let id = LintId::of(*lint);
|
2014-11-06 12:25:16 -05:00
|
|
|
if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
|
2014-06-13 13:04:52 -07:00
|
|
|
let msg = format!("duplicate specification of lint {}", lint.name_lower());
|
2014-06-06 15:49:48 -07:00
|
|
|
match (sess, from_plugin) {
|
|
|
|
// We load builtin lints first, so a duplicate is a compiler bug.
|
|
|
|
// Use early_error when handling -W help with no crate.
|
2015-12-31 16:50:06 +13:00
|
|
|
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
|
2016-03-25 01:14:29 +01:00
|
|
|
(Some(_), false) => bug!("{}", msg),
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
// A duplicate name from a plugin is a user error.
|
2015-02-18 14:48:57 -05:00
|
|
|
(Some(sess), true) => sess.err(&msg[..]),
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if lint.default_level != Allow {
|
|
|
|
self.levels.insert(id, (lint.default_level, Default));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-08 17:53:44 -05:00
|
|
|
pub fn register_future_incompatible(&mut self,
|
|
|
|
sess: Option<&Session>,
|
|
|
|
lints: Vec<FutureIncompatibleInfo>) {
|
|
|
|
let ids = lints.iter().map(|f| f.id).collect();
|
|
|
|
self.register_group(sess, false, "future_incompatible", ids);
|
|
|
|
for info in lints {
|
|
|
|
self.future_incompatible.insert(info.id, info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
|
|
|
|
self.future_incompatible.get(&id)
|
|
|
|
}
|
|
|
|
|
2014-07-21 15:27:59 +12:00
|
|
|
pub fn register_group(&mut self, sess: Option<&Session>,
|
|
|
|
from_plugin: bool, name: &'static str,
|
|
|
|
to: Vec<LintId>) {
|
2014-11-06 12:25:16 -05:00
|
|
|
let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
if !new {
|
|
|
|
let msg = format!("duplicate specification of lint group {}", name);
|
|
|
|
match (sess, from_plugin) {
|
|
|
|
// We load builtin lints first, so a duplicate is a compiler bug.
|
|
|
|
// Use early_error when handling -W help with no crate.
|
2015-12-31 16:50:06 +13:00
|
|
|
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
|
2016-03-25 01:14:29 +01:00
|
|
|
(Some(_), false) => bug!("{}", msg),
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
// A duplicate name from a plugin is a user error.
|
2015-02-18 14:48:57 -05:00
|
|
|
(Some(sess), true) => sess.err(&msg[..]),
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-25 22:44:44 +11:00
|
|
|
pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
|
2014-11-12 15:51:51 -08:00
|
|
|
let target = match self.by_name.get(new_name) {
|
2014-10-14 11:32:31 -07:00
|
|
|
Some(&Id(lint_id)) => lint_id.clone(),
|
2016-03-26 19:59:04 +01:00
|
|
|
_ => bug!("invalid lint renaming of {} to {}", old_name, new_name)
|
2014-10-14 11:32:31 -07:00
|
|
|
};
|
|
|
|
self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
|
|
|
|
}
|
|
|
|
|
2015-07-15 20:12:30 +03:00
|
|
|
pub fn register_removed(&mut self, name: &str, reason: &str) {
|
|
|
|
self.by_name.insert(name.into(), Removed(reason.into()));
|
|
|
|
}
|
|
|
|
|
2014-10-30 09:13:02 -07:00
|
|
|
#[allow(unused_variables)]
|
2014-10-14 11:32:31 -07:00
|
|
|
fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
|
2015-07-15 20:12:30 +03:00
|
|
|
-> Result<LintId, FindLintError>
|
2014-10-14 11:32:31 -07:00
|
|
|
{
|
2014-11-12 15:51:51 -08:00
|
|
|
match self.by_name.get(lint_name) {
|
2015-07-15 20:12:30 +03:00
|
|
|
Some(&Id(lint_id)) => Ok(lint_id),
|
2016-01-13 18:54:06 +00:00
|
|
|
Some(&Renamed(_, lint_id)) => {
|
2015-07-15 20:12:30 +03:00
|
|
|
Ok(lint_id)
|
|
|
|
},
|
|
|
|
Some(&Removed(ref reason)) => {
|
|
|
|
Err(FindLintError::Removed)
|
|
|
|
},
|
|
|
|
None => Err(FindLintError::NotFound)
|
2014-10-14 11:32:31 -07:00
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_command_line(&mut self, sess: &Session) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for &(ref lint_name, level) in &sess.opts.lint_opts {
|
2016-01-13 18:54:06 +00:00
|
|
|
check_lint_name_cmdline(sess, self,
|
|
|
|
&lint_name[..], level);
|
|
|
|
|
2017-01-05 18:55:43 -08:00
|
|
|
let lint_flag_val = Symbol::intern(&lint_name);
|
2015-02-18 14:48:57 -05:00
|
|
|
match self.find_lint(&lint_name[..], sess, None) {
|
2017-01-05 18:55:43 -08:00
|
|
|
Ok(lint_id) => self.set_level(lint_id, (level, CommandLine(lint_flag_val))),
|
2016-01-13 18:54:06 +00:00
|
|
|
Err(FindLintError::Removed) => { }
|
2015-07-15 20:12:30 +03:00
|
|
|
Err(_) => {
|
2014-12-09 12:21:18 -05:00
|
|
|
match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone()))
|
2016-11-08 14:02:55 +11:00
|
|
|
.collect::<FxHashMap<&'static str,
|
|
|
|
Vec<LintId>>>()
|
2015-02-18 14:48:57 -05:00
|
|
|
.get(&lint_name[..]) {
|
2014-07-21 15:27:59 +12:00
|
|
|
Some(v) => {
|
|
|
|
v.iter()
|
|
|
|
.map(|lint_id: &LintId|
|
2017-01-05 18:55:43 -08:00
|
|
|
self.set_level(*lint_id, (level, CommandLine(lint_flag_val))))
|
2014-07-21 15:27:59 +12:00
|
|
|
.collect::<Vec<()>>();
|
|
|
|
}
|
2016-01-13 18:54:06 +00:00
|
|
|
None => {
|
|
|
|
// The lint or lint group doesn't exist.
|
|
|
|
// This is an error, but it was handled
|
|
|
|
// by check_lint_name_cmdline.
|
|
|
|
}
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
2015-07-23 22:19:12 -07:00
|
|
|
|
|
|
|
self.lint_cap = sess.opts.lint_cap;
|
|
|
|
if let Some(cap) = self.lint_cap {
|
|
|
|
for level in self.levels.iter_mut().map(|p| &mut (p.1).0) {
|
|
|
|
*level = cmp::min(*level, cap);
|
|
|
|
}
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 16:40:59 +12:00
|
|
|
/// Context for lint checking after type checking.
|
|
|
|
pub struct LateContext<'a, 'tcx: 'a> {
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Type context we're checking in.
|
2016-05-03 05:23:22 +03:00
|
|
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2017-01-06 21:54:24 +02:00
|
|
|
/// Side-tables for the body we are in.
|
2017-01-25 16:24:00 -05:00
|
|
|
pub tables: &'a ty::TypeckTables<'tcx>,
|
2017-01-06 21:54:24 +02:00
|
|
|
|
2014-06-17 16:55:34 -07:00
|
|
|
/// The crate being checked.
|
2015-09-03 18:59:56 +05:30
|
|
|
pub krate: &'a hir::Crate,
|
2014-06-17 16:55:34 -07:00
|
|
|
|
2015-11-19 14:16:35 +03:00
|
|
|
/// Items accessible from the crate being checked.
|
|
|
|
pub access_levels: &'a AccessLevels,
|
2014-06-17 16:55:34 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// The store of registered lints.
|
|
|
|
lints: LintStore,
|
|
|
|
|
|
|
|
/// When recursing into an attributed node of the ast which modifies lint
|
|
|
|
/// levels, this stack keeps track of the previous lint levels of whatever
|
|
|
|
/// was modified.
|
|
|
|
level_stack: Vec<(LintId, LevelSource)>,
|
|
|
|
}
|
|
|
|
|
2015-09-10 16:40:59 +12:00
|
|
|
/// Context for lint checking of the AST, after expansion, before lowering to
|
|
|
|
/// HIR.
|
|
|
|
pub struct EarlyContext<'a> {
|
|
|
|
/// Type context we're checking in.
|
|
|
|
pub sess: &'a Session,
|
|
|
|
|
|
|
|
/// The crate being checked.
|
|
|
|
pub krate: &'a ast::Crate,
|
|
|
|
|
|
|
|
/// The store of registered lints.
|
|
|
|
lints: LintStore,
|
|
|
|
|
|
|
|
/// When recursing into an attributed node of the ast which modifies lint
|
|
|
|
/// levels, this stack keeps track of the previous lint levels of whatever
|
|
|
|
/// was modified.
|
|
|
|
level_stack: Vec<(LintId, LevelSource)>,
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Convenience macro for calling a `LintPass` method on every pass in the context.
|
2015-09-15 11:35:25 +12:00
|
|
|
macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({
|
2014-06-13 00:00:49 -07:00
|
|
|
// Move the vector of passes out of `$cx` so that we can
|
|
|
|
// iterate over it mutably while passing `$cx` to the methods.
|
2015-09-15 11:35:25 +12:00
|
|
|
let mut passes = $cx.mut_lints().$ps.take().unwrap();
|
2015-01-31 20:02:00 -05:00
|
|
|
for obj in &mut passes {
|
2014-06-13 00:00:49 -07:00
|
|
|
obj.$f($cx, $($args),*);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
2015-09-15 11:35:25 +12:00
|
|
|
$cx.mut_lints().$ps = Some(passes);
|
2014-11-14 09:18:10 -08:00
|
|
|
}) }
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-06-13 15:03:26 -07:00
|
|
|
/// Parse the lint attributes into a vector, with `Err`s for malformed lint
|
|
|
|
/// attributes. Writing this as an iterator is an enormous mess.
|
2015-07-31 00:04:06 -07:00
|
|
|
// See also the hir version just below.
|
2016-11-15 04:34:52 +00:00
|
|
|
pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec<Result<(ast::Name, Level, Span), Span>> {
|
2016-10-29 22:54:04 +01:00
|
|
|
let mut out = vec![];
|
2015-01-31 12:20:46 -05:00
|
|
|
for attr in attrs {
|
2016-01-13 18:54:06 +00:00
|
|
|
let r = gather_attr(attr);
|
|
|
|
out.extend(r.into_iter());
|
|
|
|
}
|
|
|
|
out
|
|
|
|
}
|
2014-06-13 15:03:26 -07:00
|
|
|
|
2016-11-15 04:34:52 +00:00
|
|
|
pub fn gather_attr(attr: &ast::Attribute) -> Vec<Result<(ast::Name, Level, Span), Span>> {
|
2016-10-29 22:54:04 +01:00
|
|
|
let mut out = vec![];
|
2014-06-13 15:03:26 -07:00
|
|
|
|
2016-11-15 04:34:52 +00:00
|
|
|
let level = match Level::from_str(&attr.name().as_str()) {
|
2016-01-13 18:54:06 +00:00
|
|
|
None => return out,
|
|
|
|
Some(lvl) => lvl,
|
|
|
|
};
|
2015-07-31 00:04:06 -07:00
|
|
|
|
2016-01-13 18:54:06 +00:00
|
|
|
attr::mark_used(attr);
|
|
|
|
|
2016-11-14 12:00:25 +00:00
|
|
|
let meta = &attr.value;
|
2016-07-15 13:13:17 -07:00
|
|
|
let metas = if let Some(metas) = meta.meta_item_list() {
|
2016-07-17 21:45:06 -07:00
|
|
|
metas
|
|
|
|
} else {
|
|
|
|
out.push(Err(meta.span));
|
|
|
|
return out;
|
|
|
|
};
|
2016-01-13 18:54:06 +00:00
|
|
|
|
2016-08-19 18:58:14 -07:00
|
|
|
for li in metas {
|
2016-11-15 04:34:52 +00:00
|
|
|
out.push(li.word().map_or(Err(li.span), |word| Ok((word.name(), level, word.span))));
|
2015-07-31 00:04:06 -07:00
|
|
|
}
|
2016-01-13 18:54:06 +00:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
out
|
|
|
|
}
|
2014-06-13 15:03:26 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Emit a lint as a warning or an error (or not at all)
|
|
|
|
/// according to `level`.
|
|
|
|
///
|
|
|
|
/// This lives outside of `Context` so it can be used by checks
|
|
|
|
/// in trans that run after the main lint pass is finished. Most
|
|
|
|
/// lints elsewhere in the compiler should call
|
|
|
|
/// `Session::add_lint()` instead.
|
2016-10-12 17:00:30 -04:00
|
|
|
pub fn raw_emit_lint<S: Into<MultiSpan>>(sess: &Session,
|
|
|
|
lints: &LintStore,
|
|
|
|
lint: &'static Lint,
|
|
|
|
lvlsrc: LevelSource,
|
|
|
|
span: Option<S>,
|
|
|
|
msg: &str) {
|
2016-01-05 13:43:57 -05:00
|
|
|
raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
|
2015-12-21 10:00:43 +13:00
|
|
|
}
|
|
|
|
|
2016-10-12 16:38:58 -04:00
|
|
|
pub fn raw_struct_lint<'a, S>(sess: &'a Session,
|
|
|
|
lints: &LintStore,
|
|
|
|
lint: &'static Lint,
|
|
|
|
lvlsrc: LevelSource,
|
|
|
|
span: Option<S>,
|
|
|
|
msg: &str)
|
|
|
|
-> DiagnosticBuilder<'a>
|
|
|
|
where S: Into<MultiSpan>
|
|
|
|
{
|
2017-01-05 18:55:36 -08:00
|
|
|
let (level, source) = lvlsrc;
|
2015-12-21 10:00:43 +13:00
|
|
|
if level == Allow {
|
2015-12-23 19:27:20 +13:00
|
|
|
return sess.diagnostic().struct_dummy();
|
2015-12-21 10:00:43 +13:00
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-06-13 13:04:52 -07:00
|
|
|
let name = lint.name_lower();
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
let mut def = None;
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2017-01-05 18:55:36 -08:00
|
|
|
// Except for possible note details, forbid behaves like deny.
|
|
|
|
let effective_level = if level == Forbid { Deny } else { level };
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2017-01-05 18:55:36 -08:00
|
|
|
let mut err = match (effective_level, span) {
|
2015-12-21 10:00:43 +13:00
|
|
|
(Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
|
|
|
|
(Warn, None) => sess.struct_warn(&msg[..]),
|
|
|
|
(Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
|
|
|
|
(Deny, None) => sess.struct_err(&msg[..]),
|
2016-03-25 01:14:29 +01:00
|
|
|
_ => bug!("impossible level in raw_emit_lint"),
|
2015-12-21 10:00:43 +13:00
|
|
|
};
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2017-01-05 18:55:36 -08:00
|
|
|
match source {
|
|
|
|
Default => {
|
|
|
|
err.note(&format!("#[{}({})] on by default", level.as_str(), name));
|
|
|
|
},
|
2017-01-05 18:55:43 -08:00
|
|
|
CommandLine(lint_flag_val) => {
|
|
|
|
let flag = match level {
|
|
|
|
Warn => "-W", Deny => "-D", Forbid => "-F",
|
|
|
|
Allow => bug!("earlier conditional return should handle Allow case")
|
|
|
|
};
|
|
|
|
let hyphen_case_lint_name = name.replace("_", "-");
|
|
|
|
if lint_flag_val.as_str().deref() == name {
|
|
|
|
err.note(&format!("requested on the command line with `{} {}`",
|
|
|
|
flag, hyphen_case_lint_name));
|
|
|
|
} else {
|
|
|
|
let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
|
2017-01-05 20:01:22 -08:00
|
|
|
err.note(&format!("`{} {}` implied by `{} {}`",
|
|
|
|
flag, hyphen_case_lint_name, flag, hyphen_case_flag_val));
|
2017-01-05 18:55:43 -08:00
|
|
|
}
|
2017-01-05 18:55:36 -08:00
|
|
|
},
|
|
|
|
Node(lint_attr_name, src) => {
|
|
|
|
def = Some(src);
|
|
|
|
if lint_attr_name.as_str().deref() != name {
|
|
|
|
let level_str = level.as_str();
|
2017-01-05 20:01:22 -08:00
|
|
|
err.note(&format!("#[{}({})] implied by #[{}({})]",
|
|
|
|
level_str, name, level_str, lint_attr_name));
|
2017-01-05 18:55:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-05 13:43:57 -05:00
|
|
|
// Check for future incompatibility lints and issue a stronger warning.
|
2016-01-08 17:53:44 -05:00
|
|
|
if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) {
|
|
|
|
let explanation = format!("this was previously accepted by the compiler \
|
2016-01-13 15:56:53 -05:00
|
|
|
but is being phased out; \
|
|
|
|
it will become a hard error in a future release!");
|
2016-01-08 17:53:44 -05:00
|
|
|
let citation = format!("for more information, see {}",
|
|
|
|
future_incompatible.reference);
|
2016-04-20 14:49:16 -04:00
|
|
|
err.warn(&explanation);
|
|
|
|
err.note(&citation);
|
2016-01-05 13:43:57 -05:00
|
|
|
}
|
|
|
|
|
2015-01-31 20:03:04 -05:00
|
|
|
if let Some(span) = def {
|
2016-10-26 23:07:38 -07:00
|
|
|
sess.diag_span_note_once(&mut err, lint, span, "lint level defined here");
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
2015-12-23 19:27:20 +13:00
|
|
|
|
|
|
|
err
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
pub trait LintContext<'tcx>: Sized {
|
2015-09-10 16:40:59 +12:00
|
|
|
fn sess(&self) -> &Session;
|
|
|
|
fn lints(&self) -> &LintStore;
|
|
|
|
fn mut_lints(&mut self) -> &mut LintStore;
|
|
|
|
fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>;
|
2016-12-06 11:26:52 +01:00
|
|
|
fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
|
|
|
|
fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-07-17 20:07:43 +10:00
|
|
|
/// Get the level of `lint` at the current position of the lint
|
|
|
|
/// traversal.
|
2015-09-10 16:40:59 +12:00
|
|
|
fn current_level(&self, lint: &'static Lint) -> Level {
|
|
|
|
self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
|
2014-07-17 20:07:43 +10:00
|
|
|
}
|
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
|
|
|
|
self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
|
2016-01-09 23:30:33 +00:00
|
|
|
&(Warn, _) => {
|
2014-06-13 13:13:05 -07:00
|
|
|
let lint_id = LintId::of(builtin::WARNINGS);
|
2016-01-09 23:30:33 +00:00
|
|
|
let warn_src = self.lints().get_level_source(lint_id);
|
|
|
|
if warn_src.0 != Warn {
|
|
|
|
warn_src
|
|
|
|
} else {
|
|
|
|
*ls
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
2015-12-21 10:00:43 +13:00
|
|
|
_ => *ls
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-10-25 23:24:09 -07:00
|
|
|
fn lookup_and_emit<S: Into<MultiSpan>>(&self,
|
|
|
|
lint: &'static Lint,
|
|
|
|
span: Option<S>,
|
|
|
|
msg: &str) {
|
2015-12-21 10:00:43 +13:00
|
|
|
let (level, src) = match self.level_src(lint) {
|
|
|
|
None => return,
|
|
|
|
Some(pair) => pair,
|
2014-06-06 15:49:48 -07:00
|
|
|
};
|
|
|
|
|
2016-01-05 13:43:57 -05:00
|
|
|
raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-10-12 17:00:30 -04:00
|
|
|
fn lookup<S: Into<MultiSpan>>(&self,
|
|
|
|
lint: &'static Lint,
|
|
|
|
span: Option<S>,
|
|
|
|
msg: &str)
|
|
|
|
-> DiagnosticBuilder {
|
2015-12-21 10:00:43 +13:00
|
|
|
let (level, src) = match self.level_src(lint) {
|
2015-12-23 19:27:20 +13:00
|
|
|
None => return self.sess().diagnostic().struct_dummy(),
|
2015-12-21 10:00:43 +13:00
|
|
|
Some(pair) => pair,
|
|
|
|
};
|
|
|
|
|
2016-01-05 13:43:57 -05:00
|
|
|
raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg)
|
2015-12-21 10:00:43 +13:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Emit a lint at the appropriate level, for a particular span.
|
2016-10-25 23:24:09 -07:00
|
|
|
fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
|
2014-06-06 15:49:48 -07:00
|
|
|
self.lookup_and_emit(lint, Some(span), msg);
|
|
|
|
}
|
|
|
|
|
2017-01-28 18:13:21 -05:00
|
|
|
fn early_lint(&self, early_lint: &EarlyLint) {
|
2016-10-13 12:08:50 -04:00
|
|
|
let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span");
|
2016-10-11 14:02:06 -04:00
|
|
|
let mut err = self.struct_span_lint(early_lint.id.lint,
|
2016-10-13 12:08:50 -04:00
|
|
|
span,
|
2017-01-11 13:55:41 -08:00
|
|
|
&early_lint.diagnostic.message());
|
2016-10-11 14:02:06 -04:00
|
|
|
err.copy_details_not_message(&early_lint.diagnostic);
|
2016-10-06 04:56:13 -04:00
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
|
2016-10-12 17:00:30 -04:00
|
|
|
fn struct_span_lint<S: Into<MultiSpan>>(&self,
|
|
|
|
lint: &'static Lint,
|
|
|
|
span: S,
|
|
|
|
msg: &str)
|
|
|
|
-> DiagnosticBuilder {
|
2015-12-21 10:00:43 +13:00
|
|
|
self.lookup(lint, Some(span), msg)
|
|
|
|
}
|
|
|
|
|
2015-10-17 01:50:33 +05:30
|
|
|
/// Emit a lint and note at the appropriate level, for a particular span.
|
|
|
|
fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
|
|
|
|
note_span: Span, note: &str) {
|
2015-12-23 19:27:20 +13:00
|
|
|
let mut err = self.lookup(lint, Some(span), msg);
|
2015-10-17 01:50:33 +05:30
|
|
|
if self.current_level(lint) != Level::Allow {
|
|
|
|
if note_span == span {
|
2016-04-20 14:49:16 -04:00
|
|
|
err.note(note);
|
2015-10-17 01:50:33 +05:30
|
|
|
} else {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(note_span, note);
|
2015-10-17 01:50:33 +05:30
|
|
|
}
|
|
|
|
}
|
2015-12-21 10:00:43 +13:00
|
|
|
err.emit();
|
2015-10-17 01:50:33 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit a lint and help at the appropriate level, for a particular span.
|
|
|
|
fn span_lint_help(&self, lint: &'static Lint, span: Span,
|
|
|
|
msg: &str, help: &str) {
|
2015-12-23 19:27:20 +13:00
|
|
|
let mut err = self.lookup(lint, Some(span), msg);
|
2015-10-17 01:50:33 +05:30
|
|
|
self.span_lint(lint, span, msg);
|
|
|
|
if self.current_level(lint) != Level::Allow {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_help(span, help);
|
2015-10-17 01:50:33 +05:30
|
|
|
}
|
2015-12-21 10:00:43 +13:00
|
|
|
err.emit();
|
2015-10-17 01:50:33 +05:30
|
|
|
}
|
|
|
|
|
2015-09-10 16:40:59 +12:00
|
|
|
/// Emit a lint at the appropriate level, with no associated span.
|
|
|
|
fn lint(&self, lint: &'static Lint, msg: &str) {
|
2016-10-25 23:24:09 -07:00
|
|
|
self.lookup_and_emit(lint, None as Option<Span>, msg);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2014-11-24 20:06:06 -05:00
|
|
|
/// Merge the lints specified by any lint attributes into the
|
|
|
|
/// current lint context, call the provided function, then reset the
|
|
|
|
/// lints in effect to their previous state.
|
2014-12-08 20:26:43 -05:00
|
|
|
fn with_lint_attrs<F>(&mut self,
|
2016-12-06 11:26:52 +01:00
|
|
|
attrs: &'tcx [ast::Attribute],
|
2015-09-10 16:40:59 +12:00
|
|
|
f: F)
|
|
|
|
where F: FnOnce(&mut Self),
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2014-06-06 15:49:48 -07:00
|
|
|
// Parse all of the lint attributes, and then add them all to the
|
|
|
|
// current dictionary of lint information. Along the way, keep a history
|
|
|
|
// of what we changed so we can roll everything back after invoking the
|
|
|
|
// specified closure
|
2015-01-25 10:58:43 +00:00
|
|
|
let mut pushed = 0;
|
2014-06-13 15:03:26 -07:00
|
|
|
|
2015-01-31 20:03:04 -05:00
|
|
|
for result in gather_attrs(attrs) {
|
2014-07-21 15:27:59 +12:00
|
|
|
let v = match result {
|
2014-06-13 15:03:26 -07:00
|
|
|
Err(span) => {
|
2015-09-10 16:40:59 +12:00
|
|
|
span_err!(self.sess(), span, E0452,
|
2015-09-11 16:17:15 +02:00
|
|
|
"malformed lint attribute");
|
2014-06-13 15:03:26 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Ok((lint_name, level, span)) => {
|
2016-11-15 04:34:52 +00:00
|
|
|
match self.lints().find_lint(&lint_name.as_str(), &self.sess(), Some(span)) {
|
2015-07-15 20:12:30 +03:00
|
|
|
Ok(lint_id) => vec![(lint_id, level, span)],
|
|
|
|
Err(FindLintError::NotFound) => {
|
2016-11-15 04:34:52 +00:00
|
|
|
match self.lints().lint_groups.get(&*lint_name.as_str()) {
|
2014-07-21 15:27:59 +12:00
|
|
|
Some(&(ref v, _)) => v.iter()
|
|
|
|
.map(|lint_id: &LintId|
|
|
|
|
(*lint_id, level, span))
|
|
|
|
.collect(),
|
|
|
|
None => {
|
2016-01-13 18:54:06 +00:00
|
|
|
// The lint or lint group doesn't exist.
|
|
|
|
// This is an error, but it was handled
|
|
|
|
// by check_lint_name_attribute.
|
2014-07-21 15:27:59 +12:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2015-07-15 20:12:30 +03:00
|
|
|
},
|
|
|
|
Err(FindLintError::Removed) => { continue; }
|
2014-06-13 15:03:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-05 18:55:36 -08:00
|
|
|
let lint_attr_name = result.expect("lint attribute should be well-formed").0;
|
|
|
|
|
2015-01-31 20:03:04 -05:00
|
|
|
for (lint_id, level, span) in v {
|
2016-06-12 17:46:43 -07:00
|
|
|
let (now, now_source) = self.lints().get_level_source(lint_id);
|
2014-07-21 15:27:59 +12:00
|
|
|
if now == Forbid && level != Forbid {
|
2016-08-23 21:27:20 -04:00
|
|
|
let lint_name = lint_id.to_string();
|
2016-06-12 17:46:43 -07:00
|
|
|
let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
|
|
|
|
"{}({}) overruled by outer forbid({})",
|
|
|
|
level.as_str(), lint_name,
|
|
|
|
lint_name);
|
2016-08-25 19:09:48 +05:30
|
|
|
diag_builder.span_label(span, &format!("overruled by previous forbid"));
|
2016-06-12 17:46:43 -07:00
|
|
|
match now_source {
|
|
|
|
LintSource::Default => &mut diag_builder,
|
2017-01-05 18:55:36 -08:00
|
|
|
LintSource::Node(_, forbid_source_span) => {
|
2016-08-25 19:09:48 +05:30
|
|
|
diag_builder.span_label(forbid_source_span,
|
|
|
|
&format!("`forbid` level set here"))
|
2016-06-12 17:46:43 -07:00
|
|
|
},
|
2017-01-05 18:55:43 -08:00
|
|
|
LintSource::CommandLine(_) => {
|
2016-06-12 17:46:43 -07:00
|
|
|
diag_builder.note("`forbid` lint level was set on command line")
|
|
|
|
}
|
|
|
|
}.emit()
|
2014-07-21 15:27:59 +12:00
|
|
|
} else if now != level {
|
2015-09-10 16:40:59 +12:00
|
|
|
let src = self.lints().get_level_source(lint_id).1;
|
|
|
|
self.level_stack().push((lint_id, (now, src)));
|
2014-07-21 15:27:59 +12:00
|
|
|
pushed += 1;
|
2017-01-05 18:55:36 -08:00
|
|
|
self.mut_lints().set_level(lint_id, (level, Node(lint_attr_name, span)));
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 16:40:59 +12:00
|
|
|
self.enter_attrs(attrs);
|
2014-06-06 15:49:48 -07:00
|
|
|
f(self);
|
2015-09-10 16:40:59 +12:00
|
|
|
self.exit_attrs(attrs);
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
// rollback
|
2015-01-26 15:46:12 -05:00
|
|
|
for _ in 0..pushed {
|
2015-09-10 16:40:59 +12:00
|
|
|
let (lint, lvlsrc) = self.level_stack().pop().unwrap();
|
|
|
|
self.mut_lints().set_level(lint, lvlsrc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> EarlyContext<'a> {
|
|
|
|
fn new(sess: &'a Session,
|
|
|
|
krate: &'a ast::Crate) -> EarlyContext<'a> {
|
2015-09-11 20:15:58 +12:00
|
|
|
// We want to own the lint store, so move it out of the session. Remember
|
|
|
|
// to put it back later...
|
2015-09-10 16:40:59 +12:00
|
|
|
let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(),
|
|
|
|
LintStore::new());
|
|
|
|
EarlyContext {
|
|
|
|
sess: sess,
|
|
|
|
krate: krate,
|
|
|
|
lints: lint_store,
|
|
|
|
level_stack: vec![],
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> {
|
2015-09-10 16:40:59 +12:00
|
|
|
/// Get the overall compiler `Session` object.
|
|
|
|
fn sess(&self) -> &Session {
|
|
|
|
&self.tcx.sess
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lints(&self) -> &LintStore {
|
|
|
|
&self.lints
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mut_lints(&mut self) -> &mut LintStore {
|
|
|
|
&mut self.lints
|
|
|
|
}
|
|
|
|
|
|
|
|
fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
|
|
|
|
&mut self.level_stack
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
|
2015-11-17 18:56:13 -05:00
|
|
|
debug!("late context: enter_attrs({:?})", attrs);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, enter_lint_attrs, late_passes, attrs);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
|
2015-11-17 18:56:13 -05:00
|
|
|
debug!("late context: exit_attrs({:?})", attrs);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, exit_lint_attrs, late_passes, attrs);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
impl<'a> LintContext<'a> for EarlyContext<'a> {
|
2015-09-10 16:40:59 +12:00
|
|
|
/// Get the overall compiler `Session` object.
|
|
|
|
fn sess(&self) -> &Session {
|
|
|
|
&self.sess
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lints(&self) -> &LintStore {
|
|
|
|
&self.lints
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mut_lints(&mut self) -> &mut LintStore {
|
|
|
|
&mut self.lints
|
|
|
|
}
|
|
|
|
|
|
|
|
fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
|
|
|
|
&mut self.level_stack
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) {
|
2015-12-19 23:33:45 +01:00
|
|
|
debug!("early context: enter_attrs({:?})", attrs);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, enter_lint_attrs, early_passes, attrs);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) {
|
2015-11-17 18:56:13 -05:00
|
|
|
debug!("early context: exit_attrs({:?})", attrs);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, exit_lint_attrs, early_passes, attrs);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
|
2015-11-17 18:56:13 -05:00
|
|
|
/// Because lints are scoped lexically, we want to walk nested
|
|
|
|
/// items in the context of the outer item, so enable
|
|
|
|
/// deep-walking.
|
2016-11-28 14:00:26 -05:00
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
|
2017-01-26 02:41:06 +02:00
|
|
|
hir_visit::NestedVisitorMap::All(&self.tcx.hir)
|
2016-11-04 18:20:15 -04:00
|
|
|
}
|
|
|
|
|
Fix lint attributes on non-item nodes.
Currently, late lint checking uses two HIR visitors: LateContext and
IdVisitor. IdVisitor only overrides visit_id, and for each node searches
for builtin lints previously added to the session; LateContext overrides
a number of methods, and runs late lints. When LateContext encounters an
item, it first has IdVisitor walk everything in it except nested items
(OnlyBodies), then recurses into it itself - i.e. there are two separate
walks.
Aside from apparently being unnecessary, this separation prevents lint
attributes (allow/deny/warn) on non-item HIR nodes from working
properly. Test case:
// generates warning without this change
fn main() { #[allow(unreachable_code)] loop { break; break; } }
LateContext contains logic to merge attributes seen into the current lint
settings while walking (with_lint_attrs), but IdVisitor does not. So
such attributes will affect late lints (because they are called from
LateContext), and if the node contains any items within it, they will
affect builtin lints within those items (because that IdVisitor is run
while LateContext is within the attributed node), but otherwise the
attributes will be ignored for builtin lints.
This change simply removes IdVisitor and moves its visit_id into
LateContext itself. Hopefully this doesn't break anything...
Also added walk calls to visit_lifetime and visit_lifetime_def
respectively, so visit_lifetime_def will recurse into the lifetime and
visit_lifetime will recurse into the name. In principle this could
confuse lint plugins. This is "necessary" because walk_lifetime calls
visit_id on the lifetime; of course, an alternative would be directly
calling visit_id (which would require manually iterating over the
lifetimes in visit_lifetime_def), but that seems less clean.
2017-01-03 20:40:29 +01:00
|
|
|
// Output any lints that were previously added to the session.
|
|
|
|
fn visit_id(&mut self, id: ast::NodeId) {
|
2017-01-28 07:01:45 -05:00
|
|
|
let lints = self.sess().lints.borrow_mut().take(id);
|
2017-01-28 18:13:21 -05:00
|
|
|
for early_lint in lints.iter().chain(self.tables.lints.get(id)) {
|
2017-01-28 07:01:45 -05:00
|
|
|
debug!("LateContext::visit_id: id={:?} early_lint={:?}", id, early_lint);
|
|
|
|
self.early_lint(early_lint);
|
Fix lint attributes on non-item nodes.
Currently, late lint checking uses two HIR visitors: LateContext and
IdVisitor. IdVisitor only overrides visit_id, and for each node searches
for builtin lints previously added to the session; LateContext overrides
a number of methods, and runs late lints. When LateContext encounters an
item, it first has IdVisitor walk everything in it except nested items
(OnlyBodies), then recurses into it itself - i.e. there are two separate
walks.
Aside from apparently being unnecessary, this separation prevents lint
attributes (allow/deny/warn) on non-item HIR nodes from working
properly. Test case:
// generates warning without this change
fn main() { #[allow(unreachable_code)] loop { break; break; } }
LateContext contains logic to merge attributes seen into the current lint
settings while walking (with_lint_attrs), but IdVisitor does not. So
such attributes will affect late lints (because they are called from
LateContext), and if the node contains any items within it, they will
affect builtin lints within those items (because that IdVisitor is run
while LateContext is within the attributed node), but otherwise the
attributes will be ignored for builtin lints.
This change simply removes IdVisitor and moves its visit_id into
LateContext itself. Hopefully this doesn't break anything...
Also added walk calls to visit_lifetime and visit_lifetime_def
respectively, so visit_lifetime_def will recurse into the lifetime and
visit_lifetime will recurse into the name. In principle this could
confuse lint plugins. This is "necessary" because walk_lifetime calls
visit_id on the lifetime; of course, an alternative would be directly
calling visit_id (which would require manually iterating over the
lifetimes in visit_lifetime_def), but that seems less clean.
2017-01-03 20:40:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:54:24 +02:00
|
|
|
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
|
|
|
let old_tables = self.tables;
|
|
|
|
self.tables = self.tcx.body_tables(body);
|
2017-01-26 02:41:06 +02:00
|
|
|
let body = self.tcx.hir.body(body);
|
2017-01-06 21:54:24 +02:00
|
|
|
self.visit_body(body);
|
|
|
|
self.tables = old_tables;
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_item(&mut self, it: &'tcx hir::Item) {
|
2015-02-20 14:08:14 -05:00
|
|
|
self.with_lint_attrs(&it.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_item, late_passes, it);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_item(cx, it);
|
2016-02-11 18:19:18 +01:00
|
|
|
run_lints!(cx, check_item_post, late_passes, it);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
|
2015-02-20 14:08:14 -05:00
|
|
|
self.with_lint_attrs(&it.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_foreign_item, late_passes, it);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_foreign_item(cx, it);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(cx, check_foreign_item_post, late_passes, it);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_pat, late_passes, p);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_pat(self, p);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
|
2016-06-18 04:01:57 +00:00
|
|
|
self.with_lint_attrs(&e.attrs, |cx| {
|
2015-11-03 17:39:51 +01:00
|
|
|
run_lints!(cx, check_expr, late_passes, e);
|
|
|
|
hir_visit::walk_expr(cx, e);
|
2016-12-21 12:32:59 +02:00
|
|
|
run_lints!(cx, check_expr_post, late_passes, e);
|
2015-11-03 17:39:51 +01:00
|
|
|
})
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
|
2015-11-03 17:39:51 +01:00
|
|
|
// statement attributes are actually just attributes on one of
|
|
|
|
// - item
|
|
|
|
// - local
|
|
|
|
// - expression
|
|
|
|
// so we keep track of lint levels there
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_stmt, late_passes, s);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_stmt(self, s);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
|
2016-12-21 12:32:59 +02:00
|
|
|
body_id: hir::BodyId, span: Span, id: ast::NodeId) {
|
2017-01-06 21:54:24 +02:00
|
|
|
// Wrap in tables here, not just in visit_nested_body,
|
|
|
|
// in order for `check_fn` to be able to use them.
|
|
|
|
let old_tables = self.tables;
|
|
|
|
self.tables = self.tcx.body_tables(body_id);
|
2017-01-26 02:41:06 +02:00
|
|
|
let body = self.tcx.hir.body(body_id);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
|
2016-10-28 22:58:32 +02:00
|
|
|
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
|
2017-01-06 21:54:24 +02:00
|
|
|
self.tables = old_tables;
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2015-10-08 03:20:57 +03:00
|
|
|
fn visit_variant_data(&mut self,
|
2016-11-09 16:45:26 -05:00
|
|
|
s: &'tcx hir::VariantData,
|
2015-09-20 03:34:12 +03:00
|
|
|
name: ast::Name,
|
2016-11-09 16:45:26 -05:00
|
|
|
g: &'tcx hir::Generics,
|
2015-10-02 20:06:59 +03:00
|
|
|
item_id: ast::NodeId,
|
|
|
|
_: Span) {
|
2015-10-02 16:14:20 +03:00
|
|
|
run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_struct_def(self, s);
|
2015-10-02 16:14:20 +03:00
|
|
|
run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
|
2016-02-27 11:34:29 +03:00
|
|
|
self.with_lint_attrs(&s.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_struct_field, late_passes, s);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_struct_field(cx, s);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_variant(&mut self,
|
|
|
|
v: &'tcx hir::Variant,
|
|
|
|
g: &'tcx hir::Generics,
|
|
|
|
item_id: ast::NodeId) {
|
2015-02-20 14:08:14 -05:00
|
|
|
self.with_lint_attrs(&v.node.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_variant, late_passes, v, g);
|
2015-10-02 16:14:20 +03:00
|
|
|
hir_visit::walk_variant(cx, v, g, item_id);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_variant_post, late_passes, v, g);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_ty, late_passes, t);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_ty(self, t);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2015-09-20 03:34:12 +03:00
|
|
|
fn visit_name(&mut self, sp: Span, name: ast::Name) {
|
|
|
|
run_lints!(self, check_name, late_passes, sp, name);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_mod, late_passes, m, s, n);
|
2016-07-28 05:58:45 -04:00
|
|
|
hir_visit::walk_mod(self, m, n);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(self, check_mod_post, late_passes, m, s, n);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_local(&mut self, l: &'tcx hir::Local) {
|
2016-06-18 04:01:57 +00:00
|
|
|
self.with_lint_attrs(&l.attrs, |cx| {
|
2015-11-03 17:39:51 +01:00
|
|
|
run_lints!(cx, check_local, late_passes, l);
|
|
|
|
hir_visit::walk_local(cx, l);
|
|
|
|
})
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_block(&mut self, b: &'tcx hir::Block) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_block, late_passes, b);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_block(self, b);
|
2016-02-11 05:58:09 +01:00
|
|
|
run_lints!(self, check_block_post, late_passes, b);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_arm, late_passes, a);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_arm(self, a);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_decl(&mut self, d: &'tcx hir::Decl) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_decl, late_passes, d);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_decl(self, d);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_generics, late_passes, g);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_generics(self, g);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
2015-03-10 12:28:44 +02:00
|
|
|
self.with_lint_attrs(&trait_item.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_trait_item, late_passes, trait_item);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_trait_item(cx, trait_item);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(cx, check_trait_item_post, late_passes, trait_item);
|
2015-03-10 12:28:44 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
2015-03-10 12:28:44 +02:00
|
|
|
self.with_lint_attrs(&impl_item.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_impl_item, late_passes, impl_item);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_impl_item(cx, impl_item);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(cx, check_impl_item_post, late_passes, impl_item);
|
2015-03-10 12:28:44 +02:00
|
|
|
});
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
2015-09-29 00:23:54 +03:00
|
|
|
run_lints!(self, check_lifetime, late_passes, lt);
|
Fix lint attributes on non-item nodes.
Currently, late lint checking uses two HIR visitors: LateContext and
IdVisitor. IdVisitor only overrides visit_id, and for each node searches
for builtin lints previously added to the session; LateContext overrides
a number of methods, and runs late lints. When LateContext encounters an
item, it first has IdVisitor walk everything in it except nested items
(OnlyBodies), then recurses into it itself - i.e. there are two separate
walks.
Aside from apparently being unnecessary, this separation prevents lint
attributes (allow/deny/warn) on non-item HIR nodes from working
properly. Test case:
// generates warning without this change
fn main() { #[allow(unreachable_code)] loop { break; break; } }
LateContext contains logic to merge attributes seen into the current lint
settings while walking (with_lint_attrs), but IdVisitor does not. So
such attributes will affect late lints (because they are called from
LateContext), and if the node contains any items within it, they will
affect builtin lints within those items (because that IdVisitor is run
while LateContext is within the attributed node), but otherwise the
attributes will be ignored for builtin lints.
This change simply removes IdVisitor and moves its visit_id into
LateContext itself. Hopefully this doesn't break anything...
Also added walk calls to visit_lifetime and visit_lifetime_def
respectively, so visit_lifetime_def will recurse into the lifetime and
visit_lifetime will recurse into the name. In principle this could
confuse lint plugins. This is "necessary" because walk_lifetime calls
visit_id on the lifetime; of course, an alternative would be directly
calling visit_id (which would require manually iterating over the
lifetimes in visit_lifetime_def), but that seems less clean.
2017-01-03 20:40:29 +01:00
|
|
|
hir_visit::walk_lifetime(self, lt);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_lifetime_def, late_passes, lt);
|
Fix lint attributes on non-item nodes.
Currently, late lint checking uses two HIR visitors: LateContext and
IdVisitor. IdVisitor only overrides visit_id, and for each node searches
for builtin lints previously added to the session; LateContext overrides
a number of methods, and runs late lints. When LateContext encounters an
item, it first has IdVisitor walk everything in it except nested items
(OnlyBodies), then recurses into it itself - i.e. there are two separate
walks.
Aside from apparently being unnecessary, this separation prevents lint
attributes (allow/deny/warn) on non-item HIR nodes from working
properly. Test case:
// generates warning without this change
fn main() { #[allow(unreachable_code)] loop { break; break; } }
LateContext contains logic to merge attributes seen into the current lint
settings while walking (with_lint_attrs), but IdVisitor does not. So
such attributes will affect late lints (because they are called from
LateContext), and if the node contains any items within it, they will
affect builtin lints within those items (because that IdVisitor is run
while LateContext is within the attributed node), but otherwise the
attributes will be ignored for builtin lints.
This change simply removes IdVisitor and moves its visit_id into
LateContext itself. Hopefully this doesn't break anything...
Also added walk calls to visit_lifetime and visit_lifetime_def
respectively, so visit_lifetime_def will recurse into the lifetime and
visit_lifetime will recurse into the name. In principle this could
confuse lint plugins. This is "necessary" because walk_lifetime calls
visit_id on the lifetime; of course, an alternative would be directly
calling visit_id (which would require manually iterating over the
lifetimes in visit_lifetime_def), but that seems less clean.
2017-01-03 20:40:29 +01:00
|
|
|
hir_visit::walk_lifetime_def(self, lt);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:45:26 -05:00
|
|
|
fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_path, late_passes, p, id);
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_path(self, p);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
|
2016-01-13 18:54:06 +00:00
|
|
|
check_lint_name_attribute(self, attr);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_attribute, late_passes, attr);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
|
|
|
|
fn visit_item(&mut self, it: &'a ast::Item) {
|
2015-09-15 17:31:33 +12:00
|
|
|
self.with_lint_attrs(&it.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_item, early_passes, it);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_item(cx, it);
|
2016-02-12 18:21:43 +01:00
|
|
|
run_lints!(cx, check_item_post, early_passes, it);
|
2015-09-10 16:40:59 +12:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
|
2015-09-15 17:31:33 +12:00
|
|
|
self.with_lint_attrs(&it.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_foreign_item, early_passes, it);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_foreign_item(cx, it);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(cx, check_foreign_item_post, early_passes, it);
|
2015-09-10 16:40:59 +12:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_pat(&mut self, p: &'a ast::Pat) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_pat, early_passes, p);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_pat(self, p);
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
2016-06-18 04:01:57 +00:00
|
|
|
self.with_lint_attrs(&e.attrs, |cx| {
|
2015-12-19 23:33:45 +01:00
|
|
|
run_lints!(cx, check_expr, early_passes, e);
|
|
|
|
ast_visit::walk_expr(cx, e);
|
|
|
|
})
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_stmt(&mut self, s: &'a ast::Stmt) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_stmt, early_passes, s);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_stmt(self, s);
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl,
|
2016-10-26 02:17:29 +03:00
|
|
|
span: Span, id: ast::NodeId) {
|
|
|
|
run_lints!(self, check_fn, early_passes, fk, decl, span, id);
|
|
|
|
ast_visit::walk_fn(self, fk, decl, span);
|
|
|
|
run_lints!(self, check_fn_post, early_passes, fk, decl, span, id);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2015-10-08 03:20:57 +03:00
|
|
|
fn visit_variant_data(&mut self,
|
2016-12-06 11:26:52 +01:00
|
|
|
s: &'a ast::VariantData,
|
2015-09-10 16:40:59 +12:00
|
|
|
ident: ast::Ident,
|
2016-12-06 11:26:52 +01:00
|
|
|
g: &'a ast::Generics,
|
2015-10-02 20:06:59 +03:00
|
|
|
item_id: ast::NodeId,
|
|
|
|
_: Span) {
|
2015-10-02 16:14:20 +03:00
|
|
|
run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_struct_def(self, s);
|
2015-10-02 16:14:20 +03:00
|
|
|
run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_struct_field(&mut self, s: &'a ast::StructField) {
|
2016-04-06 11:19:10 +03:00
|
|
|
self.with_lint_attrs(&s.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_struct_field, early_passes, s);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_struct_field(cx, s);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
|
2015-09-15 17:31:33 +12:00
|
|
|
self.with_lint_attrs(&v.node.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_variant, early_passes, v, g);
|
2015-10-02 16:14:20 +03:00
|
|
|
ast_visit::walk_variant(cx, v, g, item_id);
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_variant_post, early_passes, v, g);
|
2015-09-10 16:40:59 +12:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_ty(&mut self, t: &'a ast::Ty) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_ty, early_passes, t);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_ty(self, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_ident, early_passes, sp, id);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, n: ast::NodeId) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_mod, early_passes, m, s, n);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_mod(self, m);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(self, check_mod_post, early_passes, m, s, n);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_local(&mut self, l: &'a ast::Local) {
|
2016-06-18 04:01:57 +00:00
|
|
|
self.with_lint_attrs(&l.attrs, |cx| {
|
2015-12-19 23:33:45 +01:00
|
|
|
run_lints!(cx, check_local, early_passes, l);
|
|
|
|
ast_visit::walk_local(cx, l);
|
|
|
|
})
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_block(&mut self, b: &'a ast::Block) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_block, early_passes, b);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_block(self, b);
|
2016-02-11 05:58:09 +01:00
|
|
|
run_lints!(self, check_block_post, early_passes, b);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_arm(&mut self, a: &'a ast::Arm) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_arm, early_passes, a);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_arm(self, a);
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_expr_post(&mut self, e: &'a ast::Expr) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_expr_post, early_passes, e);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_generics, early_passes, g);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_generics(self, g);
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
|
2015-09-15 17:31:33 +12:00
|
|
|
self.with_lint_attrs(&trait_item.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_trait_item, early_passes, trait_item);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_trait_item(cx, trait_item);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(cx, check_trait_item_post, early_passes, trait_item);
|
2015-09-10 16:40:59 +12:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
|
2015-09-15 17:31:33 +12:00
|
|
|
self.with_lint_attrs(&impl_item.attrs, |cx| {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_impl_item, early_passes, impl_item);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_impl_item(cx, impl_item);
|
2016-02-27 00:21:20 +01:00
|
|
|
run_lints!(cx, check_impl_item_post, early_passes, impl_item);
|
2015-09-10 16:40:59 +12:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
|
2015-09-28 14:26:26 +03:00
|
|
|
run_lints!(self, check_lifetime, early_passes, lt);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_lifetime_def, early_passes, lt);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_path, early_passes, p, id);
|
2015-09-10 16:40:59 +12:00
|
|
|
ast_visit::walk_path(self, p);
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_path_list_item(&mut self, prefix: &'a ast::Path, item: &'a ast::PathListItem) {
|
2015-09-17 15:19:24 +03:00
|
|
|
run_lints!(self, check_path_list_item, early_passes, item);
|
|
|
|
ast_visit::walk_path_list_item(self, prefix, item);
|
2015-09-12 16:10:12 +03:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(self, check_attribute, early_passes, attr);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-12 20:46:59 +00:00
|
|
|
enum CheckLintNameResult {
|
2016-01-13 18:54:06 +00:00
|
|
|
Ok,
|
|
|
|
// Lint doesn't exist
|
|
|
|
NoLint,
|
2016-03-12 20:46:59 +00:00
|
|
|
// The lint is either renamed or removed. This is the warning
|
|
|
|
// message.
|
|
|
|
Warning(String)
|
2016-01-13 18:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks the name of a lint for its existence, and whether it was
|
|
|
|
/// renamed or removed. Generates a DiagnosticBuilder containing a
|
|
|
|
/// warning for renamed and removed lints. This is over both lint
|
|
|
|
/// names from attributes and those passed on the command line. Since
|
|
|
|
/// it emits non-fatal warnings and there are *two* lint passes that
|
|
|
|
/// inspect attributes, this is only run from the late pass to avoid
|
|
|
|
/// printing duplicate warnings.
|
2016-03-12 20:46:59 +00:00
|
|
|
fn check_lint_name(lint_cx: &LintStore,
|
|
|
|
lint_name: &str) -> CheckLintNameResult {
|
2016-01-13 18:54:06 +00:00
|
|
|
match lint_cx.by_name.get(lint_name) {
|
|
|
|
Some(&Renamed(ref new_name, _)) => {
|
2016-03-12 20:46:59 +00:00
|
|
|
CheckLintNameResult::Warning(
|
|
|
|
format!("lint {} has been renamed to {}", lint_name, new_name)
|
|
|
|
)
|
2016-01-13 18:54:06 +00:00
|
|
|
},
|
|
|
|
Some(&Removed(ref reason)) => {
|
2016-03-12 20:46:59 +00:00
|
|
|
CheckLintNameResult::Warning(
|
|
|
|
format!("lint {} has been removed: {}", lint_name, reason)
|
|
|
|
)
|
2016-01-13 18:54:06 +00:00
|
|
|
},
|
|
|
|
None => {
|
|
|
|
match lint_cx.lint_groups.get(lint_name) {
|
|
|
|
None => {
|
|
|
|
CheckLintNameResult::NoLint
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
/* lint group exists */
|
|
|
|
CheckLintNameResult::Ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
/* lint exists */
|
|
|
|
CheckLintNameResult::Ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks the validity of lint names derived from attributes
|
|
|
|
fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) {
|
|
|
|
for result in gather_attr(attr) {
|
|
|
|
match result {
|
|
|
|
Err(_) => {
|
|
|
|
// Malformed lint attr. Reported by with_lint_attrs
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Ok((lint_name, _, span)) => {
|
2016-11-15 04:34:52 +00:00
|
|
|
match check_lint_name(&cx.lints, &lint_name.as_str()) {
|
2016-01-13 18:54:06 +00:00
|
|
|
CheckLintNameResult::Ok => (),
|
2016-03-12 20:46:59 +00:00
|
|
|
CheckLintNameResult::Warning(ref msg) => {
|
|
|
|
cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS,
|
|
|
|
span, msg);
|
2016-01-13 18:54:06 +00:00
|
|
|
}
|
|
|
|
CheckLintNameResult::NoLint => {
|
|
|
|
cx.span_lint(builtin::UNKNOWN_LINTS, span,
|
|
|
|
&format!("unknown lint: `{}`",
|
|
|
|
lint_name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks the validity of lint names derived from the command line
|
|
|
|
fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
|
|
|
|
lint_name: &str, level: Level) {
|
2016-03-12 20:46:59 +00:00
|
|
|
let db = match check_lint_name(lint_cx, lint_name) {
|
2016-01-13 18:54:06 +00:00
|
|
|
CheckLintNameResult::Ok => None,
|
2016-03-12 20:46:59 +00:00
|
|
|
CheckLintNameResult::Warning(ref msg) => {
|
|
|
|
Some(sess.struct_warn(msg))
|
|
|
|
},
|
2016-01-13 18:54:06 +00:00
|
|
|
CheckLintNameResult::NoLint => {
|
|
|
|
Some(sess.struct_err(&format!("unknown lint: `{}`", lint_name)))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(mut db) = db {
|
|
|
|
let msg = format!("requested on the command line with `{} {}`",
|
|
|
|
match level {
|
|
|
|
Level::Allow => "-A",
|
|
|
|
Level::Warn => "-W",
|
|
|
|
Level::Deny => "-D",
|
|
|
|
Level::Forbid => "-F",
|
|
|
|
},
|
|
|
|
lint_name);
|
|
|
|
db.note(&msg);
|
|
|
|
db.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Perform lint checking on a crate.
|
|
|
|
///
|
|
|
|
/// Consumes the `lint_store` field of the `Session`.
|
2016-05-03 05:23:22 +03:00
|
|
|
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
access_levels: &AccessLevels) {
|
2015-12-22 16:35:02 -05:00
|
|
|
let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);
|
|
|
|
|
2017-01-26 02:41:06 +02:00
|
|
|
let krate = tcx.hir.krate();
|
2017-01-06 21:54:24 +02:00
|
|
|
|
|
|
|
// We want to own the lint store, so move it out of the session.
|
|
|
|
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), LintStore::new());
|
|
|
|
let mut cx = LateContext {
|
|
|
|
tcx: tcx,
|
2017-01-25 16:24:00 -05:00
|
|
|
tables: &ty::TypeckTables::empty(),
|
2017-01-06 21:54:24 +02:00
|
|
|
krate: krate,
|
|
|
|
access_levels: access_levels,
|
|
|
|
lints: lint_store,
|
|
|
|
level_stack: vec![],
|
|
|
|
};
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
// Visit the whole crate.
|
2015-02-20 14:08:14 -05:00
|
|
|
cx.with_lint_attrs(&krate.attrs, |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
// since the root module isn't visited as an item (because it isn't an
|
|
|
|
// item), warn for it here.
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_crate, late_passes, krate);
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2015-09-10 16:40:59 +12:00
|
|
|
hir_visit::walk_crate(cx, krate);
|
2016-02-11 05:58:09 +01:00
|
|
|
|
|
|
|
run_lints!(cx, check_crate_post, late_passes, krate);
|
2014-06-06 15:49:48 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// If we missed any lints added to the session, then there's a bug somewhere
|
|
|
|
// in the iteration code.
|
2017-01-28 07:01:45 -05:00
|
|
|
if let Some((id, v)) = tcx.sess.lints.borrow().get_any() {
|
2016-10-06 04:56:13 -04:00
|
|
|
for early_lint in v {
|
2016-10-13 12:08:50 -04:00
|
|
|
span_bug!(early_lint.diagnostic.span.clone(),
|
2016-10-06 04:56:13 -04:00
|
|
|
"unprocessed lint {:?} at {}",
|
2017-01-26 02:41:06 +02:00
|
|
|
early_lint, tcx.hir.node_to_string(*id));
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 18:35:27 +02:00
|
|
|
// Put the lint store back in the session.
|
|
|
|
mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
2015-09-10 16:40:59 +12:00
|
|
|
|
|
|
|
pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
|
|
|
|
let mut cx = EarlyContext::new(sess, krate);
|
|
|
|
|
|
|
|
// Visit the whole crate.
|
2015-09-15 17:31:33 +12:00
|
|
|
cx.with_lint_attrs(&krate.attrs, |cx| {
|
2016-03-29 12:12:01 +03:00
|
|
|
// Lints may be assigned to the whole crate.
|
2017-01-28 07:01:45 -05:00
|
|
|
let lints = cx.sess.lints.borrow_mut().take(ast::CRATE_NODE_ID);
|
|
|
|
for early_lint in lints {
|
2017-01-28 18:13:21 -05:00
|
|
|
cx.early_lint(&early_lint);
|
2016-03-29 12:12:01 +03:00
|
|
|
}
|
2015-09-10 16:40:59 +12:00
|
|
|
|
|
|
|
// since the root module isn't visited as an item (because it isn't an
|
|
|
|
// item), warn for it here.
|
2015-09-15 11:35:25 +12:00
|
|
|
run_lints!(cx, check_crate, early_passes, krate);
|
2015-09-10 16:40:59 +12:00
|
|
|
|
|
|
|
ast_visit::walk_crate(cx, krate);
|
2016-02-11 05:58:09 +01:00
|
|
|
|
|
|
|
run_lints!(cx, check_crate_post, early_passes, krate);
|
2015-09-10 16:40:59 +12:00
|
|
|
});
|
|
|
|
|
|
|
|
// Put the lint store back in the session.
|
|
|
|
mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);
|
|
|
|
|
|
|
|
// If we missed any lints added to the session, then there's a bug somewhere
|
|
|
|
// in the iteration code.
|
2017-01-28 07:01:45 -05:00
|
|
|
for (_, v) in sess.lints.borrow().get_any() {
|
2016-10-06 04:56:13 -04:00
|
|
|
for early_lint in v {
|
2016-10-13 12:08:50 -04:00
|
|
|
span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint);
|
2015-09-10 16:40:59 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-28 18:13:21 -05:00
|
|
|
|
|
|
|
impl Encodable for LintId {
|
|
|
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
|
|
|
s.emit_str(&self.lint.name.to_lowercase())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Decodable for LintId {
|
|
|
|
#[inline]
|
|
|
|
fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> {
|
|
|
|
let s = d.read_str()?;
|
|
|
|
ty::tls::with(|tcx| {
|
|
|
|
match tcx.sess.lint_store.borrow().find_lint(&s, tcx.sess, None) {
|
|
|
|
Ok(id) => Ok(id),
|
|
|
|
Err(_) => panic!("invalid lint-id `{}`", s),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|