|  | 
|  | 1 | +use crate::lints::UselessAnonymousReexportDiag; | 
|  | 2 | +use crate::{LateContext, LateLintPass, LintContext}; | 
|  | 3 | +use rustc_hir::def::DefKind; | 
|  | 4 | +use rustc_hir::def_id::DefId; | 
|  | 5 | +use rustc_hir::{Item, ItemKind, UseKind}; | 
|  | 6 | +use rustc_middle::ty::Visibility; | 
|  | 7 | +use rustc_span::symbol::kw; | 
|  | 8 | +use rustc_span::Span; | 
|  | 9 | + | 
|  | 10 | +declare_lint! { | 
|  | 11 | +    /// The `useless_anonymous_reexport` lint checks if anonymous re-exports | 
|  | 12 | +    /// are re-exports of traits. | 
|  | 13 | +    /// | 
|  | 14 | +    /// ### Example | 
|  | 15 | +    /// | 
|  | 16 | +    /// ```rust,compile_fail | 
|  | 17 | +    /// #![deny(useless_anonymous_reexport)] | 
|  | 18 | +    /// | 
|  | 19 | +    /// mod sub { | 
|  | 20 | +    ///     pub struct Bar; | 
|  | 21 | +    /// } | 
|  | 22 | +    /// | 
|  | 23 | +    /// pub use self::sub::Bar as _; | 
|  | 24 | +    /// # fn main() {} | 
|  | 25 | +    /// ``` | 
|  | 26 | +    /// | 
|  | 27 | +    /// {{produces}} | 
|  | 28 | +    /// | 
|  | 29 | +    /// ### Explanation | 
|  | 30 | +    /// | 
|  | 31 | +    /// Anonymous re-exports are only useful if it's a re-export of a trait | 
|  | 32 | +    /// in case you want to give access to it. If you re-export any other kind, | 
|  | 33 | +    /// you won't be able to use it since its name won't be accessible. | 
|  | 34 | +    pub USELESS_ANONYMOUS_REEXPORT, | 
|  | 35 | +    Warn, | 
|  | 36 | +    "useless anonymous re-export" | 
|  | 37 | +} | 
|  | 38 | + | 
|  | 39 | +declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]); | 
|  | 40 | + | 
|  | 41 | +fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) { | 
|  | 42 | +    let article = cx.tcx.def_descr_article(def_id); | 
|  | 43 | +    let desc = cx.tcx.def_descr(def_id); | 
|  | 44 | +    cx.emit_spanned_lint( | 
|  | 45 | +        USELESS_ANONYMOUS_REEXPORT, | 
|  | 46 | +        span, | 
|  | 47 | +        UselessAnonymousReexportDiag { article, desc }, | 
|  | 48 | +    ); | 
|  | 49 | +} | 
|  | 50 | + | 
|  | 51 | +impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport { | 
|  | 52 | +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { | 
|  | 53 | +        if let ItemKind::Use(path, kind) = item.kind && | 
|  | 54 | +            !matches!(kind, UseKind::Glob) && | 
|  | 55 | +            item.ident.name == kw::Underscore && | 
|  | 56 | +            // We only want re-exports. If it's just a `use X;`, then we ignore it. | 
|  | 57 | +            match cx.tcx.local_visibility(item.owner_id.def_id) { | 
|  | 58 | +                Visibility::Public => true, | 
|  | 59 | +                Visibility::Restricted(level) => { | 
|  | 60 | +                    level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id) | 
|  | 61 | +                } | 
|  | 62 | +            } | 
|  | 63 | +        { | 
|  | 64 | +            for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) { | 
|  | 65 | +                match cx.tcx.def_kind(def_id) { | 
|  | 66 | +                    DefKind::Trait | DefKind::TraitAlias => {} | 
|  | 67 | +                    DefKind::TyAlias => { | 
|  | 68 | +                        let ty = cx.tcx.type_of(def_id); | 
|  | 69 | +                        if !ty.0.is_trait() { | 
|  | 70 | +                            emit_err(cx, item.span, def_id); | 
|  | 71 | +                            break; | 
|  | 72 | +                        } | 
|  | 73 | +                    } | 
|  | 74 | +                    _ => { | 
|  | 75 | +                        emit_err(cx, item.span, def_id); | 
|  | 76 | +                        break; | 
|  | 77 | +                    } | 
|  | 78 | +                } | 
|  | 79 | +            } | 
|  | 80 | +        } | 
|  | 81 | +    } | 
|  | 82 | +} | 
0 commit comments