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
::ExportedItems
;
29 use middle
::ty
::{self, Ty}
;
30 use session
::{early_error, Session}
;
31 use lint
::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject}
;
32 use lint
::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}
;
34 use util
::nodemap
::FnvHashMap
;
36 use std
::cell
::RefCell
;
39 use syntax
::ast_util
::IdVisitingOperation
;
40 use rustc_front
::attr
::{self, AttrMetaMethods}
;
41 use rustc_front
::util
;
42 use syntax
::codemap
::Span
;
43 use syntax
::parse
::token
::InternedString
;
46 use rustc_front
::visit
::{self, Visitor, FnKind}
;
47 use syntax
::visit
::Visitor
as SyntaxVisitor
;
48 use syntax
::diagnostic
;
50 /// Information about the registered lints.
52 /// This is basically the subset of `Context` that we can
53 /// build early in the compile pipeline.
54 pub struct LintStore
{
55 /// Registered lints. The bool is true if the lint was
56 /// added by a plugin.
57 lints
: Vec
<(&'
static Lint
, bool
)>,
59 /// Trait objects for each lint pass.
60 /// This is only `None` while iterating over the objects. See the definition
62 passes
: Option
<Vec
<LintPassObject
>>,
64 /// Lints indexed by name.
65 by_name
: FnvHashMap
<String
, TargetLint
>,
67 /// Current levels of each lint, and where they were set.
68 levels
: FnvHashMap
<LintId
, LevelSource
>,
70 /// Map of registered lint groups to what lints they expand to. The bool
71 /// is true if the lint group was added by a plugin.
72 lint_groups
: FnvHashMap
<&'
static str, (Vec
<LintId
>, bool
)>,
74 /// Maximum level a lint can be
75 lint_cap
: Option
<Level
>,
78 /// The targed of the `by_name` map, which accounts for renaming/deprecation.
80 /// A direct lint target
83 /// Temporary renaming, used for easing migration pain; see #16545
84 Renamed(String
, LintId
),
86 /// Lint with this name existed previously, but has been removed/deprecated.
87 /// The string argument is the reason for removal.
97 fn get_level_source(&self, lint
: LintId
) -> LevelSource
{
98 match self.levels
.get(&lint
) {
100 None
=> (Allow
, Default
),
104 fn set_level(&mut self, lint
: LintId
, mut lvlsrc
: LevelSource
) {
105 if let Some(cap
) = self.lint_cap
{
106 lvlsrc
.0 = cmp
::min(lvlsrc
.0, cap
);
108 if lvlsrc
.0 == Allow
{
109 self.levels
.remove(&lint
);
111 self.levels
.insert(lint
, lvlsrc
);
115 pub fn new() -> LintStore
{
118 passes
: Some(vec
!()),
119 by_name
: FnvHashMap(),
120 levels
: FnvHashMap(),
121 lint_groups
: FnvHashMap(),
126 pub fn get_lints
<'t
>(&'t
self) -> &'t
[(&'
static Lint
, bool
)] {
130 pub fn get_lint_groups
<'t
>(&'t
self) -> Vec
<(&'
static str, Vec
<LintId
>, bool
)> {
131 self.lint_groups
.iter().map(|(k
, v
)| (*k
,
136 pub fn register_pass(&mut self, sess
: Option
<&Session
>,
137 from_plugin
: bool
, pass
: LintPassObject
) {
138 for &lint
in pass
.get_lints() {
139 self.lints
.push((*lint
, from_plugin
));
141 let id
= LintId
::of(*lint
);
142 if self.by_name
.insert(lint
.name_lower(), Id(id
)).is_some() {
143 let msg
= format
!("duplicate specification of lint {}", lint
.name_lower());
144 match (sess
, from_plugin
) {
145 // We load builtin lints first, so a duplicate is a compiler bug.
146 // Use early_error when handling -W help with no crate.
147 (None
, _
) => early_error(diagnostic
::Auto
, &msg
[..]),
148 (Some(sess
), false) => sess
.bug(&msg
[..]),
150 // A duplicate name from a plugin is a user error.
151 (Some(sess
), true) => sess
.err(&msg
[..]),
155 if lint
.default_level
!= Allow
{
156 self.levels
.insert(id
, (lint
.default_level
, Default
));
159 self.passes
.as_mut().unwrap().push(pass
);
162 pub fn register_group(&mut self, sess
: Option
<&Session
>,
163 from_plugin
: bool
, name
: &'
static str,
165 let new
= self.lint_groups
.insert(name
, (to
, from_plugin
)).is_none();
168 let msg
= format
!("duplicate specification of lint group {}", name
);
169 match (sess
, from_plugin
) {
170 // We load builtin lints first, so a duplicate is a compiler bug.
171 // Use early_error when handling -W help with no crate.
172 (None
, _
) => early_error(diagnostic
::Auto
, &msg
[..]),
173 (Some(sess
), false) => sess
.bug(&msg
[..]),
175 // A duplicate name from a plugin is a user error.
176 (Some(sess
), true) => sess
.err(&msg
[..]),
181 pub fn register_renamed(&mut self, old_name
: &str, new_name
: &str) {
182 let target
= match self.by_name
.get(new_name
) {
183 Some(&Id(lint_id
)) => lint_id
.clone(),
184 _
=> panic
!("invalid lint renaming of {} to {}", old_name
, new_name
)
186 self.by_name
.insert(old_name
.to_string(), Renamed(new_name
.to_string(), target
));
189 pub fn register_removed(&mut self, name
: &str, reason
: &str) {
190 self.by_name
.insert(name
.into(), Removed(reason
.into()));
193 #[allow(unused_variables)]
194 fn find_lint(&self, lint_name
: &str, sess
: &Session
, span
: Option
<Span
>)
195 -> Result
<LintId
, FindLintError
>
197 match self.by_name
.get(lint_name
) {
198 Some(&Id(lint_id
)) => Ok(lint_id
),
199 Some(&Renamed(ref new_name
, lint_id
)) => {
200 let warning
= format
!("lint {} has been renamed to {}",
201 lint_name
, new_name
);
203 Some(span
) => sess
.span_warn(span
, &warning
[..]),
204 None
=> sess
.warn(&warning
[..]),
208 Some(&Removed(ref reason
)) => {
209 let warning
= format
!("lint {} has been removed: {}", lint_name
, reason
);
211 Some(span
) => sess
.span_warn(span
, &warning
[..]),
212 None
=> sess
.warn(&warning
[..])
214 Err(FindLintError
::Removed
)
216 None
=> Err(FindLintError
::NotFound
)
220 pub fn process_command_line(&mut self, sess
: &Session
) {
221 for &(ref lint_name
, level
) in &sess
.opts
.lint_opts
{
222 match self.find_lint(&lint_name
[..], sess
, None
) {
223 Ok(lint_id
) => self.set_level(lint_id
, (level
, CommandLine
)),
225 match self.lint_groups
.iter().map(|(&x
, pair
)| (x
, pair
.0.clone()))
226 .collect
::<FnvHashMap
<&'
static str,
228 .get(&lint_name
[..]) {
231 .map(|lint_id
: &LintId
|
232 self.set_level(*lint_id
, (level
, CommandLine
)))
233 .collect
::<Vec
<()>>();
235 None
=> sess
.err(&format
!("unknown {} flag: {}",
236 level
.as_str(), lint_name
)),
242 self.lint_cap
= sess
.opts
.lint_cap
;
243 if let Some(cap
) = self.lint_cap
{
244 for level
in self.levels
.iter_mut().map(|p
| &mut (p
.1).0) {
245 *level
= cmp
::min(*level
, cap
);
251 /// Context for lint checking.
252 pub struct Context
<'a
, 'tcx
: 'a
> {
253 /// Type context we're checking in.
254 pub tcx
: &'a ty
::ctxt
<'tcx
>,
256 /// The crate being checked.
257 pub krate
: &'a hir
::Crate
,
259 /// Items exported from the crate being checked.
260 pub exported_items
: &'a ExportedItems
,
262 /// The store of registered lints.
265 /// When recursing into an attributed node of the ast which modifies lint
266 /// levels, this stack keeps track of the previous lint levels of whatever
268 level_stack
: Vec
<(LintId
, LevelSource
)>,
270 /// Level of lints for certain NodeIds, stored here because the body of
271 /// the lint needs to run in trans.
272 node_levels
: RefCell
<FnvHashMap
<(ast
::NodeId
, LintId
), LevelSource
>>,
275 /// Convenience macro for calling a `LintPass` method on every pass in the context.
276 macro_rules
! run_lints
{ ($cx
:expr
, $f
:ident
, $
($args
:expr
),*) => ({
277 // Move the vector of passes out of `$cx` so that we can
278 // iterate over it mutably while passing `$cx` to the methods.
279 let mut passes
= $cx
.lints
.passes
.take().unwrap();
280 for obj
in &mut passes
{
281 obj
.$
f($cx
, $
($args
),*);
283 $cx
.lints
.passes
= Some(passes
);
286 /// Parse the lint attributes into a vector, with `Err`s for malformed lint
287 /// attributes. Writing this as an iterator is an enormous mess.
288 // See also the hir version just below.
289 pub fn gather_attrs(attrs
: &[hir
::Attribute
])
290 -> Vec
<Result
<(InternedString
, Level
, Span
), Span
>> {
291 let mut out
= vec
!();
293 let level
= match Level
::from_str(&attr
.name()) {
298 attr
::mark_used(attr
);
300 let meta
= &attr
.node
.value
;
301 let metas
= match meta
.node
{
302 hir
::MetaList(_
, ref metas
) => metas
,
304 out
.push(Err(meta
.span
));
310 out
.push(match meta
.node
{
311 hir
::MetaWord(ref lint_name
) => Ok((lint_name
.clone(), level
, meta
.span
)),
318 // Copy-pasted from the above function :-(
319 pub fn gather_attrs_from_hir(attrs
: &[::rustc_front
::hir
::Attribute
])
320 -> Vec
<Result
<(InternedString
, Level
, Span
), Span
>> {
321 use ::rustc_front
::attr
::AttrMetaMethods
;
323 let mut out
= vec
!();
325 let level
= match Level
::from_str(&attr
.name()) {
330 ::rustc_front
::attr
::mark_used(attr
);
332 let meta
= &attr
.node
.value
;
333 let metas
= match meta
.node
{
334 ::rustc_front
::hir
::MetaList(_
, ref metas
) => metas
,
336 out
.push(Err(meta
.span
));
342 out
.push(match meta
.node
{
343 ::rustc_front
::hir
::MetaWord(ref lint_name
) => {
344 Ok((lint_name
.clone(), level
, meta
.span
))
353 /// Emit a lint as a warning or an error (or not at all)
354 /// according to `level`.
356 /// This lives outside of `Context` so it can be used by checks
357 /// in trans that run after the main lint pass is finished. Most
358 /// lints elsewhere in the compiler should call
359 /// `Session::add_lint()` instead.
360 pub fn raw_emit_lint(sess
: &Session
, lint
: &'
static Lint
,
361 lvlsrc
: LevelSource
, span
: Option
<Span
>, msg
: &str) {
362 let (mut level
, source
) = lvlsrc
;
363 if level
== Allow { return }
365 let name
= lint
.name_lower();
367 let msg
= match source
{
369 format
!("{}, #[{}({})] on by default", msg
,
370 level
.as_str(), name
)
373 format
!("{} [-{} {}]", msg
,
375 Warn
=> 'W'
, Deny
=> 'D'
, Forbid
=> 'F'
,
377 }, name
.replace("_", "-"))
385 // For purposes of printing, we can treat forbid as deny.
386 if level
== Forbid { level = Deny; }
388 match (level
, span
) {
389 (Warn
, Some(sp
)) => sess
.span_warn(sp
, &msg
[..]),
390 (Warn
, None
) => sess
.warn(&msg
[..]),
391 (Deny
, Some(sp
)) => sess
.span_err(sp
, &msg
[..]),
392 (Deny
, None
) => sess
.err(&msg
[..]),
393 _
=> sess
.bug("impossible level in raw_emit_lint"),
396 if let Some(span
) = def
{
397 sess
.span_note(span
, "lint level defined here");
401 impl<'a
, 'tcx
> Context
<'a
, 'tcx
> {
402 fn new(tcx
: &'a ty
::ctxt
<'tcx
>,
403 krate
: &'a hir
::Crate
,
404 exported_items
: &'a ExportedItems
) -> Context
<'a
, 'tcx
> {
405 // We want to own the lint store, so move it out of the session.
406 let lint_store
= mem
::replace(&mut *tcx
.sess
.lint_store
.borrow_mut(),
412 exported_items
: exported_items
,
415 node_levels
: RefCell
::new(FnvHashMap()),
419 /// Get the overall compiler `Session` object.
420 pub fn sess(&'a
self) -> &'a Session
{
424 /// Get the level of `lint` at the current position of the lint
426 pub fn current_level(&self, lint
: &'
static Lint
) -> Level
{
427 self.lints
.levels
.get(&LintId
::of(lint
)).map_or(Allow
, |&(lvl
, _
)| lvl
)
430 fn lookup_and_emit(&self, lint
: &'
static Lint
, span
: Option
<Span
>, msg
: &str) {
431 let (level
, src
) = match self.lints
.levels
.get(&LintId
::of(lint
)) {
433 Some(&(Warn
, src
)) => {
434 let lint_id
= LintId
::of(builtin
::WARNINGS
);
435 (self.lints
.get_level_source(lint_id
).0, src
)
440 raw_emit_lint(&self.tcx
.sess
, lint
, (level
, src
), span
, msg
);
443 /// Emit a lint at the appropriate level, with no associated span.
444 pub fn lint(&self, lint
: &'
static Lint
, msg
: &str) {
445 self.lookup_and_emit(lint
, None
, msg
);
448 /// Emit a lint at the appropriate level, for a particular span.
449 pub fn span_lint(&self, lint
: &'
static Lint
, span
: Span
, msg
: &str) {
450 self.lookup_and_emit(lint
, Some(span
), msg
);
453 /// Merge the lints specified by any lint attributes into the
454 /// current lint context, call the provided function, then reset the
455 /// lints in effect to their previous state.
456 fn with_lint_attrs
<F
>(&mut self,
457 attrs
: &[hir
::Attribute
],
459 F
: FnOnce(&mut Context
),
461 // Parse all of the lint attributes, and then add them all to the
462 // current dictionary of lint information. Along the way, keep a history
463 // of what we changed so we can roll everything back after invoking the
467 for result
in gather_attrs(attrs
) {
468 let v
= match result
{
470 self.tcx
.sess
.span_err(span
, "malformed lint attribute");
473 Ok((lint_name
, level
, span
)) => {
474 match self.lints
.find_lint(&lint_name
, &self.tcx
.sess
, Some(span
)) {
475 Ok(lint_id
) => vec
![(lint_id
, level
, span
)],
476 Err(FindLintError
::NotFound
) => {
477 match self.lints
.lint_groups
.get(&lint_name
[..]) {
478 Some(&(ref v
, _
)) => v
.iter()
479 .map(|lint_id
: &LintId
|
480 (*lint_id
, level
, span
))
483 self.span_lint(builtin
::UNKNOWN_LINTS
, span
,
484 &format
!("unknown `{}` attribute: `{}`",
485 level
.as_str(), lint_name
));
490 Err(FindLintError
::Removed
) => { continue; }
495 for (lint_id
, level
, span
) in v
{
496 let now
= self.lints
.get_level_source(lint_id
).0;
497 if now
== Forbid
&& level
!= Forbid
{
498 let lint_name
= lint_id
.as_str();
499 self.tcx
.sess
.span_err(span
,
500 &format
!("{}({}) overruled by outer forbid({})",
501 level
.as_str(), lint_name
,
503 } else if now
!= level
{
504 let src
= self.lints
.get_level_source(lint_id
).1;
505 self.level_stack
.push((lint_id
, (now
, src
)));
507 self.lints
.set_level(lint_id
, (level
, Node(span
)));
512 run_lints
!(self, enter_lint_attrs
, attrs
);
514 run_lints
!(self, exit_lint_attrs
, attrs
);
518 let (lint
, lvlsrc
) = self.level_stack
.pop().unwrap();
519 self.lints
.set_level(lint
, lvlsrc
);
523 fn visit_ids
<F
>(&mut self, f
: F
) where
524 F
: FnOnce(&mut util
::IdVisitor
<Context
>)
526 let mut v
= util
::IdVisitor
{
528 pass_through_items
: false,
529 visited_outermost
: false,
535 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for Context
<'a
, 'tcx
> {
536 fn visit_item(&mut self, it
: &hir
::Item
) {
537 self.with_lint_attrs(&it
.attrs
, |cx
| {
538 run_lints
!(cx
, check_item
, it
);
539 cx
.visit_ids(|v
| v
.visit_item(it
));
540 visit
::walk_item(cx
, it
);
544 fn visit_foreign_item(&mut self, it
: &hir
::ForeignItem
) {
545 self.with_lint_attrs(&it
.attrs
, |cx
| {
546 run_lints
!(cx
, check_foreign_item
, it
);
547 visit
::walk_foreign_item(cx
, it
);
551 fn visit_pat(&mut self, p
: &hir
::Pat
) {
552 run_lints
!(self, check_pat
, p
);
553 visit
::walk_pat(self, p
);
556 fn visit_expr(&mut self, e
: &hir
::Expr
) {
557 run_lints
!(self, check_expr
, e
);
558 visit
::walk_expr(self, e
);
561 fn visit_stmt(&mut self, s
: &hir
::Stmt
) {
562 run_lints
!(self, check_stmt
, s
);
563 visit
::walk_stmt(self, s
);
566 fn visit_fn(&mut self, fk
: FnKind
<'v
>, decl
: &'v hir
::FnDecl
,
567 body
: &'v hir
::Block
, span
: Span
, id
: ast
::NodeId
) {
568 run_lints
!(self, check_fn
, fk
, decl
, body
, span
, id
);
569 visit
::walk_fn(self, fk
, decl
, body
, span
);
572 fn visit_struct_def(&mut self,
577 run_lints
!(self, check_struct_def
, s
, ident
, g
, id
);
578 visit
::walk_struct_def(self, s
);
579 run_lints
!(self, check_struct_def_post
, s
, ident
, g
, id
);
582 fn visit_struct_field(&mut self, s
: &hir
::StructField
) {
583 self.with_lint_attrs(&s
.node
.attrs
, |cx
| {
584 run_lints
!(cx
, check_struct_field
, s
);
585 visit
::walk_struct_field(cx
, s
);
589 fn visit_variant(&mut self, v
: &hir
::Variant
, g
: &hir
::Generics
) {
590 self.with_lint_attrs(&v
.node
.attrs
, |cx
| {
591 run_lints
!(cx
, check_variant
, v
, g
);
592 visit
::walk_variant(cx
, v
, g
);
593 run_lints
!(cx
, check_variant_post
, v
, g
);
597 fn visit_ty(&mut self, t
: &hir
::Ty
) {
598 run_lints
!(self, check_ty
, t
);
599 visit
::walk_ty(self, t
);
602 fn visit_ident(&mut self, sp
: Span
, id
: ast
::Ident
) {
603 run_lints
!(self, check_ident
, sp
, id
);
606 fn visit_mod(&mut self, m
: &hir
::Mod
, s
: Span
, n
: ast
::NodeId
) {
607 run_lints
!(self, check_mod
, m
, s
, n
);
608 visit
::walk_mod(self, m
);
611 fn visit_local(&mut self, l
: &hir
::Local
) {
612 run_lints
!(self, check_local
, l
);
613 visit
::walk_local(self, l
);
616 fn visit_block(&mut self, b
: &hir
::Block
) {
617 run_lints
!(self, check_block
, b
);
618 visit
::walk_block(self, b
);
621 fn visit_arm(&mut self, a
: &hir
::Arm
) {
622 run_lints
!(self, check_arm
, a
);
623 visit
::walk_arm(self, a
);
626 fn visit_decl(&mut self, d
: &hir
::Decl
) {
627 run_lints
!(self, check_decl
, d
);
628 visit
::walk_decl(self, d
);
631 fn visit_expr_post(&mut self, e
: &hir
::Expr
) {
632 run_lints
!(self, check_expr_post
, e
);
635 fn visit_generics(&mut self, g
: &hir
::Generics
) {
636 run_lints
!(self, check_generics
, g
);
637 visit
::walk_generics(self, g
);
640 fn visit_trait_item(&mut self, trait_item
: &hir
::TraitItem
) {
641 self.with_lint_attrs(&trait_item
.attrs
, |cx
| {
642 run_lints
!(cx
, check_trait_item
, trait_item
);
643 cx
.visit_ids(|v
| v
.visit_trait_item(trait_item
));
644 visit
::walk_trait_item(cx
, trait_item
);
648 fn visit_impl_item(&mut self, impl_item
: &hir
::ImplItem
) {
649 self.with_lint_attrs(&impl_item
.attrs
, |cx
| {
650 run_lints
!(cx
, check_impl_item
, impl_item
);
651 cx
.visit_ids(|v
| v
.visit_impl_item(impl_item
));
652 visit
::walk_impl_item(cx
, impl_item
);
656 fn visit_opt_lifetime_ref(&mut self, sp
: Span
, lt
: &Option
<hir
::Lifetime
>) {
657 run_lints
!(self, check_opt_lifetime_ref
, sp
, lt
);
660 fn visit_lifetime_ref(&mut self, lt
: &hir
::Lifetime
) {
661 run_lints
!(self, check_lifetime_ref
, lt
);
664 fn visit_lifetime_def(&mut self, lt
: &hir
::LifetimeDef
) {
665 run_lints
!(self, check_lifetime_def
, lt
);
668 fn visit_explicit_self(&mut self, es
: &hir
::ExplicitSelf
) {
669 run_lints
!(self, check_explicit_self
, es
);
670 visit
::walk_explicit_self(self, es
);
673 fn visit_path(&mut self, p
: &hir
::Path
, id
: ast
::NodeId
) {
674 run_lints
!(self, check_path
, p
, id
);
675 visit
::walk_path(self, p
);
678 fn visit_attribute(&mut self, attr
: &hir
::Attribute
) {
679 run_lints
!(self, check_attribute
, attr
);
683 // Output any lints that were previously added to the session.
684 impl<'a
, 'tcx
> IdVisitingOperation
for Context
<'a
, 'tcx
> {
685 fn visit_id(&mut self, id
: ast
::NodeId
) {
686 match self.tcx
.sess
.lints
.borrow_mut().remove(&id
) {
689 for (lint_id
, span
, msg
) in lints
{
690 self.span_lint(lint_id
.lint
, span
, &msg
[..])
697 // This lint pass is defined here because it touches parts of the `Context`
698 // that we don't want to expose. It records the lint level at certain AST
699 // nodes, so that the variant size difference check in trans can call
702 pub struct GatherNodeLevels
;
704 impl LintPass
for GatherNodeLevels
{
705 fn get_lints(&self) -> LintArray
{
709 fn check_item(&mut self, cx
: &Context
, it
: &hir
::Item
) {
711 hir
::ItemEnum(..) => {
712 let lint_id
= LintId
::of(builtin
::VARIANT_SIZE_DIFFERENCES
);
713 let lvlsrc
= cx
.lints
.get_level_source(lint_id
);
715 (lvl
, _
) if lvl
!= Allow
=> {
716 cx
.node_levels
.borrow_mut()
717 .insert((it
.id
, lint_id
), lvlsrc
);
727 /// Perform lint checking on a crate.
729 /// Consumes the `lint_store` field of the `Session`.
730 pub fn check_crate(tcx
: &ty
::ctxt
,
732 exported_items
: &ExportedItems
) {
734 let mut cx
= Context
::new(tcx
, krate
, exported_items
);
736 // Visit the whole crate.
737 cx
.with_lint_attrs(&krate
.attrs
, |cx
| {
738 cx
.visit_id(ast
::CRATE_NODE_ID
);
740 v
.visited_outermost
= true;
741 visit
::walk_crate(v
, krate
);
744 // since the root module isn't visited as an item (because it isn't an
745 // item), warn for it here.
746 run_lints
!(cx
, check_crate
, krate
);
748 visit
::walk_crate(cx
, krate
);
751 // If we missed any lints added to the session, then there's a bug somewhere
752 // in the iteration code.
753 for (id
, v
) in tcx
.sess
.lints
.borrow().iter() {
754 for &(lint
, span
, ref msg
) in v
{
755 tcx
.sess
.span_bug(span
,
756 &format
!("unprocessed lint {} at {}: {}",
757 lint
.as_str(), tcx
.map
.node_to_string(*id
), *msg
))
761 *tcx
.node_lint_levels
.borrow_mut() = cx
.node_levels
.into_inner();