1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Implementation of lint checking.
13 //! The lint checking is mostly consolidated into one pass which runs
14 //! after all other analyses. Throughout compilation, lint warnings
15 //! can be added via the `add_lint` method on the Session structure. This
16 //! requires a span and an id of the node that the lint is being added to. The
17 //! lint isn't actually emitted at that time because it is unknown what the
18 //! actual lint level at that location is.
20 //! To actually emit lint warnings/errors, a separate pass is used.
21 //! A context keeps track of the current state of all lint levels.
22 //! Upon entering a node of the ast which can modify the lint settings, the
23 //! previous lint state is pushed onto a stack and the ast is then recursed
24 //! upon. As the ast is traversed, this keeps track of the current lint level
25 //! for all lint attributes.
27 use self::TargetLint::*;
30 use rustc_data_structures::sync::ReadGuard;
31 use lint::{EarlyLintPassObject, LateLintPassObject};
32 use lint::{Level, Lint, LintId, LintPass, LintBuffer};
33 use lint::builtin::BuiltinLintDiagnostics;
34 use lint::levels::{LintLevelSets, LintLevelsBuilder};
35 use middle::privacy::AccessLevels;
36 use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
37 use session::{config, early_error, Session};
38 use ty::{self, TyCtxt, Ty};
39 use ty::layout::{LayoutError, LayoutOf, TyLayout};
40 use util::nodemap::FxHashMap;
42 use std::default::Default as StdDefault;
45 use syntax_pos::{MultiSpan, Span, symbol::LocalInternedString};
46 use errors::DiagnosticBuilder;
48 use hir::def_id::LOCAL_CRATE;
49 use hir::intravisit as hir_visit;
50 use syntax::visit as ast_visit;
52 /// Information about the registered lints.
54 /// This is basically the subset of `Context` that we can
55 /// build early in the compile pipeline.
56 pub struct LintStore {
57 /// Registered lints. The bool is true if the lint was
58 /// added by a plugin.
59 lints: Vec<(&'static Lint, bool)>,
61 /// Trait objects for each lint pass.
62 /// This is only `None` while performing a lint pass.
63 pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
64 early_passes: Option<Vec<EarlyLintPassObject>>,
65 late_passes: Option<Vec<LateLintPassObject>>,
67 /// Lints indexed by name.
68 by_name: FxHashMap<String, TargetLint>,
70 /// Map of registered lint groups to what lints they expand to. The first
71 /// bool is true if the lint group was added by a plugin. The optional string
72 /// is used to store the new names of deprecated lint group names.
73 lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool, Option<&'static str>)>,
75 /// Extra info for future incompatibility lints, describing the
76 /// issue or RFC that caused the incompatibility.
77 future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
80 pub struct LintSession<'a, PassObject> {
81 /// Reference to the store of registered lints.
82 lints: ReadGuard<'a, LintStore>,
84 /// Trait objects for each lint pass.
85 passes: Option<Vec<PassObject>>,
89 /// Lints that are buffered up early on in the `Session` before the
90 /// `LintLevels` is calculated
91 #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
92 pub struct BufferedEarlyLint {
94 pub ast_id: ast::NodeId,
97 pub diagnostic: BuiltinLintDiagnostics,
100 /// Extra information for a future incompatibility lint. See the call
101 /// to `register_future_incompatible` in `librustc_lint/lib.rs` for
103 pub struct FutureIncompatibleInfo {
105 /// e.g., a URL for an issue/PR/RFC or error code
106 pub reference: &'static str,
107 /// If this is an edition fixing lint, the edition in which
108 /// this lint becomes obsolete
109 pub edition: Option<edition::Edition>,
112 /// The target of the `by_name` map, which accounts for renaming/deprecation.
114 /// A direct lint target
117 /// Temporary renaming, used for easing migration pain; see #16545
118 Renamed(String, LintId),
120 /// Lint with this name existed previously, but has been removed/deprecated.
121 /// The string argument is the reason for removal.
125 pub enum FindLintError {
130 pub enum CheckLintNameResult<'a> {
132 /// Lint doesn't exist
134 /// The lint is either renamed or removed. This is the warning
135 /// message, and an optional new name (`None` if removed).
136 Warning(String, Option<String>),
137 /// The lint is from a tool. If the Option is None, then either
138 /// the lint does not exist in the tool or the code was not
139 /// compiled with the tool and therefore the lint was never
140 /// added to the `LintStore`. Otherwise the `LintId` will be
141 /// returned as if it where a rustc lint.
142 Tool(Option<&'a [LintId]>),
146 pub fn new() -> LintStore {
149 pre_expansion_passes: Some(vec![]),
150 early_passes: Some(vec![]),
151 late_passes: Some(vec![]),
152 by_name: FxHashMap(),
153 future_incompatible: FxHashMap(),
154 lint_groups: FxHashMap(),
158 pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
162 pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
163 self.lint_groups.iter().map(|(k, v)| (*k,
168 pub fn register_early_pass(&mut self,
169 sess: Option<&Session>,
171 pass: EarlyLintPassObject) {
172 self.push_pass(sess, from_plugin, &pass);
173 self.early_passes.as_mut().unwrap().push(pass);
176 pub fn register_pre_expansion_pass(
178 sess: Option<&Session>,
179 pass: EarlyLintPassObject,
181 self.push_pass(sess, false, &pass);
182 self.pre_expansion_passes.as_mut().unwrap().push(pass);
185 pub fn register_late_pass(&mut self,
186 sess: Option<&Session>,
188 pass: LateLintPassObject) {
189 self.push_pass(sess, from_plugin, &pass);
190 self.late_passes.as_mut().unwrap().push(pass);
193 // Helper method for register_early/late_pass
194 fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
195 sess: Option<&Session>,
198 for lint in pass.get_lints() {
199 self.lints.push((lint, from_plugin));
201 let id = LintId::of(lint);
202 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
203 let msg = format!("duplicate specification of lint {}", lint.name_lower());
204 match (sess, from_plugin) {
205 // We load builtin lints first, so a duplicate is a compiler bug.
206 // Use early_error when handling -W help with no crate.
207 (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
208 (Some(_), false) => bug!("{}", msg),
210 // A duplicate name from a plugin is a user error.
211 (Some(sess), true) => sess.err(&msg[..]),
217 pub fn register_future_incompatible(&mut self,
218 sess: Option<&Session>,
219 lints: Vec<FutureIncompatibleInfo>) {
221 for edition in edition::ALL_EDITIONS {
222 let lints = lints.iter().filter(|f| f.edition == Some(*edition)).map(|f| f.id)
223 .collect::<Vec<_>>();
224 if !lints.is_empty() {
225 self.register_group(sess, false, edition.lint_name(), None, lints)
229 let mut future_incompatible = Vec::with_capacity(lints.len());
231 future_incompatible.push(lint.id);
232 self.future_incompatible.insert(lint.id, lint);
238 "future_incompatible",
244 pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
245 self.future_incompatible.get(&id)
248 pub fn register_group(
250 sess: Option<&Session>,
253 deprecated_name: Option<&'static str>,
258 .insert(name, (to, from_plugin, None))
260 if let Some(deprecated) = deprecated_name {
262 .insert(deprecated, (vec![], from_plugin, Some(name)));
266 let msg = format!("duplicate specification of lint group {}", name);
267 match (sess, from_plugin) {
268 // We load builtin lints first, so a duplicate is a compiler bug.
269 // Use early_error when handling -W help with no crate.
270 (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
271 (Some(_), false) => bug!("{}", msg),
273 // A duplicate name from a plugin is a user error.
274 (Some(sess), true) => sess.err(&msg[..]),
279 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
280 let target = match self.by_name.get(new_name) {
281 Some(&Id(lint_id)) => lint_id.clone(),
282 _ => bug!("invalid lint renaming of {} to {}", old_name, new_name)
284 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
287 pub fn register_removed(&mut self, name: &str, reason: &str) {
288 self.by_name.insert(name.into(), Removed(reason.into()));
291 pub fn find_lints(&self, lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
292 match self.by_name.get(lint_name) {
293 Some(&Id(lint_id)) => Ok(vec![lint_id]),
294 Some(&Renamed(_, lint_id)) => {
297 Some(&Removed(_)) => {
298 Err(FindLintError::Removed)
301 match self.lint_groups.get(lint_name) {
302 Some(v) => Ok(v.0.clone()),
303 None => Err(FindLintError::Removed)
309 /// Checks the validity of lint names derived from the command line
310 pub fn check_lint_name_cmdline(&self,
314 let db = match self.check_lint_name(lint_name, None) {
315 CheckLintNameResult::Ok(_) => None,
316 CheckLintNameResult::Warning(ref msg, _) => {
317 Some(sess.struct_warn(msg))
319 CheckLintNameResult::NoLint => {
320 Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
322 CheckLintNameResult::Tool(_) => unreachable!(),
325 if let Some(mut db) = db {
326 let msg = format!("requested on the command line with `{} {}`",
328 Level::Allow => "-A",
331 Level::Forbid => "-F",
339 /// Checks the name of a lint for its existence, and whether it was
340 /// renamed or removed. Generates a DiagnosticBuilder containing a
341 /// warning for renamed and removed lints. This is over both lint
342 /// names from attributes and those passed on the command line. Since
343 /// it emits non-fatal warnings and there are *two* lint passes that
344 /// inspect attributes, this is only run from the late pass to avoid
345 /// printing duplicate warnings.
346 pub fn check_lint_name(
349 tool_name: Option<LocalInternedString>,
350 ) -> CheckLintNameResult {
351 let complete_name = if let Some(tool_name) = tool_name {
352 format!("{}::{}", tool_name, lint_name)
354 lint_name.to_string()
356 if let Some(_) = tool_name {
357 match self.by_name.get(&complete_name) {
358 None => match self.lint_groups.get(&*complete_name) {
359 None => return CheckLintNameResult::Tool(None),
360 Some(ids) => return CheckLintNameResult::Tool(Some(&ids.0)),
362 Some(&Id(ref id)) => return CheckLintNameResult::Tool(Some(slice::from_ref(id))),
363 // If the lint was registered as removed or renamed by the lint tool, we don't need
364 // to treat tool_lints and rustc lints different and can use the code below.
368 match self.by_name.get(&complete_name) {
369 Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
370 format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
371 Some(new_name.to_owned()),
373 Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
374 format!("lint `{}` has been removed: `{}`", lint_name, reason),
377 None => match self.lint_groups.get(&*complete_name) {
378 None => CheckLintNameResult::NoLint,
379 Some(ids) => CheckLintNameResult::Ok(&ids.0),
381 Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
386 /// Context for lint checking after type checking.
387 pub struct LateContext<'a, 'tcx: 'a> {
388 /// Type context we're checking in.
389 pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
391 /// Side-tables for the body we are in.
392 pub tables: &'a ty::TypeckTables<'tcx>,
394 /// Parameter environment for the item we are in.
395 pub param_env: ty::ParamEnv<'tcx>,
397 /// Items accessible from the crate being checked.
398 pub access_levels: &'a AccessLevels,
400 /// The store of registered lints and the lint levels.
401 lint_sess: LintSession<'tcx, LateLintPassObject>,
403 last_ast_node_with_lint_attrs: ast::NodeId,
405 /// Generic type parameters in scope for the item we are in.
406 pub generics: Option<&'tcx hir::Generics>,
409 /// Context for lint checking of the AST, after expansion, before lowering to
411 pub struct EarlyContext<'a> {
412 /// Type context we're checking in.
413 pub sess: &'a Session,
415 /// The crate being checked.
416 pub krate: &'a ast::Crate,
418 builder: LintLevelsBuilder<'a>,
420 /// The store of registered lints and the lint levels.
421 lint_sess: LintSession<'a, EarlyLintPassObject>,
423 buffered: LintBuffer,
426 /// Convenience macro for calling a `LintPass` method on every pass in the context.
427 macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
428 // Move the vector of passes out of `$cx` so that we can
429 // iterate over it mutably while passing `$cx` to the methods.
430 let mut passes = $cx.lint_sess_mut().passes.take().unwrap();
431 for obj in &mut passes {
432 obj.$f($cx, $($args),*);
434 $cx.lint_sess_mut().passes = Some(passes);
437 pub trait LintPassObject: Sized {}
439 impl LintPassObject for EarlyLintPassObject {}
441 impl LintPassObject for LateLintPassObject {}
444 pub trait LintContext<'tcx>: Sized {
445 type PassObject: LintPassObject;
447 fn sess(&self) -> &Session;
448 fn lints(&self) -> &LintStore;
449 fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject>;
450 fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject>;
451 fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
452 fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
454 fn lookup_and_emit<S: Into<MultiSpan>>(&self,
458 self.lookup(lint, span, msg).emit();
461 fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
465 diagnostic: BuiltinLintDiagnostics) {
466 let mut db = self.lookup(lint, span, msg);
467 diagnostic.run(self.sess(), &mut db);
471 fn lookup<S: Into<MultiSpan>>(&self,
475 -> DiagnosticBuilder;
477 /// Emit a lint at the appropriate level, for a particular span.
478 fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
479 self.lookup_and_emit(lint, Some(span), msg);
482 fn struct_span_lint<S: Into<MultiSpan>>(&self,
486 -> DiagnosticBuilder {
487 self.lookup(lint, Some(span), msg)
490 /// Emit a lint and note at the appropriate level, for a particular span.
491 fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
492 note_span: Span, note: &str) {
493 let mut err = self.lookup(lint, Some(span), msg);
494 if note_span == span {
497 err.span_note(note_span, note);
502 /// Emit a lint and help at the appropriate level, for a particular span.
503 fn span_lint_help(&self, lint: &'static Lint, span: Span,
504 msg: &str, help: &str) {
505 let mut err = self.lookup(lint, Some(span), msg);
506 self.span_lint(lint, span, msg);
507 err.span_help(span, help);
511 /// Emit a lint at the appropriate level, with no associated span.
512 fn lint(&self, lint: &'static Lint, msg: &str) {
513 self.lookup_and_emit(lint, None as Option<Span>, msg);
516 /// Merge the lints specified by any lint attributes into the
517 /// current lint context, call the provided function, then reset the
518 /// lints in effect to their previous state.
519 fn with_lint_attrs<F>(&mut self,
521 attrs: &'tcx [ast::Attribute],
523 where F: FnOnce(&mut Self);
527 impl<'a> EarlyContext<'a> {
530 krate: &'a ast::Crate,
531 passes: Option<Vec<EarlyLintPassObject>>,
532 buffered: LintBuffer,
533 ) -> EarlyContext<'a> {
537 lint_sess: LintSession {
538 lints: sess.lint_store.borrow(),
541 builder: LintLevelSets::builder(sess),
546 fn check_id(&mut self, id: ast::NodeId) {
547 for early_lint in self.buffered.take(id) {
548 self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint,
549 Some(early_lint.span.clone()),
551 early_lint.diagnostic);
556 impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> {
557 type PassObject = LateLintPassObject;
559 /// Get the overall compiler `Session` object.
560 fn sess(&self) -> &Session {
564 fn lints(&self) -> &LintStore {
565 &*self.lint_sess.lints
568 fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject> {
572 fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject> {
576 fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
577 debug!("late context: enter_attrs({:?})", attrs);
578 run_lints!(self, enter_lint_attrs, attrs);
581 fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
582 debug!("late context: exit_attrs({:?})", attrs);
583 run_lints!(self, exit_lint_attrs, attrs);
586 fn lookup<S: Into<MultiSpan>>(&self,
590 -> DiagnosticBuilder {
591 let id = self.last_ast_node_with_lint_attrs;
593 Some(s) => self.tcx.struct_span_lint_node(lint, id, s, msg),
594 None => self.tcx.struct_lint_node(lint, id, msg),
598 fn with_lint_attrs<F>(&mut self,
600 attrs: &'tcx [ast::Attribute],
602 where F: FnOnce(&mut Self)
604 let prev = self.last_ast_node_with_lint_attrs;
605 self.last_ast_node_with_lint_attrs = id;
606 self.enter_attrs(attrs);
608 self.exit_attrs(attrs);
609 self.last_ast_node_with_lint_attrs = prev;
613 impl<'a> LintContext<'a> for EarlyContext<'a> {
614 type PassObject = EarlyLintPassObject;
616 /// Get the overall compiler `Session` object.
617 fn sess(&self) -> &Session {
621 fn lints(&self) -> &LintStore {
622 &*self.lint_sess.lints
625 fn lint_sess(&self) -> &LintSession<'a, Self::PassObject> {
629 fn lint_sess_mut(&mut self) -> &mut LintSession<'a, Self::PassObject> {
633 fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) {
634 debug!("early context: enter_attrs({:?})", attrs);
635 run_lints!(self, enter_lint_attrs, attrs);
638 fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) {
639 debug!("early context: exit_attrs({:?})", attrs);
640 run_lints!(self, exit_lint_attrs, attrs);
643 fn lookup<S: Into<MultiSpan>>(&self,
647 -> DiagnosticBuilder {
648 self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
651 fn with_lint_attrs<F>(&mut self,
653 attrs: &'a [ast::Attribute],
655 where F: FnOnce(&mut Self)
657 let push = self.builder.push(attrs);
659 self.enter_attrs(attrs);
661 self.exit_attrs(attrs);
662 self.builder.pop(push);
666 impl<'a, 'tcx> LateContext<'a, 'tcx> {
667 fn with_param_env<F>(&mut self, id: ast::NodeId, f: F)
668 where F: FnOnce(&mut Self),
670 let old_param_env = self.param_env;
671 self.param_env = self.tcx.param_env(self.tcx.hir.local_def_id(id));
673 self.param_env = old_param_env;
675 pub fn current_lint_root(&self) -> ast::NodeId {
676 self.last_ast_node_with_lint_attrs
680 impl<'a, 'tcx> LayoutOf for &'a LateContext<'a, 'tcx> {
682 type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
684 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
685 self.tcx.layout_of(self.param_env.and(ty))
689 impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
690 /// Because lints are scoped lexically, we want to walk nested
691 /// items in the context of the outer item, so enable
693 fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
694 hir_visit::NestedVisitorMap::All(&self.tcx.hir)
697 fn visit_nested_body(&mut self, body: hir::BodyId) {
698 let old_tables = self.tables;
699 self.tables = self.tcx.body_tables(body);
700 let body = self.tcx.hir.body(body);
701 self.visit_body(body);
702 self.tables = old_tables;
705 fn visit_body(&mut self, body: &'tcx hir::Body) {
706 run_lints!(self, check_body, body);
707 hir_visit::walk_body(self, body);
708 run_lints!(self, check_body_post, body);
711 fn visit_item(&mut self, it: &'tcx hir::Item) {
712 let generics = self.generics.take();
713 self.generics = it.node.generics();
714 self.with_lint_attrs(it.id, &it.attrs, |cx| {
715 cx.with_param_env(it.id, |cx| {
716 run_lints!(cx, check_item, it);
717 hir_visit::walk_item(cx, it);
718 run_lints!(cx, check_item_post, it);
721 self.generics = generics;
724 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
725 self.with_lint_attrs(it.id, &it.attrs, |cx| {
726 cx.with_param_env(it.id, |cx| {
727 run_lints!(cx, check_foreign_item, it);
728 hir_visit::walk_foreign_item(cx, it);
729 run_lints!(cx, check_foreign_item_post, it);
734 fn visit_pat(&mut self, p: &'tcx hir::Pat) {
735 run_lints!(self, check_pat, p);
736 hir_visit::walk_pat(self, p);
739 fn visit_expr(&mut self, e: &'tcx hir::Expr) {
740 self.with_lint_attrs(e.id, &e.attrs, |cx| {
741 run_lints!(cx, check_expr, e);
742 hir_visit::walk_expr(cx, e);
743 run_lints!(cx, check_expr_post, e);
747 fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
748 // statement attributes are actually just attributes on one of
752 // so we keep track of lint levels there
753 run_lints!(self, check_stmt, s);
754 hir_visit::walk_stmt(self, s);
757 fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
758 body_id: hir::BodyId, span: Span, id: ast::NodeId) {
759 // Wrap in tables here, not just in visit_nested_body,
760 // in order for `check_fn` to be able to use them.
761 let old_tables = self.tables;
762 self.tables = self.tcx.body_tables(body_id);
763 let body = self.tcx.hir.body(body_id);
764 run_lints!(self, check_fn, fk, decl, body, span, id);
765 hir_visit::walk_fn(self, fk, decl, body_id, span, id);
766 run_lints!(self, check_fn_post, fk, decl, body, span, id);
767 self.tables = old_tables;
770 fn visit_variant_data(&mut self,
771 s: &'tcx hir::VariantData,
773 g: &'tcx hir::Generics,
774 item_id: ast::NodeId,
776 run_lints!(self, check_struct_def, s, name, g, item_id);
777 hir_visit::walk_struct_def(self, s);
778 run_lints!(self, check_struct_def_post, s, name, g, item_id);
781 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
782 self.with_lint_attrs(s.id, &s.attrs, |cx| {
783 run_lints!(cx, check_struct_field, s);
784 hir_visit::walk_struct_field(cx, s);
788 fn visit_variant(&mut self,
789 v: &'tcx hir::Variant,
790 g: &'tcx hir::Generics,
791 item_id: ast::NodeId) {
792 self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |cx| {
793 run_lints!(cx, check_variant, v, g);
794 hir_visit::walk_variant(cx, v, g, item_id);
795 run_lints!(cx, check_variant_post, v, g);
799 fn visit_ty(&mut self, t: &'tcx hir::Ty) {
800 run_lints!(self, check_ty, t);
801 hir_visit::walk_ty(self, t);
804 fn visit_name(&mut self, sp: Span, name: ast::Name) {
805 run_lints!(self, check_name, sp, name);
808 fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
809 run_lints!(self, check_mod, m, s, n);
810 hir_visit::walk_mod(self, m, n);
811 run_lints!(self, check_mod_post, m, s, n);
814 fn visit_local(&mut self, l: &'tcx hir::Local) {
815 self.with_lint_attrs(l.id, &l.attrs, |cx| {
816 run_lints!(cx, check_local, l);
817 hir_visit::walk_local(cx, l);
821 fn visit_block(&mut self, b: &'tcx hir::Block) {
822 run_lints!(self, check_block, b);
823 hir_visit::walk_block(self, b);
824 run_lints!(self, check_block_post, b);
827 fn visit_arm(&mut self, a: &'tcx hir::Arm) {
828 run_lints!(self, check_arm, a);
829 hir_visit::walk_arm(self, a);
832 fn visit_decl(&mut self, d: &'tcx hir::Decl) {
833 run_lints!(self, check_decl, d);
834 hir_visit::walk_decl(self, d);
837 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
838 run_lints!(self, check_generic_param, p);
839 hir_visit::walk_generic_param(self, p);
842 fn visit_generics(&mut self, g: &'tcx hir::Generics) {
843 run_lints!(self, check_generics, g);
844 hir_visit::walk_generics(self, g);
847 fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) {
848 run_lints!(self, check_where_predicate, p);
849 hir_visit::walk_where_predicate(self, p);
852 fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef,
853 m: hir::TraitBoundModifier) {
854 run_lints!(self, check_poly_trait_ref, t, m);
855 hir_visit::walk_poly_trait_ref(self, t, m);
858 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
859 let generics = self.generics.take();
860 self.generics = Some(&trait_item.generics);
861 self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
862 cx.with_param_env(trait_item.id, |cx| {
863 run_lints!(cx, check_trait_item, trait_item);
864 hir_visit::walk_trait_item(cx, trait_item);
865 run_lints!(cx, check_trait_item_post, trait_item);
868 self.generics = generics;
871 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
872 let generics = self.generics.take();
873 self.generics = Some(&impl_item.generics);
874 self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
875 cx.with_param_env(impl_item.id, |cx| {
876 run_lints!(cx, check_impl_item, impl_item);
877 hir_visit::walk_impl_item(cx, impl_item);
878 run_lints!(cx, check_impl_item_post, impl_item);
881 self.generics = generics;
884 fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
885 run_lints!(self, check_lifetime, lt);
886 hir_visit::walk_lifetime(self, lt);
889 fn visit_path(&mut self, p: &'tcx hir::Path, id: hir::HirId) {
890 run_lints!(self, check_path, p, id);
891 hir_visit::walk_path(self, p);
894 fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
895 run_lints!(self, check_attribute, attr);
899 impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
900 fn visit_item(&mut self, it: &'a ast::Item) {
901 self.with_lint_attrs(it.id, &it.attrs, |cx| {
902 run_lints!(cx, check_item, it);
903 ast_visit::walk_item(cx, it);
904 run_lints!(cx, check_item_post, it);
908 fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
909 self.with_lint_attrs(it.id, &it.attrs, |cx| {
910 run_lints!(cx, check_foreign_item, it);
911 ast_visit::walk_foreign_item(cx, it);
912 run_lints!(cx, check_foreign_item_post, it);
916 fn visit_pat(&mut self, p: &'a ast::Pat) {
917 run_lints!(self, check_pat, p);
919 ast_visit::walk_pat(self, p);
922 fn visit_expr(&mut self, e: &'a ast::Expr) {
923 self.with_lint_attrs(e.id, &e.attrs, |cx| {
924 run_lints!(cx, check_expr, e);
925 ast_visit::walk_expr(cx, e);
929 fn visit_stmt(&mut self, s: &'a ast::Stmt) {
930 run_lints!(self, check_stmt, s);
932 ast_visit::walk_stmt(self, s);
935 fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl,
936 span: Span, id: ast::NodeId) {
937 run_lints!(self, check_fn, fk, decl, span, id);
939 ast_visit::walk_fn(self, fk, decl, span);
940 run_lints!(self, check_fn_post, fk, decl, span, id);
943 fn visit_variant_data(&mut self,
944 s: &'a ast::VariantData,
946 g: &'a ast::Generics,
947 item_id: ast::NodeId,
949 run_lints!(self, check_struct_def, s, ident, g, item_id);
950 self.check_id(s.id());
951 ast_visit::walk_struct_def(self, s);
952 run_lints!(self, check_struct_def_post, s, ident, g, item_id);
955 fn visit_struct_field(&mut self, s: &'a ast::StructField) {
956 self.with_lint_attrs(s.id, &s.attrs, |cx| {
957 run_lints!(cx, check_struct_field, s);
958 ast_visit::walk_struct_field(cx, s);
962 fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
963 self.with_lint_attrs(item_id, &v.node.attrs, |cx| {
964 run_lints!(cx, check_variant, v, g);
965 ast_visit::walk_variant(cx, v, g, item_id);
966 run_lints!(cx, check_variant_post, v, g);
970 fn visit_ty(&mut self, t: &'a ast::Ty) {
971 run_lints!(self, check_ty, t);
973 ast_visit::walk_ty(self, t);
976 fn visit_ident(&mut self, ident: ast::Ident) {
977 run_lints!(self, check_ident, ident);
980 fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
981 run_lints!(self, check_mod, m, s, n);
983 ast_visit::walk_mod(self, m);
984 run_lints!(self, check_mod_post, m, s, n);
987 fn visit_local(&mut self, l: &'a ast::Local) {
988 self.with_lint_attrs(l.id, &l.attrs, |cx| {
989 run_lints!(cx, check_local, l);
990 ast_visit::walk_local(cx, l);
994 fn visit_block(&mut self, b: &'a ast::Block) {
995 run_lints!(self, check_block, b);
997 ast_visit::walk_block(self, b);
998 run_lints!(self, check_block_post, b);
1001 fn visit_arm(&mut self, a: &'a ast::Arm) {
1002 run_lints!(self, check_arm, a);
1003 ast_visit::walk_arm(self, a);
1006 fn visit_expr_post(&mut self, e: &'a ast::Expr) {
1007 run_lints!(self, check_expr_post, e);
1010 fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
1011 run_lints!(self, check_generic_param, param);
1012 ast_visit::walk_generic_param(self, param);
1015 fn visit_generics(&mut self, g: &'a ast::Generics) {
1016 run_lints!(self, check_generics, g);
1017 ast_visit::walk_generics(self, g);
1020 fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
1021 run_lints!(self, check_where_predicate, p);
1022 ast_visit::walk_where_predicate(self, p);
1025 fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
1026 run_lints!(self, check_poly_trait_ref, t, m);
1027 ast_visit::walk_poly_trait_ref(self, t, m);
1030 fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
1031 self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
1032 run_lints!(cx, check_trait_item, trait_item);
1033 ast_visit::walk_trait_item(cx, trait_item);
1034 run_lints!(cx, check_trait_item_post, trait_item);
1038 fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
1039 self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
1040 run_lints!(cx, check_impl_item, impl_item);
1041 ast_visit::walk_impl_item(cx, impl_item);
1042 run_lints!(cx, check_impl_item_post, impl_item);
1046 fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
1047 run_lints!(self, check_lifetime, lt);
1048 self.check_id(lt.id);
1051 fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
1052 run_lints!(self, check_path, p, id);
1054 ast_visit::walk_path(self, p);
1057 fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
1058 run_lints!(self, check_attribute, attr);
1061 fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) {
1062 run_lints!(self, check_mac_def, mac, id);
1066 fn visit_mac(&mut self, mac: &'a ast::Mac) {
1067 run_lints!(self, check_mac, mac);
1072 /// Perform lint checking on a crate.
1074 /// Consumes the `lint_store` field of the `Session`.
1075 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1076 let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1078 let krate = tcx.hir.krate();
1079 let passes = tcx.sess.lint_store.borrow_mut().late_passes.take();
1082 let mut cx = LateContext {
1084 tables: &ty::TypeckTables::empty(None),
1085 param_env: ty::ParamEnv::empty(),
1087 lint_sess: LintSession {
1089 lints: tcx.sess.lint_store.borrow(),
1091 last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID,
1095 // Visit the whole crate.
1096 cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
1097 // since the root module isn't visited as an item (because it isn't an
1098 // item), warn for it here.
1099 run_lints!(cx, check_crate, krate);
1101 hir_visit::walk_crate(cx, krate);
1103 run_lints!(cx, check_crate_post, krate);
1108 // Put the lint store levels and passes back in the session.
1109 tcx.sess.lint_store.borrow_mut().late_passes = passes;
1112 pub fn check_ast_crate(
1115 pre_expansion: bool,
1117 let (passes, buffered) = if pre_expansion {
1119 sess.lint_store.borrow_mut().pre_expansion_passes.take(),
1124 sess.lint_store.borrow_mut().early_passes.take(),
1125 sess.buffered_lints.borrow_mut().take().unwrap(),
1128 let (passes, buffered) = {
1129 let mut cx = EarlyContext::new(sess, krate, passes, buffered);
1131 // Visit the whole crate.
1132 cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
1133 // since the root module isn't visited as an item (because it isn't an
1134 // item), warn for it here.
1135 run_lints!(cx, check_crate, krate);
1137 ast_visit::walk_crate(cx, krate);
1139 run_lints!(cx, check_crate_post, krate);
1141 (cx.lint_sess.passes, cx.buffered)
1144 // Put the lint store levels and passes back in the session.
1146 sess.lint_store.borrow_mut().pre_expansion_passes = passes;
1148 sess.lint_store.borrow_mut().early_passes = passes;
1151 // All of the buffered lints should have been emitted at this point.
1152 // If not, that means that we somehow buffered a lint for a node id
1153 // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
1155 // Rustdoc runs everybody-loops before the early lints and removes
1156 // function bodies, so it's totally possible for linted
1157 // node ids to not exist (e.g. macros defined within functions for the
1158 // unused_macro lint) anymore. So we only run this check
1159 // when we're not in rustdoc mode. (see issue #47639)
1160 if !sess.opts.actually_rustdoc {
1161 for (_id, lints) in buffered.map {
1162 for early_lint in lints {
1163 sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
1169 impl Encodable for LintId {
1170 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
1171 s.emit_str(&self.lint.name.to_lowercase())
1175 impl Decodable for LintId {
1177 fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> {
1178 let s = d.read_str()?;
1179 ty::tls::with(|tcx| {
1180 match tcx.sess.lint_store.borrow().find_lints(&s) {
1183 panic!("invalid lint-id `{}`", s);
1187 Err(_) => panic!("invalid lint-id `{}`", s),