1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::is_test_module_or_function
;
3 use clippy_utils
::source
::{snippet, snippet_with_applicability}
;
4 use if_chain
::if_chain
;
5 use rustc_errors
::Applicability
;
8 Item
, ItemKind
, PathSegment
, UseKind
,
10 use rustc_lint
::{LateContext, LateLintPass}
;
12 use rustc_session
::{declare_tool_lint, impl_lint_pass}
;
13 use rustc_span
::symbol
::kw
;
14 use rustc_span
::{sym, BytePos}
;
16 declare_clippy_lint
! {
18 /// Checks for `use Enum::*`.
20 /// ### Why is this bad?
21 /// It is usually better style to use the prefixed name of
22 /// an enumeration variant, rather than importing variants.
24 /// ### Known problems
25 /// Old-style enumerations that prefix the variants are
30 /// use std::cmp::Ordering::*;
32 /// # fn foo(_: std::cmp::Ordering) {}
38 /// use std::cmp::Ordering;
40 /// # fn foo(_: Ordering) {}
41 /// foo(Ordering::Less)
43 #[clippy::version = "pre 1.29.0"]
46 "use items that import all variants of an enum"
49 declare_clippy_lint
! {
51 /// Checks for wildcard imports `use _::*`.
53 /// ### Why is this bad?
54 /// wildcard imports can pollute the namespace. This is especially bad if
55 /// you try to import something through a wildcard, that already has been imported by name from
56 /// a different source:
59 /// use crate1::foo; // Imports a function named foo
60 /// use crate2::*; // Has a function named foo
62 /// foo(); // Calls crate1::foo
65 /// This can lead to confusing error messages at best and to unexpected behavior at worst.
68 /// Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
69 /// provide modules named "prelude" specifically designed for wildcard import.
71 /// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
73 /// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
75 /// ### Known problems
76 /// If macros are imported through the wildcard, this macro is not included
77 /// by the suggestion and has to be added by hand.
79 /// Applying the suggestion when explicit imports of the things imported with a glob import
80 /// exist, may result in `unused_imports` warnings.
95 #[clippy::version = "1.43.0"]
98 "lint `use _::*` statements"
102 pub struct WildcardImports
{
104 test_modules_deep
: u32,
107 impl WildcardImports
{
108 pub fn new(warn_on_all
: bool
) -> Self {
111 test_modules_deep
: 0,
116 impl_lint_pass
!(WildcardImports
=> [ENUM_GLOB_USE
, WILDCARD_IMPORTS
]);
118 impl LateLintPass
<'_
> for WildcardImports
{
119 fn check_item(&mut self, cx
: &LateContext
<'_
>, item
: &Item
<'_
>) {
120 if is_test_module_or_function(cx
.tcx
, item
) {
121 self.test_modules_deep
= self.test_modules_deep
.saturating_add(1);
123 let module
= cx
.tcx
.parent_module_from_def_id(item
.owner_id
.def_id
);
124 if cx
.tcx
.visibility(item
.owner_id
.def_id
) != ty
::Visibility
::Restricted(module
.to_def_id()) {
128 if let ItemKind
::Use(use_path
, UseKind
::Glob
) = &item
.kind
;
129 if self.warn_on_all
|| !self.check_exceptions(item
, use_path
.segments
);
130 let used_imports
= cx
.tcx
.names_imported_by_glob_use(item
.owner_id
.def_id
);
131 if !used_imports
.is_empty(); // Already handled by `unused_imports`
133 let mut applicability
= Applicability
::MachineApplicable
;
134 let import_source_snippet
= snippet_with_applicability(cx
, use_path
.span
, "..", &mut applicability
);
135 let (span
, braced_glob
) = if import_source_snippet
.is_empty() {
136 // This is a `_::{_, *}` import
137 // In this case `use_path.span` is empty and ends directly in front of the `*`,
138 // so we need to extend it by one byte.
140 use_path
.span
.with_hi(use_path
.span
.hi() + BytePos(1)),
144 // In this case, the `use_path.span` ends right before the `::*`, so we need to
145 // extend it up to the `*`. Since it is hard to find the `*` in weird
146 // formattings like `use _ :: *;`, we extend it up to, but not including the
147 // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
148 // can just use the end of the item span
149 let mut span
= use_path
.span
.with_hi(item
.span
.hi());
150 if snippet(cx
, span
, "").ends_with('
;'
) {
151 span
= use_path
.span
.with_hi(item
.span
.hi() - BytePos(1));
158 let mut imports
= used_imports
.items().map(ToString
::to_string
).into_sorted_stable_ord(false);
159 let imports_string
= if imports
.len() == 1 {
160 imports
.pop().unwrap()
161 } else if braced_glob
{
164 format
!("{{{}}}", imports
.join(", "))
167 let sugg
= if braced_glob
{
170 format
!("{import_source_snippet}::{imports_string}")
173 // Glob imports always have a single resolution.
174 let (lint
, message
) = if let Res
::Def(DefKind
::Enum
, _
) = use_path
.res
[0] {
175 (ENUM_GLOB_USE
, "usage of wildcard import for enum variants")
177 (WILDCARD_IMPORTS
, "usage of wildcard import")
193 fn check_item_post(&mut self, cx
: &LateContext
<'_
>, item
: &Item
<'_
>) {
194 if is_test_module_or_function(cx
.tcx
, item
) {
195 self.test_modules_deep
= self.test_modules_deep
.saturating_sub(1);
200 impl WildcardImports
{
201 fn check_exceptions(&self, item
: &Item
<'_
>, segments
: &[PathSegment
<'_
>]) -> bool
{
202 item
.span
.from_expansion()
203 || is_prelude_import(segments
)
204 || (is_super_only_import(segments
) && self.test_modules_deep
> 0)
208 // Allow "...prelude::..::*" imports.
209 // Many crates have a prelude, and it is imported as a glob by design.
210 fn is_prelude_import(segments
: &[PathSegment
<'_
>]) -> bool
{
211 segments
.iter().any(|ps
| ps
.ident
.name
== sym
::prelude
)
214 // Allow "super::*" imports in tests.
215 fn is_super_only_import(segments
: &[PathSegment
<'_
>]) -> bool
{
216 segments
.len() == 1 && segments
[0].ident
.name
== kw
::Super