1 use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_sugg};
2 use if_chain::if_chain;
3 use rustc_errors::Applicability;
6 Item, ItemKind, UseKind,
8 use rustc_lint::{LateContext, LateLintPass};
9 use rustc_session::{declare_lint_pass, declare_tool_lint};
10 use rustc_span::BytePos;
12 declare_clippy_lint! {
13 /// **What it does:** Checks for `use Enum::*`.
15 /// **Why is this bad?** It is usually better style to use the prefixed name of
16 /// an enumeration variant, rather than importing variants.
18 /// **Known problems:** Old-style enumerations that prefix the variants are
23 /// use std::cmp::Ordering::*;
27 "use items that import all variants of an enum"
30 declare_clippy_lint! {
31 /// **What it does:** Checks for wildcard imports `use _::*`.
33 /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
34 /// you try to import something through a wildcard, that already has been imported by name from
35 /// a different source:
38 /// use crate1::foo; // Imports a function named foo
39 /// use crate2::*; // Has a function named foo
41 /// foo(); // Calls crate1::foo
44 /// This can lead to confusing error messages at best and to unexpected behavior at worst.
46 /// **Known problems:** If macros are imported through the wildcard, this macro is not included
47 /// by the suggestion and has to be added by hand.
49 /// Applying the suggestion when explicit imports of the things imported with a glob import
50 /// exist, may result in `unused_imports` warnings.
69 "lint `use _::*` statements"
72 declare_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
74 impl LateLintPass<'_, '_> for WildcardImports {
75 fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
76 if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
80 if !in_macro(item.span);
81 if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
82 // don't lint prelude glob imports
83 if !use_path.segments.iter().last().map_or(false, |ps| ps.ident.as_str() == "prelude");
84 let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner_def_id());
85 if !used_imports.is_empty(); // Already handled by `unused_imports`
87 let mut applicability = Applicability::MachineApplicable;
88 let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
89 let (span, braced_glob) = if import_source_snippet.is_empty() {
90 // This is a `_::{_, *}` import
91 // In this case `use_path.span` is empty and ends directly in front of the `*`,
92 // so we need to extend it by one byte.
94 use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
98 // In this case, the `use_path.span` ends right before the `::*`, so we need to
99 // extend it up to the `*`. Since it is hard to find the `*` in weird
100 // formattings like `use _ :: *;`, we extend it up to, but not including the
101 // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
102 // can just use the end of the item span
103 let mut span = use_path.span.with_hi(item.span.hi());
104 if snippet(cx, span, "").ends_with(';') {
105 span = use_path.span.with_hi(item.span.hi() - BytePos(1));
113 let imports_string = if used_imports.len() == 1 {
114 used_imports.iter().next().unwrap().to_string()
116 let mut imports = used_imports
118 .map(ToString::to_string)
119 .collect::<Vec<_>>();
124 format!("{{{}}}", imports.join(", "))
128 let sugg = if braced_glob {
131 format!("{}::{}", import_source_snippet, imports_string)
134 let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
135 (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
137 (WILDCARD_IMPORTS, "usage of wildcard import")