1 use clippy_utils::diagnostics::span_lint_and_help;
2 use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
3 use rustc_errors::MultiSpan;
4 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
5 use rustc_session::{declare_tool_lint, impl_lint_pass};
6 use rustc_span::{FileName, Span};
7 use std::collections::BTreeMap;
8 use std::path::PathBuf;
10 declare_clippy_lint! {
12 /// Checks for files that are included as modules multiple times.
14 /// ### Why is this bad?
15 /// Loading a file as a module more than once causes it to be compiled
16 /// multiple times, taking longer and putting duplicate content into the
27 /// #[path = "./b.rs"]
42 #[clippy::version = "1.62.0"]
45 "file loaded as module multiple times"
48 #[derive(PartialOrd, Ord, PartialEq, Eq)]
55 pub struct DuplicateMod {
56 /// map from the canonicalized path to `Modules`, `BTreeMap` to make the
57 /// order deterministic for tests
58 modules: BTreeMap<PathBuf, Modules>,
61 impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
63 impl EarlyLintPass for DuplicateMod {
64 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
65 if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind
66 && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
67 && let Some(local_path) = real.into_local_path()
68 && let Ok(absolute_path) = local_path.canonicalize()
70 let modules = self.modules.entry(absolute_path).or_insert(Modules {
74 modules.spans.push(item.span_with_attributes());
78 fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
79 for Modules { local_path, spans } in self.modules.values() {
84 let mut multi_span = MultiSpan::from_spans(spans.clone());
85 let (&first, duplicates) = spans.split_first().unwrap();
87 multi_span.push_span_label(first, "first loaded here");
88 for &duplicate in duplicates {
89 multi_span.push_span_label(duplicate, "loaded again here");
96 &format!("file is loaded as a module multiple times: `{}`", local_path.display()),
98 "replace all but one `mod` item with `use` items",