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 just
14 //! before translation to LLVM bytecode. 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 just before
21 //! translation. 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.
26 use self::TargetLint
::*;
28 use middle
::privacy
::AccessLevels
;
29 use middle
::ty
::{self, Ty}
;
30 use session
::{early_error, Session}
;
31 use lint
::{Level, LevelSource, Lint, LintId, LintArray, LintPass}
;
32 use lint
::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject}
;
33 use lint
::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}
;
35 use util
::nodemap
::FnvHashMap
;
37 use std
::cell
::RefCell
;
40 use syntax
::ast_util
::{self, IdVisitingOperation}
;
41 use syntax
::attr
::{self, AttrMetaMethods}
;
42 use syntax
::codemap
::Span
;
43 use syntax
::parse
::token
::InternedString
;
45 use syntax
::attr
::ThinAttributesExt
;
47 use rustc_front
::util
;
48 use rustc_front
::intravisit
as hir_visit
;
49 use syntax
::visit
as ast_visit
;
50 use syntax
::diagnostic
;
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 iterating over the objects. See the definition
64 early_passes
: Option
<Vec
<EarlyLintPassObject
>>,
65 late_passes
: Option
<Vec
<LateLintPassObject
>>,
67 /// Lints indexed by name.
68 by_name
: FnvHashMap
<String
, TargetLint
>,
70 /// Current levels of each lint, and where they were set.
71 levels
: FnvHashMap
<LintId
, LevelSource
>,
73 /// Map of registered lint groups to what lints they expand to. The bool
74 /// is true if the lint group was added by a plugin.
75 lint_groups
: FnvHashMap
<&'
static str, (Vec
<LintId
>, bool
)>,
77 /// Maximum level a lint can be
78 lint_cap
: Option
<Level
>,
81 /// The targed of the `by_name` map, which accounts for renaming/deprecation.
83 /// A direct lint target
86 /// Temporary renaming, used for easing migration pain; see #16545
87 Renamed(String
, LintId
),
89 /// Lint with this name existed previously, but has been removed/deprecated.
90 /// The string argument is the reason for removal.
100 fn get_level_source(&self, lint
: LintId
) -> LevelSource
{
101 match self.levels
.get(&lint
) {
103 None
=> (Allow
, Default
),
107 fn set_level(&mut self, lint
: LintId
, mut lvlsrc
: LevelSource
) {
108 if let Some(cap
) = self.lint_cap
{
109 lvlsrc
.0 = cmp
::min(lvlsrc
.0, cap
);
111 if lvlsrc
.0 == Allow
{
112 self.levels
.remove(&lint
);
114 self.levels
.insert(lint
, lvlsrc
);
118 pub fn new() -> LintStore
{
121 early_passes
: Some(vec
!()),
122 late_passes
: Some(vec
!()),
123 by_name
: FnvHashMap(),
124 levels
: FnvHashMap(),
125 lint_groups
: FnvHashMap(),
130 pub fn get_lints
<'t
>(&'t
self) -> &'t
[(&'
static Lint
, bool
)] {
134 pub fn get_lint_groups
<'t
>(&'t
self) -> Vec
<(&'
static str, Vec
<LintId
>, bool
)> {
135 self.lint_groups
.iter().map(|(k
, v
)| (*k
,
140 pub fn register_early_pass(&mut self,
141 sess
: Option
<&Session
>,
143 pass
: EarlyLintPassObject
) {
144 self.push_pass(sess
, from_plugin
, &pass
);
145 self.early_passes
.as_mut().unwrap().push(pass
);
148 pub fn register_late_pass(&mut self,
149 sess
: Option
<&Session
>,
151 pass
: LateLintPassObject
) {
152 self.push_pass(sess
, from_plugin
, &pass
);
153 self.late_passes
.as_mut().unwrap().push(pass
);
156 // Helper method for register_early/late_pass
157 fn push_pass
<P
: LintPass
+ ?Sized
+ '
static>(&mut self,
158 sess
: Option
<&Session
>,
161 for &lint
in pass
.get_lints() {
162 self.lints
.push((*lint
, from_plugin
));
164 let id
= LintId
::of(*lint
);
165 if self.by_name
.insert(lint
.name_lower(), Id(id
)).is_some() {
166 let msg
= format
!("duplicate specification of lint {}", lint
.name_lower());
167 match (sess
, from_plugin
) {
168 // We load builtin lints first, so a duplicate is a compiler bug.
169 // Use early_error when handling -W help with no crate.
170 (None
, _
) => early_error(diagnostic
::Auto
, &msg
[..]),
171 (Some(sess
), false) => sess
.bug(&msg
[..]),
173 // A duplicate name from a plugin is a user error.
174 (Some(sess
), true) => sess
.err(&msg
[..]),
178 if lint
.default_level
!= Allow
{
179 self.levels
.insert(id
, (lint
.default_level
, Default
));
184 pub fn register_group(&mut self, sess
: Option
<&Session
>,
185 from_plugin
: bool
, name
: &'
static str,
187 let new
= self.lint_groups
.insert(name
, (to
, from_plugin
)).is_none();
190 let msg
= format
!("duplicate specification of lint group {}", name
);
191 match (sess
, from_plugin
) {
192 // We load builtin lints first, so a duplicate is a compiler bug.
193 // Use early_error when handling -W help with no crate.
194 (None
, _
) => early_error(diagnostic
::Auto
, &msg
[..]),
195 (Some(sess
), false) => sess
.bug(&msg
[..]),
197 // A duplicate name from a plugin is a user error.
198 (Some(sess
), true) => sess
.err(&msg
[..]),
203 pub fn register_renamed(&mut self, old_name
: &str, new_name
: &str) {
204 let target
= match self.by_name
.get(new_name
) {
205 Some(&Id(lint_id
)) => lint_id
.clone(),
206 _
=> panic
!("invalid lint renaming of {} to {}", old_name
, new_name
)
208 self.by_name
.insert(old_name
.to_string(), Renamed(new_name
.to_string(), target
));
211 pub fn register_removed(&mut self, name
: &str, reason
: &str) {
212 self.by_name
.insert(name
.into(), Removed(reason
.into()));
215 #[allow(unused_variables)]
216 fn find_lint(&self, lint_name
: &str, sess
: &Session
, span
: Option
<Span
>)
217 -> Result
<LintId
, FindLintError
>
219 match self.by_name
.get(lint_name
) {
220 Some(&Id(lint_id
)) => Ok(lint_id
),
221 Some(&Renamed(_
, lint_id
)) => {
224 Some(&Removed(ref reason
)) => {
225 Err(FindLintError
::Removed
)
227 None
=> Err(FindLintError
::NotFound
)
231 pub fn process_command_line(&mut self, sess
: &Session
) {
232 for &(ref lint_name
, level
) in &sess
.opts
.lint_opts
{
233 check_lint_name_cmdline(sess
, self,
234 &lint_name
[..], level
);
236 match self.find_lint(&lint_name
[..], sess
, None
) {
237 Ok(lint_id
) => self.set_level(lint_id
, (level
, CommandLine
)),
238 Err(FindLintError
::Removed
) => { }
240 match self.lint_groups
.iter().map(|(&x
, pair
)| (x
, pair
.0.clone()))
241 .collect
::<FnvHashMap
<&'
static str,
243 .get(&lint_name
[..]) {
246 .map(|lint_id
: &LintId
|
247 self.set_level(*lint_id
, (level
, CommandLine
)))
248 .collect
::<Vec
<()>>();
251 // The lint or lint group doesn't exist.
252 // This is an error, but it was handled
253 // by check_lint_name_cmdline.
260 self.lint_cap
= sess
.opts
.lint_cap
;
261 if let Some(cap
) = self.lint_cap
{
262 for level
in self.levels
.iter_mut().map(|p
| &mut (p
.1).0) {
263 *level
= cmp
::min(*level
, cap
);
269 /// Context for lint checking after type checking.
270 pub struct LateContext
<'a
, 'tcx
: 'a
> {
271 /// Type context we're checking in.
272 pub tcx
: &'a ty
::ctxt
<'tcx
>,
274 /// The crate being checked.
275 pub krate
: &'a hir
::Crate
,
277 /// Items accessible from the crate being checked.
278 pub access_levels
: &'a AccessLevels
,
280 /// The store of registered lints.
283 /// When recursing into an attributed node of the ast which modifies lint
284 /// levels, this stack keeps track of the previous lint levels of whatever
286 level_stack
: Vec
<(LintId
, LevelSource
)>,
288 /// Level of lints for certain NodeIds, stored here because the body of
289 /// the lint needs to run in trans.
290 node_levels
: RefCell
<FnvHashMap
<(ast
::NodeId
, LintId
), LevelSource
>>,
293 /// Context for lint checking of the AST, after expansion, before lowering to
295 pub struct EarlyContext
<'a
> {
296 /// Type context we're checking in.
297 pub sess
: &'a Session
,
299 /// The crate being checked.
300 pub krate
: &'a ast
::Crate
,
302 /// The store of registered lints.
305 /// When recursing into an attributed node of the ast which modifies lint
306 /// levels, this stack keeps track of the previous lint levels of whatever
308 level_stack
: Vec
<(LintId
, LevelSource
)>,
311 /// Convenience macro for calling a `LintPass` method on every pass in the context.
312 macro_rules
! run_lints
{ ($cx
:expr
, $f
:ident
, $ps
:ident
, $
($args
:expr
),*) => ({
313 // Move the vector of passes out of `$cx` so that we can
314 // iterate over it mutably while passing `$cx` to the methods.
315 let mut passes
= $cx
.mut_lints().$ps
.take().unwrap();
316 for obj
in &mut passes
{
317 obj
.$
f($cx
, $
($args
),*);
319 $cx
.mut_lints().$ps
= Some(passes
);
322 /// Parse the lint attributes into a vector, with `Err`s for malformed lint
323 /// attributes. Writing this as an iterator is an enormous mess.
324 // See also the hir version just below.
325 pub fn gather_attrs(attrs
: &[ast
::Attribute
])
326 -> Vec
<Result
<(InternedString
, Level
, Span
), Span
>> {
327 let mut out
= vec
!();
329 let r
= gather_attr(attr
);
330 out
.extend(r
.into_iter());
335 pub fn gather_attr(attr
: &ast
::Attribute
)
336 -> Vec
<Result
<(InternedString
, Level
, Span
), Span
>> {
337 let mut out
= vec
!();
339 let level
= match Level
::from_str(&attr
.name()) {
344 attr
::mark_used(attr
);
346 let meta
= &attr
.node
.value
;
347 let metas
= match meta
.node
{
348 ast
::MetaList(_
, ref metas
) => metas
,
350 out
.push(Err(meta
.span
));
356 out
.push(match meta
.node
{
357 ast
::MetaWord(ref lint_name
) => Ok((lint_name
.clone(), level
, meta
.span
)),
365 /// Emit a lint as a warning or an error (or not at all)
366 /// according to `level`.
368 /// This lives outside of `Context` so it can be used by checks
369 /// in trans that run after the main lint pass is finished. Most
370 /// lints elsewhere in the compiler should call
371 /// `Session::add_lint()` instead.
372 pub fn raw_emit_lint(sess
: &Session
,
378 let (mut level
, source
) = lvlsrc
;
379 if level
== Allow { return }
381 let name
= lint
.name_lower();
383 let msg
= match source
{
385 format
!("{}, #[{}({})] on by default", msg
,
386 level
.as_str(), name
)
389 format
!("{} [-{} {}]", msg
,
391 Warn
=> 'W'
, Deny
=> 'D'
, Forbid
=> 'F'
,
393 }, name
.replace("_", "-"))
401 // For purposes of printing, we can treat forbid as deny.
402 if level
== Forbid { level = Deny; }
404 match (level
, span
) {
405 (Warn
, Some(sp
)) => sess
.span_warn(sp
, &msg
[..]),
406 (Warn
, None
) => sess
.warn(&msg
[..]),
407 (Deny
, Some(sp
)) => sess
.span_err(sp
, &msg
[..]),
408 (Deny
, None
) => sess
.err(&msg
[..]),
409 _
=> sess
.bug("impossible level in raw_emit_lint"),
412 // Check for future incompatibility lints and issue a stronger warning.
413 let future_incompat_lints
= &lints
.lint_groups
[builtin
::FUTURE_INCOMPATIBLE
];
414 let this_id
= LintId
::of(lint
);
415 if future_incompat_lints
.0.iter
().any(|&id
| id
== this_id
) {
416 let msg
= "this lint will become a HARD ERROR in a future release!";
417 if let Some(sp
) = span
{
418 sess
.span_note(sp
, msg
);
424 if let Some(span
) = def
{
425 sess
.span_note(span
, "lint level defined here");
429 pub trait LintContext
: Sized
{
430 fn sess(&self) -> &Session
;
431 fn lints(&self) -> &LintStore
;
432 fn mut_lints(&mut self) -> &mut LintStore
;
433 fn level_stack(&mut self) -> &mut Vec
<(LintId
, LevelSource
)>;
434 fn enter_attrs(&mut self, attrs
: &[ast
::Attribute
]);
435 fn exit_attrs(&mut self, attrs
: &[ast
::Attribute
]);
437 /// Get the level of `lint` at the current position of the lint
439 fn current_level(&self, lint
: &'
static Lint
) -> Level
{
440 self.lints().levels
.get(&LintId
::of(lint
)).map_or(Allow
, |&(lvl
, _
)| lvl
)
443 fn lookup_and_emit(&self, lint
: &'
static Lint
, span
: Option
<Span
>, msg
: &str) {
444 let (level
, src
) = match self.lints().levels
.get(&LintId
::of(lint
)) {
446 Some(&(Warn
, src
)) => {
447 let lint_id
= LintId
::of(builtin
::WARNINGS
);
448 (self.lints().get_level_source(lint_id
).0, src
)
453 raw_emit_lint(&self.sess(), self.lints(), lint
, (level
, src
), span
, msg
);
456 /// Emit a lint at the appropriate level, for a particular span.
457 fn span_lint(&self, lint
: &'
static Lint
, span
: Span
, msg
: &str) {
458 self.lookup_and_emit(lint
, Some(span
), msg
);
461 /// Emit a lint and note at the appropriate level, for a particular span.
462 fn span_lint_note(&self, lint
: &'
static Lint
, span
: Span
, msg
: &str,
463 note_span
: Span
, note
: &str) {
464 self.span_lint(lint
, span
, msg
);
465 if self.current_level(lint
) != Level
::Allow
{
466 if note_span
== span
{
467 self.sess().fileline_note(note_span
, note
)
469 self.sess().span_note(note_span
, note
)
474 /// Emit a lint and help at the appropriate level, for a particular span.
475 fn span_lint_help(&self, lint
: &'
static Lint
, span
: Span
,
476 msg
: &str, help
: &str) {
477 self.span_lint(lint
, span
, msg
);
478 if self.current_level(lint
) != Level
::Allow
{
479 self.sess().span_help(span
, help
)
483 /// Emit a lint at the appropriate level, with no associated span.
484 fn lint(&self, lint
: &'
static Lint
, msg
: &str) {
485 self.lookup_and_emit(lint
, None
, msg
);
488 /// Merge the lints specified by any lint attributes into the
489 /// current lint context, call the provided function, then reset the
490 /// lints in effect to their previous state.
491 fn with_lint_attrs
<F
>(&mut self,
492 attrs
: &[ast
::Attribute
],
494 where F
: FnOnce(&mut Self),
496 // Parse all of the lint attributes, and then add them all to the
497 // current dictionary of lint information. Along the way, keep a history
498 // of what we changed so we can roll everything back after invoking the
502 for result
in gather_attrs(attrs
) {
503 let v
= match result
{
505 span_err
!(self.sess(), span
, E0452
,
506 "malformed lint attribute");
509 Ok((lint_name
, level
, span
)) => {
510 match self.lints().find_lint(&lint_name
, &self.sess(), Some(span
)) {
511 Ok(lint_id
) => vec
![(lint_id
, level
, span
)],
512 Err(FindLintError
::NotFound
) => {
513 match self.lints().lint_groups
.get(&lint_name
[..]) {
514 Some(&(ref v
, _
)) => v
.iter()
515 .map(|lint_id
: &LintId
|
516 (*lint_id
, level
, span
))
519 // The lint or lint group doesn't exist.
520 // This is an error, but it was handled
521 // by check_lint_name_attribute.
526 Err(FindLintError
::Removed
) => { continue; }
531 for (lint_id
, level
, span
) in v
{
532 let now
= self.lints().get_level_source(lint_id
).0;
533 if now
== Forbid
&& level
!= Forbid
{
534 let lint_name
= lint_id
.as_str();
535 span_err
!(self.sess(), span
, E0453
,
536 "{}({}) overruled by outer forbid({})",
537 level
.as_str(), lint_name
,
539 } else if now
!= level
{
540 let src
= self.lints().get_level_source(lint_id
).1;
541 self.level_stack().push((lint_id
, (now
, src
)));
543 self.mut_lints().set_level(lint_id
, (level
, Node(span
)));
548 self.enter_attrs(attrs
);
550 self.exit_attrs(attrs
);
554 let (lint
, lvlsrc
) = self.level_stack().pop().unwrap();
555 self.mut_lints().set_level(lint
, lvlsrc
);
561 impl<'a
> EarlyContext
<'a
> {
562 fn new(sess
: &'a Session
,
563 krate
: &'a ast
::Crate
) -> EarlyContext
<'a
> {
564 // We want to own the lint store, so move it out of the session. Remember
565 // to put it back later...
566 let lint_store
= mem
::replace(&mut *sess
.lint_store
.borrow_mut(),
576 fn visit_ids
<F
>(&mut self, f
: F
)
577 where F
: FnOnce(&mut ast_util
::IdVisitor
<EarlyContext
>)
579 let mut v
= ast_util
::IdVisitor
{
581 visited_outermost
: false,
587 impl<'a
, 'tcx
> LateContext
<'a
, 'tcx
> {
588 fn new(tcx
: &'a ty
::ctxt
<'tcx
>,
589 krate
: &'a hir
::Crate
,
590 access_levels
: &'a AccessLevels
) -> LateContext
<'a
, 'tcx
> {
591 // We want to own the lint store, so move it out of the session.
592 let lint_store
= mem
::replace(&mut *tcx
.sess
.lint_store
.borrow_mut(),
598 access_levels
: access_levels
,
601 node_levels
: RefCell
::new(FnvHashMap()),
605 fn visit_ids
<F
>(&mut self, f
: F
)
606 where F
: FnOnce(&mut util
::IdVisitor
<LateContext
>)
608 let mut v
= util
::IdVisitor
::new(self);
613 impl<'a
, 'tcx
> LintContext
for LateContext
<'a
, 'tcx
> {
614 /// Get the overall compiler `Session` object.
615 fn sess(&self) -> &Session
{
619 fn lints(&self) -> &LintStore
{
623 fn mut_lints(&mut self) -> &mut LintStore
{
627 fn level_stack(&mut self) -> &mut Vec
<(LintId
, LevelSource
)> {
628 &mut self.level_stack
631 fn enter_attrs(&mut self, attrs
: &[ast
::Attribute
]) {
632 debug
!("late context: enter_attrs({:?})", attrs
);
633 run_lints
!(self, enter_lint_attrs
, late_passes
, attrs
);
636 fn exit_attrs(&mut self, attrs
: &[ast
::Attribute
]) {
637 debug
!("late context: exit_attrs({:?})", attrs
);
638 run_lints
!(self, exit_lint_attrs
, late_passes
, attrs
);
642 impl<'a
> LintContext
for EarlyContext
<'a
> {
643 /// Get the overall compiler `Session` object.
644 fn sess(&self) -> &Session
{
648 fn lints(&self) -> &LintStore
{
652 fn mut_lints(&mut self) -> &mut LintStore
{
656 fn level_stack(&mut self) -> &mut Vec
<(LintId
, LevelSource
)> {
657 &mut self.level_stack
660 fn enter_attrs(&mut self, attrs
: &[ast
::Attribute
]) {
661 debug
!("early context: exit_attrs({:?})", attrs
);
662 run_lints
!(self, enter_lint_attrs
, early_passes
, attrs
);
665 fn exit_attrs(&mut self, attrs
: &[ast
::Attribute
]) {
666 debug
!("early context: exit_attrs({:?})", attrs
);
667 run_lints
!(self, exit_lint_attrs
, early_passes
, attrs
);
671 impl<'a
, 'tcx
, 'v
> hir_visit
::Visitor
<'v
> for LateContext
<'a
, 'tcx
> {
672 /// Because lints are scoped lexically, we want to walk nested
673 /// items in the context of the outer item, so enable
675 fn visit_nested_item(&mut self, item
: hir
::ItemId
) {
676 self.visit_item(self.tcx
.map
.expect_item(item
.id
))
679 fn visit_item(&mut self, it
: &hir
::Item
) {
680 self.with_lint_attrs(&it
.attrs
, |cx
| {
681 run_lints
!(cx
, check_item
, late_passes
, it
);
682 cx
.visit_ids(|v
| v
.visit_item(it
));
683 hir_visit
::walk_item(cx
, it
);
687 fn visit_foreign_item(&mut self, it
: &hir
::ForeignItem
) {
688 self.with_lint_attrs(&it
.attrs
, |cx
| {
689 run_lints
!(cx
, check_foreign_item
, late_passes
, it
);
690 hir_visit
::walk_foreign_item(cx
, it
);
694 fn visit_pat(&mut self, p
: &hir
::Pat
) {
695 run_lints
!(self, check_pat
, late_passes
, p
);
696 hir_visit
::walk_pat(self, p
);
699 fn visit_expr(&mut self, e
: &hir
::Expr
) {
700 self.with_lint_attrs(e
.attrs
.as_attr_slice(), |cx
| {
701 run_lints
!(cx
, check_expr
, late_passes
, e
);
702 hir_visit
::walk_expr(cx
, e
);
706 fn visit_stmt(&mut self, s
: &hir
::Stmt
) {
707 // statement attributes are actually just attributes on one of
711 // so we keep track of lint levels there
712 run_lints
!(self, check_stmt
, late_passes
, s
);
713 hir_visit
::walk_stmt(self, s
);
716 fn visit_fn(&mut self, fk
: hir_visit
::FnKind
<'v
>, decl
: &'v hir
::FnDecl
,
717 body
: &'v hir
::Block
, span
: Span
, id
: ast
::NodeId
) {
718 run_lints
!(self, check_fn
, late_passes
, fk
, decl
, body
, span
, id
);
719 hir_visit
::walk_fn(self, fk
, decl
, body
, span
);
722 fn visit_variant_data(&mut self,
723 s
: &hir
::VariantData
,
726 item_id
: ast
::NodeId
,
728 run_lints
!(self, check_struct_def
, late_passes
, s
, name
, g
, item_id
);
729 hir_visit
::walk_struct_def(self, s
);
730 run_lints
!(self, check_struct_def_post
, late_passes
, s
, name
, g
, item_id
);
733 fn visit_struct_field(&mut self, s
: &hir
::StructField
) {
734 self.with_lint_attrs(&s
.node
.attrs
, |cx
| {
735 run_lints
!(cx
, check_struct_field
, late_passes
, s
);
736 hir_visit
::walk_struct_field(cx
, s
);
740 fn visit_variant(&mut self, v
: &hir
::Variant
, g
: &hir
::Generics
, item_id
: ast
::NodeId
) {
741 self.with_lint_attrs(&v
.node
.attrs
, |cx
| {
742 run_lints
!(cx
, check_variant
, late_passes
, v
, g
);
743 hir_visit
::walk_variant(cx
, v
, g
, item_id
);
744 run_lints
!(cx
, check_variant_post
, late_passes
, v
, g
);
748 fn visit_ty(&mut self, t
: &hir
::Ty
) {
749 run_lints
!(self, check_ty
, late_passes
, t
);
750 hir_visit
::walk_ty(self, t
);
753 fn visit_name(&mut self, sp
: Span
, name
: ast
::Name
) {
754 run_lints
!(self, check_name
, late_passes
, sp
, name
);
757 fn visit_mod(&mut self, m
: &hir
::Mod
, s
: Span
, n
: ast
::NodeId
) {
758 run_lints
!(self, check_mod
, late_passes
, m
, s
, n
);
759 hir_visit
::walk_mod(self, m
);
762 fn visit_local(&mut self, l
: &hir
::Local
) {
763 self.with_lint_attrs(l
.attrs
.as_attr_slice(), |cx
| {
764 run_lints
!(cx
, check_local
, late_passes
, l
);
765 hir_visit
::walk_local(cx
, l
);
769 fn visit_block(&mut self, b
: &hir
::Block
) {
770 run_lints
!(self, check_block
, late_passes
, b
);
771 hir_visit
::walk_block(self, b
);
774 fn visit_arm(&mut self, a
: &hir
::Arm
) {
775 run_lints
!(self, check_arm
, late_passes
, a
);
776 hir_visit
::walk_arm(self, a
);
779 fn visit_decl(&mut self, d
: &hir
::Decl
) {
780 run_lints
!(self, check_decl
, late_passes
, d
);
781 hir_visit
::walk_decl(self, d
);
784 fn visit_expr_post(&mut self, e
: &hir
::Expr
) {
785 run_lints
!(self, check_expr_post
, late_passes
, e
);
788 fn visit_generics(&mut self, g
: &hir
::Generics
) {
789 run_lints
!(self, check_generics
, late_passes
, g
);
790 hir_visit
::walk_generics(self, g
);
793 fn visit_trait_item(&mut self, trait_item
: &hir
::TraitItem
) {
794 self.with_lint_attrs(&trait_item
.attrs
, |cx
| {
795 run_lints
!(cx
, check_trait_item
, late_passes
, trait_item
);
796 cx
.visit_ids(|v
| v
.visit_trait_item(trait_item
));
797 hir_visit
::walk_trait_item(cx
, trait_item
);
801 fn visit_impl_item(&mut self, impl_item
: &hir
::ImplItem
) {
802 self.with_lint_attrs(&impl_item
.attrs
, |cx
| {
803 run_lints
!(cx
, check_impl_item
, late_passes
, impl_item
);
804 cx
.visit_ids(|v
| v
.visit_impl_item(impl_item
));
805 hir_visit
::walk_impl_item(cx
, impl_item
);
809 fn visit_lifetime(&mut self, lt
: &hir
::Lifetime
) {
810 run_lints
!(self, check_lifetime
, late_passes
, lt
);
813 fn visit_lifetime_def(&mut self, lt
: &hir
::LifetimeDef
) {
814 run_lints
!(self, check_lifetime_def
, late_passes
, lt
);
817 fn visit_explicit_self(&mut self, es
: &hir
::ExplicitSelf
) {
818 run_lints
!(self, check_explicit_self
, late_passes
, es
);
819 hir_visit
::walk_explicit_self(self, es
);
822 fn visit_path(&mut self, p
: &hir
::Path
, id
: ast
::NodeId
) {
823 run_lints
!(self, check_path
, late_passes
, p
, id
);
824 hir_visit
::walk_path(self, p
);
827 fn visit_path_list_item(&mut self, prefix
: &hir
::Path
, item
: &hir
::PathListItem
) {
828 run_lints
!(self, check_path_list_item
, late_passes
, item
);
829 hir_visit
::walk_path_list_item(self, prefix
, item
);
832 fn visit_attribute(&mut self, attr
: &ast
::Attribute
) {
833 check_lint_name_attribute(self, attr
);
834 run_lints
!(self, check_attribute
, late_passes
, attr
);
838 impl<'a
, 'v
> ast_visit
::Visitor
<'v
> for EarlyContext
<'a
> {
839 fn visit_item(&mut self, it
: &ast
::Item
) {
840 self.with_lint_attrs(&it
.attrs
, |cx
| {
841 run_lints
!(cx
, check_item
, early_passes
, it
);
842 cx
.visit_ids(|v
| v
.visit_item(it
));
843 ast_visit
::walk_item(cx
, it
);
847 fn visit_foreign_item(&mut self, it
: &ast
::ForeignItem
) {
848 self.with_lint_attrs(&it
.attrs
, |cx
| {
849 run_lints
!(cx
, check_foreign_item
, early_passes
, it
);
850 ast_visit
::walk_foreign_item(cx
, it
);
854 fn visit_pat(&mut self, p
: &ast
::Pat
) {
855 run_lints
!(self, check_pat
, early_passes
, p
);
856 ast_visit
::walk_pat(self, p
);
859 fn visit_expr(&mut self, e
: &ast
::Expr
) {
860 run_lints
!(self, check_expr
, early_passes
, e
);
861 ast_visit
::walk_expr(self, e
);
864 fn visit_stmt(&mut self, s
: &ast
::Stmt
) {
865 run_lints
!(self, check_stmt
, early_passes
, s
);
866 ast_visit
::walk_stmt(self, s
);
869 fn visit_fn(&mut self, fk
: ast_visit
::FnKind
<'v
>, decl
: &'v ast
::FnDecl
,
870 body
: &'v ast
::Block
, span
: Span
, id
: ast
::NodeId
) {
871 run_lints
!(self, check_fn
, early_passes
, fk
, decl
, body
, span
, id
);
872 ast_visit
::walk_fn(self, fk
, decl
, body
, span
);
875 fn visit_variant_data(&mut self,
876 s
: &ast
::VariantData
,
879 item_id
: ast
::NodeId
,
881 run_lints
!(self, check_struct_def
, early_passes
, s
, ident
, g
, item_id
);
882 ast_visit
::walk_struct_def(self, s
);
883 run_lints
!(self, check_struct_def_post
, early_passes
, s
, ident
, g
, item_id
);
886 fn visit_struct_field(&mut self, s
: &ast
::StructField
) {
887 self.with_lint_attrs(&s
.node
.attrs
, |cx
| {
888 run_lints
!(cx
, check_struct_field
, early_passes
, s
);
889 ast_visit
::walk_struct_field(cx
, s
);
893 fn visit_variant(&mut self, v
: &ast
::Variant
, g
: &ast
::Generics
, item_id
: ast
::NodeId
) {
894 self.with_lint_attrs(&v
.node
.attrs
, |cx
| {
895 run_lints
!(cx
, check_variant
, early_passes
, v
, g
);
896 ast_visit
::walk_variant(cx
, v
, g
, item_id
);
897 run_lints
!(cx
, check_variant_post
, early_passes
, v
, g
);
901 fn visit_ty(&mut self, t
: &ast
::Ty
) {
902 run_lints
!(self, check_ty
, early_passes
, t
);
903 ast_visit
::walk_ty(self, t
);
906 fn visit_ident(&mut self, sp
: Span
, id
: ast
::Ident
) {
907 run_lints
!(self, check_ident
, early_passes
, sp
, id
);
910 fn visit_mod(&mut self, m
: &ast
::Mod
, s
: Span
, n
: ast
::NodeId
) {
911 run_lints
!(self, check_mod
, early_passes
, m
, s
, n
);
912 ast_visit
::walk_mod(self, m
);
915 fn visit_local(&mut self, l
: &ast
::Local
) {
916 run_lints
!(self, check_local
, early_passes
, l
);
917 ast_visit
::walk_local(self, l
);
920 fn visit_block(&mut self, b
: &ast
::Block
) {
921 run_lints
!(self, check_block
, early_passes
, b
);
922 ast_visit
::walk_block(self, b
);
925 fn visit_arm(&mut self, a
: &ast
::Arm
) {
926 run_lints
!(self, check_arm
, early_passes
, a
);
927 ast_visit
::walk_arm(self, a
);
930 fn visit_decl(&mut self, d
: &ast
::Decl
) {
931 run_lints
!(self, check_decl
, early_passes
, d
);
932 ast_visit
::walk_decl(self, d
);
935 fn visit_expr_post(&mut self, e
: &ast
::Expr
) {
936 run_lints
!(self, check_expr_post
, early_passes
, e
);
939 fn visit_generics(&mut self, g
: &ast
::Generics
) {
940 run_lints
!(self, check_generics
, early_passes
, g
);
941 ast_visit
::walk_generics(self, g
);
944 fn visit_trait_item(&mut self, trait_item
: &ast
::TraitItem
) {
945 self.with_lint_attrs(&trait_item
.attrs
, |cx
| {
946 run_lints
!(cx
, check_trait_item
, early_passes
, trait_item
);
947 cx
.visit_ids(|v
| v
.visit_trait_item(trait_item
));
948 ast_visit
::walk_trait_item(cx
, trait_item
);
952 fn visit_impl_item(&mut self, impl_item
: &ast
::ImplItem
) {
953 self.with_lint_attrs(&impl_item
.attrs
, |cx
| {
954 run_lints
!(cx
, check_impl_item
, early_passes
, impl_item
);
955 cx
.visit_ids(|v
| v
.visit_impl_item(impl_item
));
956 ast_visit
::walk_impl_item(cx
, impl_item
);
960 fn visit_lifetime(&mut self, lt
: &ast
::Lifetime
) {
961 run_lints
!(self, check_lifetime
, early_passes
, lt
);
964 fn visit_lifetime_def(&mut self, lt
: &ast
::LifetimeDef
) {
965 run_lints
!(self, check_lifetime_def
, early_passes
, lt
);
968 fn visit_explicit_self(&mut self, es
: &ast
::ExplicitSelf
) {
969 run_lints
!(self, check_explicit_self
, early_passes
, es
);
970 ast_visit
::walk_explicit_self(self, es
);
973 fn visit_path(&mut self, p
: &ast
::Path
, id
: ast
::NodeId
) {
974 run_lints
!(self, check_path
, early_passes
, p
, id
);
975 ast_visit
::walk_path(self, p
);
978 fn visit_path_list_item(&mut self, prefix
: &ast
::Path
, item
: &ast
::PathListItem
) {
979 run_lints
!(self, check_path_list_item
, early_passes
, item
);
980 ast_visit
::walk_path_list_item(self, prefix
, item
);
983 fn visit_attribute(&mut self, attr
: &ast
::Attribute
) {
984 run_lints
!(self, check_attribute
, early_passes
, attr
);
988 // Output any lints that were previously added to the session.
989 impl<'a
, 'tcx
> IdVisitingOperation
for LateContext
<'a
, 'tcx
> {
990 fn visit_id(&mut self, id
: ast
::NodeId
) {
991 match self.sess().lints
.borrow_mut().remove(&id
) {
994 debug
!("LateContext::visit_id: id={:?} lints={:?}", id
, lints
);
995 for (lint_id
, span
, msg
) in lints
{
996 self.span_lint(lint_id
.lint
, span
, &msg
[..])
1002 impl<'a
> IdVisitingOperation
for EarlyContext
<'a
> {
1003 fn visit_id(&mut self, id
: ast
::NodeId
) {
1004 match self.sess
.lints
.borrow_mut().remove(&id
) {
1007 for (lint_id
, span
, msg
) in lints
{
1008 self.span_lint(lint_id
.lint
, span
, &msg
[..])
1015 // This lint pass is defined here because it touches parts of the `LateContext`
1016 // that we don't want to expose. It records the lint level at certain AST
1017 // nodes, so that the variant size difference check in trans can call
1020 pub struct GatherNodeLevels
;
1022 impl LintPass
for GatherNodeLevels
{
1023 fn get_lints(&self) -> LintArray
{
1028 impl LateLintPass
for GatherNodeLevels
{
1029 fn check_item(&mut self, cx
: &LateContext
, it
: &hir
::Item
) {
1031 hir
::ItemEnum(..) => {
1032 let lint_id
= LintId
::of(builtin
::VARIANT_SIZE_DIFFERENCES
);
1033 let lvlsrc
= cx
.lints
.get_level_source(lint_id
);
1035 (lvl
, _
) if lvl
!= Allow
=> {
1036 cx
.node_levels
.borrow_mut()
1037 .insert((it
.id
, lint_id
), lvlsrc
);
1047 enum CheckLintNameResult
{
1049 // Lint doesn't exist
1051 // The lint is either renamed or removed and a warning was generated
1055 /// Checks the name of a lint for its existence, and whether it was
1056 /// renamed or removed. Generates a DiagnosticBuilder containing a
1057 /// warning for renamed and removed lints. This is over both lint
1058 /// names from attributes and those passed on the command line. Since
1059 /// it emits non-fatal warnings and there are *two* lint passes that
1060 /// inspect attributes, this is only run from the late pass to avoid
1061 /// printing duplicate warnings.
1062 fn check_lint_name(sess
: &Session
,
1063 lint_cx
: &LintStore
,
1065 span
: Option
<Span
>) -> CheckLintNameResult
{
1066 match lint_cx
.by_name
.get(lint_name
) {
1067 Some(&Renamed(ref new_name
, _
)) => {
1068 let warning
= format
!("lint {} has been renamed to {}",
1069 lint_name
, new_name
);
1071 Some(span
) => sess
.span_warn(span
, &warning
[..]),
1072 None
=> sess
.warn(&warning
[..]),
1074 CheckLintNameResult
::Mentioned
1076 Some(&Removed(ref reason
)) => {
1077 let warning
= format
!("lint {} has been removed: {}", lint_name
, reason
);
1079 Some(span
) => sess
.span_warn(span
, &warning
[..]),
1080 None
=> sess
.warn(&warning
[..])
1082 CheckLintNameResult
::Mentioned
1085 match lint_cx
.lint_groups
.get(lint_name
) {
1087 CheckLintNameResult
::NoLint
1090 /* lint group exists */
1091 CheckLintNameResult
::Ok
1097 CheckLintNameResult
::Ok
1102 // Checks the validity of lint names derived from attributes
1103 fn check_lint_name_attribute(cx
: &LateContext
, attr
: &ast
::Attribute
) {
1104 for result
in gather_attr(attr
) {
1107 // Malformed lint attr. Reported by with_lint_attrs
1110 Ok((lint_name
, _
, span
)) => {
1111 match check_lint_name(&cx
.tcx
.sess
, &cx
.lints
, &lint_name
[..], Some(span
)) {
1112 CheckLintNameResult
::Ok
=> (),
1113 CheckLintNameResult
::Mentioned
=> (),
1114 CheckLintNameResult
::NoLint
=> {
1115 cx
.span_lint(builtin
::UNKNOWN_LINTS
, span
,
1116 &format
!("unknown lint: `{}`",
1125 // Checks the validity of lint names derived from the command line
1126 fn check_lint_name_cmdline(sess
: &Session
, lint_cx
: &LintStore
,
1127 lint_name
: &str, level
: Level
) {
1128 let explain
= match check_lint_name(sess
, lint_cx
, lint_name
, None
) {
1129 CheckLintNameResult
::Ok
=> false,
1130 CheckLintNameResult
::Mentioned
=> true,
1131 CheckLintNameResult
::NoLint
=> {
1132 sess
.err(&format
!("unknown lint: `{}`", lint_name
));
1138 let msg
= format
!("requested on the command line with `{} {}`",
1140 Level
::Allow
=> "-A",
1141 Level
::Warn
=> "-W",
1142 Level
::Deny
=> "-D",
1143 Level
::Forbid
=> "-F",
1151 /// Perform lint checking on a crate.
1153 /// Consumes the `lint_store` field of the `Session`.
1154 pub fn check_crate(tcx
: &ty
::ctxt
, access_levels
: &AccessLevels
) {
1155 let krate
= tcx
.map
.krate();
1156 let mut cx
= LateContext
::new(tcx
, krate
, access_levels
);
1158 // Visit the whole crate.
1159 cx
.with_lint_attrs(&krate
.attrs
, |cx
| {
1160 cx
.visit_id(ast
::CRATE_NODE_ID
);
1162 hir_visit
::walk_crate(v
, krate
);
1165 // since the root module isn't visited as an item (because it isn't an
1166 // item), warn for it here.
1167 run_lints
!(cx
, check_crate
, late_passes
, krate
);
1169 hir_visit
::walk_crate(cx
, krate
);
1172 // If we missed any lints added to the session, then there's a bug somewhere
1173 // in the iteration code.
1174 for (id
, v
) in tcx
.sess
.lints
.borrow().iter() {
1175 for &(lint
, span
, ref msg
) in v
{
1176 tcx
.sess
.span_bug(span
,
1177 &format
!("unprocessed lint {} at {}: {}",
1178 lint
.as_str(), tcx
.map
.node_to_string(*id
), *msg
))
1182 *tcx
.node_lint_levels
.borrow_mut() = cx
.node_levels
.into_inner();
1185 pub fn check_ast_crate(sess
: &Session
, krate
: &ast
::Crate
) {
1186 let mut cx
= EarlyContext
::new(sess
, krate
);
1188 // Visit the whole crate.
1189 cx
.with_lint_attrs(&krate
.attrs
, |cx
| {
1190 cx
.visit_id(ast
::CRATE_NODE_ID
);
1192 v
.visited_outermost
= true;
1193 ast_visit
::walk_crate(v
, krate
);
1196 // since the root module isn't visited as an item (because it isn't an
1197 // item), warn for it here.
1198 run_lints
!(cx
, check_crate
, early_passes
, krate
);
1200 ast_visit
::walk_crate(cx
, krate
);
1203 // Put the lint store back in the session.
1204 mem
::replace(&mut *sess
.lint_store
.borrow_mut(), cx
.lints
);
1206 // If we missed any lints added to the session, then there's a bug somewhere
1207 // in the iteration code.
1208 for (_
, v
) in sess
.lints
.borrow().iter() {
1209 for &(lint
, span
, ref msg
) in v
{
1211 &format
!("unprocessed lint {}: {}",
1212 lint
.as_str(), *msg
))