about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2023-03-10 22:19:48 +0100
committerGuillaume Gomez <guillaume.gomez@huawei.com>2023-03-12 15:12:42 +0100
commit2df7770d5e8e32728e0add987c65ce8a95fc475d (patch)
tree0ee6b8143c71ea0977637fb5d0cfa804e598e9b3
parent24c0b81c1fd5de8e00276524896d3352ed91a8cb (diff)
downloadrust-2df7770d5e8e32728e0add987c65ce8a95fc475d.tar.gz
rust-2df7770d5e8e32728e0add987c65ce8a95fc475d.zip
Add lint for useless anonymous reexports
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs7
-rw-r--r--compiler/rustc_lint/src/reexports.rs82
4 files changed, 95 insertions, 0 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 68e62c9789a..1924ae08c39 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -508,3 +508,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
     .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
+
+lint_useless_anonymous_reexport = useless anonymous re-export
+    .note = only anonymous re-exports of traits are useful, this is {$article} `${desc}`
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b3578540516..c2cc2fcdf55 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -74,6 +74,7 @@ mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
+mod reexports;
 mod traits;
 mod types;
 mod unused;
@@ -111,6 +112,7 @@ use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
 use redundant_semicolon::*;
+use reexports::*;
 use traits::*;
 use types::*;
 use unused::*;
@@ -242,6 +244,7 @@ late_lint_methods!(
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
             MapUnitFn: MapUnitFn,
+            UselessAnonymousReexport: UselessAnonymousReexport,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 20ab0af5856..ac73f0830f6 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1530,3 +1530,10 @@ pub struct UnusedAllocationDiag;
 #[derive(LintDiagnostic)]
 #[diag(lint_unused_allocation_mut)]
 pub struct UnusedAllocationMutDiag;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_useless_anonymous_reexport)]
+pub struct UselessAnonymousReexportDiag {
+    pub article: &'static str,
+    pub desc: &'static str,
+}
diff --git a/compiler/rustc_lint/src/reexports.rs b/compiler/rustc_lint/src/reexports.rs
new file mode 100644
index 00000000000..8737a57ea02
--- /dev/null
+++ b/compiler/rustc_lint/src/reexports.rs
@@ -0,0 +1,82 @@
+use crate::lints::UselessAnonymousReexportDiag;
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Item, ItemKind, UseKind};
+use rustc_middle::ty::Visibility;
+use rustc_span::symbol::kw;
+use rustc_span::Span;
+
+declare_lint! {
+    /// The `useless_anonymous_reexport` lint checks if anonymous re-exports
+    /// are re-exports of traits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(useless_anonymous_reexport)]
+    ///
+    /// mod sub {
+    ///     pub struct Bar;
+    /// }
+    ///
+    /// pub use self::sub::Bar as _;
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Anonymous re-exports are only useful if it's a re-export of a trait
+    /// in case you want to give access to it. If you re-export any other kind,
+    /// you won't be able to use it since its name won't be accessible.
+    pub USELESS_ANONYMOUS_REEXPORT,
+    Warn,
+    "useless anonymous re-export"
+}
+
+declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]);
+
+fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) {
+    let article = cx.tcx.def_descr_article(def_id);
+    let desc = cx.tcx.def_descr(def_id);
+    cx.emit_spanned_lint(
+        USELESS_ANONYMOUS_REEXPORT,
+        span,
+        UselessAnonymousReexportDiag { article, desc },
+    );
+}
+
+impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Use(path, kind) = item.kind &&
+            !matches!(kind, UseKind::Glob) &&
+            item.ident.name == kw::Underscore &&
+            // We only want re-exports. If it's just a `use X;`, then we ignore it.
+            match cx.tcx.local_visibility(item.owner_id.def_id) {
+                Visibility::Public => true,
+                Visibility::Restricted(level) => {
+                    level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
+                }
+            }
+        {
+            for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) {
+                match cx.tcx.def_kind(def_id) {
+                    DefKind::Trait | DefKind::TraitAlias => {}
+                    DefKind::TyAlias => {
+                        let ty = cx.tcx.type_of(def_id);
+                        if !ty.0.is_trait() {
+                            emit_err(cx, item.span, def_id);
+                            break;
+                        }
+                    }
+                    _ => {
+                        emit_err(cx, item.span, def_id);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}