use rustc::hir::intravisit; use rustc::hir::map::Map; use rustc::lint::{LintLevelMap, LintLevelSets, LintLevelsBuilder, LintStore}; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use syntax::ast; pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId}; fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { assert_eq!(cnum, LOCAL_CRATE); let store = &tcx.lint_store; let mut builder = LintLevelMapBuilder { levels: LintLevelSets::builder(tcx.sess, false, &store), tcx: tcx, store: store, }; let krate = tcx.hir().krate(); let push = builder.levels.push(&krate.attrs, &store); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in krate.exported_macros { builder.levels.register_id(macro_def.hir_id); } intravisit::walk_crate(&mut builder, krate); builder.levels.pop(push); tcx.arena.alloc(builder.levels.build_map()) } struct LintLevelMapBuilder<'a, 'tcx> { levels: LintLevelsBuilder<'tcx>, tcx: TyCtxt<'tcx>, store: &'a LintStore, } impl LintLevelMapBuilder<'_, '_> { fn with_lint_attrs(&mut self, id: hir::HirId, attrs: &[ast::Attribute], f: F) where F: FnOnce(&mut Self), { let push = self.levels.push(attrs, self.store); if push.changed { self.levels.register_id(id); } f(self); self.levels.pop(push); } } impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { type Map = Map<'tcx>; fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { self.with_lint_attrs(param.hir_id, ¶m.attrs, |builder| { intravisit::walk_param(builder, param); }); } fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { self.with_lint_attrs(it.hir_id, &it.attrs, |builder| { intravisit::walk_item(builder, it); }); } fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { self.with_lint_attrs(it.hir_id, &it.attrs, |builder| { intravisit::walk_foreign_item(builder, it); }) } fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { self.with_lint_attrs(e.hir_id, &e.attrs, |builder| { intravisit::walk_expr(builder, e); }) } fn visit_struct_field(&mut self, s: &'tcx hir::StructField<'tcx>) { self.with_lint_attrs(s.hir_id, &s.attrs, |builder| { intravisit::walk_struct_field(builder, s); }) } fn visit_variant( &mut self, v: &'tcx hir::Variant<'tcx>, g: &'tcx hir::Generics<'tcx>, item_id: hir::HirId, ) { self.with_lint_attrs(v.id, &v.attrs, |builder| { intravisit::walk_variant(builder, v, g, item_id); }) } fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { self.with_lint_attrs(l.hir_id, &l.attrs, |builder| { intravisit::walk_local(builder, l); }) } fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { self.with_lint_attrs(a.hir_id, &a.attrs, |builder| { intravisit::walk_arm(builder, a); }) } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |builder| { intravisit::walk_trait_item(builder, trait_item); }); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |builder| { intravisit::walk_impl_item(builder, impl_item); }); } } pub fn provide(providers: &mut Providers<'_>) { providers.lint_levels = lint_levels; }