//
// Unused import checking
//
// Although this is mostly a lint pass, it lives in here because it depends on
// resolve data structures and because it finalises the privacy information for
// `use` items.
//
// Unused trait imports can't be checked until the method resolution. We save
// candidates here, and do the actual check in rustc_hir_analysis/check_unused.rs.
//
// Checking for unused imports is split into three steps:
//
//  - `UnusedImportCheckVisitor` walks the AST to find all the unused imports
//    inside of `UseTree`s, recording their `NodeId`s and grouping them by
//    the parent `use` item
//
//  - `calc_unused_spans` then walks over all the `use` items marked in the
//    previous step to collect the spans associated with the `NodeId`s and to
//    calculate the spans that can be removed by rustfix; This is done in a
//    separate step to be able to collapse the adjacent spans that rustfix
//    will remove
//
//  - `check_unused` finally emits the diagnostics based on the data generated
//    in the last step

use rustc_ast as ast;
use rustc_ast::visit::{self, Visitor};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::unord::UnordSet;
use rustc_errors::MultiSpan;
use rustc_hir::def::{DefKind, Res};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{
    MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS,
};
use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw};

use crate::imports::{Import, ImportKind};
use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string};

struct UnusedImport {
    use_tree: ast::UseTree,
    use_tree_id: ast::NodeId,
    item_span: Span,
    unused: UnordSet<ast::NodeId>,
}

impl UnusedImport {
    fn add(&mut self, id: ast::NodeId) {
        self.unused.insert(id);
    }
}

struct UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
    r: &'a mut Resolver<'ra, 'tcx>,
    /// All the (so far) unused imports, grouped path list
    unused_imports: FxIndexMap<ast::NodeId, UnusedImport>,
    extern_crate_items: Vec<ExternCrateToLint>,
    base_use_tree: Option<&'a ast::UseTree>,
    base_id: ast::NodeId,
    item_span: Span,
}

struct ExternCrateToLint {
    id: ast::NodeId,
    /// Span from the item
    span: Span,
    /// Span to use to suggest complete removal.
    span_with_attributes: Span,
    /// Span of the visibility, if any.
    vis_span: Span,
    /// Whether the item has attrs.
    has_attrs: bool,
    /// Name used to refer to the crate.
    ident: Ident,
    /// Whether the statement renames the crate `extern crate orig_name as new_name;`.
    renames: bool,
}

impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
    // We have information about whether `use` (import) items are actually
    // used now. If an import is not used at all, we signal a lint error.
    fn check_import(&mut self, id: ast::NodeId) {
        let used = self.r.used_imports.contains(&id);
        let def_id = self.r.local_def_id(id);
        if !used {
            if self.r.maybe_unused_trait_imports.contains(&def_id) {
                // Check later.
                return;
            }
            self.unused_import(self.base_id).add(id);
        } else {
            // This trait import is definitely used, in a way other than
            // method resolution.
            // FIXME(#120456) - is `swap_remove` correct?
            self.r.maybe_unused_trait_imports.swap_remove(&def_id);
            if let Some(i) = self.unused_imports.get_mut(&self.base_id) {
                i.unused.remove(&id);
            }
        }
    }

    fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) {
        if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) {
            self.check_import_as_underscore(use_tree, id);
            return;
        }

        if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
            if items.is_empty() {
                self.unused_import(self.base_id).add(id);
            }
        } else {
            self.check_import(id);
        }
    }

    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport {
        let use_tree_id = self.base_id;
        let use_tree = self.base_use_tree.unwrap().clone();
        let item_span = self.item_span;

        self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
            use_tree,
            use_tree_id,
            item_span,
            unused: Default::default(),
        })
    }

    fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) {
        match item.kind {
            ast::UseTreeKind::Simple(Some(ident)) => {
                if ident.name == kw::Underscore
                    && !self.r.import_res_map.get(&id).is_some_and(|per_ns| {
                        matches!(
                            per_ns.type_ns,
                            Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
                        )
                    })
                {
                    self.unused_import(self.base_id).add(id);
                }
            }
            ast::UseTreeKind::Nested { ref items, .. } => self.check_imports_as_underscore(items),
            _ => {}
        }
    }

    fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) {
        for (item, id) in items {
            self.check_import_as_underscore(item, *id);
        }
    }

    fn report_unused_extern_crate_items(
        &mut self,
        maybe_unused_extern_crates: FxHashMap<ast::NodeId, Span>,
    ) {
        let tcx = self.r.tcx();
        for extern_crate in &self.extern_crate_items {
            let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');

            // If the crate is fully unused, we suggest removing it altogether.
            // We do this in any edition.
            if warn_if_unused {
                if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
                    self.r.lint_buffer.buffer_lint(
                        UNUSED_EXTERN_CRATES,
                        extern_crate.id,
                        span,
                        crate::errors::UnusedExternCrate {
                            span: extern_crate.span,
                            removal_span: extern_crate.span_with_attributes,
                        },
                    );
                    continue;
                }
            }

            // If we are not in Rust 2018 edition, then we don't make any further
            // suggestions.
            if !tcx.sess.at_least_rust_2018() {
                continue;
            }

            // If the extern crate has any attributes, they may have funky
            // semantics we can't faithfully represent using `use` (most
            // notably `#[macro_use]`). Ignore it.
            if extern_crate.has_attrs {
                continue;
            }

            // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
            // would not insert the new name into the prelude, where other imports in the crate may be
            // expecting it.
            if extern_crate.renames {
                continue;
            }

            // If the extern crate isn't in the extern prelude,
            // there is no way it can be written as a `use`.
            if self
                .r
                .extern_prelude
                .get(&Macros20NormalizedIdent::new(extern_crate.ident))
                .is_none_or(|entry| entry.introduced_by_item())
            {
                continue;
            }

            let module = self
                .r
                .get_nearest_non_block_module(self.r.local_def_id(extern_crate.id).to_def_id());
            if module.no_implicit_prelude {
                // If the module has `no_implicit_prelude`, then we don't suggest
                // replacing the extern crate with a use, as it would not be
                // inserted into the prelude. User writes `extern` style deliberately.
                continue;
            }

            let vis_span = extern_crate
                .vis_span
                .find_ancestor_inside(extern_crate.span)
                .unwrap_or(extern_crate.vis_span);
            let ident_span = extern_crate
                .ident
                .span
                .find_ancestor_inside(extern_crate.span)
                .unwrap_or(extern_crate.ident.span);
            self.r.lint_buffer.buffer_lint(
                UNUSED_EXTERN_CRATES,
                extern_crate.id,
                extern_crate.span,
                BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
            );
        }
    }
}

impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
    fn visit_item(&mut self, item: &'a ast::Item) {
        self.item_span = item.span_with_attributes();
        match &item.kind {
            // Ignore is_public import statements because there's no way to be sure
            // whether they're used or not. Also ignore imports with a dummy span
            // because this means that they were generated in some fashion by the
            // compiler and we don't need to consider them.
            ast::ItemKind::Use(..) if item.span.is_dummy() => return,
            // Use the base UseTree's NodeId as the item id
            // This allows the grouping of all the lints in the same item
            ast::ItemKind::Use(use_tree) => {
                self.base_id = item.id;
                self.base_use_tree = Some(use_tree);
                self.check_use_tree(use_tree, item.id);
            }
            &ast::ItemKind::ExternCrate(orig_name, ident) => {
                self.extern_crate_items.push(ExternCrateToLint {
                    id: item.id,
                    span: item.span,
                    vis_span: item.vis.span,
                    span_with_attributes: item.span_with_attributes(),
                    has_attrs: !item.attrs.is_empty(),
                    ident,
                    renames: orig_name.is_some(),
                });
            }
            _ => {}
        }

        visit::walk_item(self, item);
    }

    fn visit_nested_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) {
        self.check_use_tree(use_tree, id);
        visit::walk_use_tree(self, use_tree);
    }
}

enum UnusedSpanResult {
    Used,
    Unused { spans: Vec<Span>, remove: Span },
    PartialUnused { spans: Vec<Span>, remove: Vec<Span> },
}

fn calc_unused_spans(
    unused_import: &UnusedImport,
    use_tree: &ast::UseTree,
    use_tree_id: ast::NodeId,
) -> UnusedSpanResult {
    // The full span is the whole item's span if this current tree is not nested inside another
    // This tells rustfix to remove the whole item if all the imports are unused
    let full_span = if unused_import.use_tree.span == use_tree.span {
        unused_import.item_span
    } else {
        use_tree.span
    };
    match use_tree.kind {
        ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob => {
            if unused_import.unused.contains(&use_tree_id) {
                UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span }
            } else {
                UnusedSpanResult::Used
            }
        }
        ast::UseTreeKind::Nested { items: ref nested, span: tree_span } => {
            if nested.is_empty() {
                return UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span };
            }

            let mut unused_spans = Vec::new();
            let mut to_remove = Vec::new();
            let mut used_children = 0;
            let mut contains_self = false;
            let mut previous_unused = false;
            for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() {
                let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) {
                    UnusedSpanResult::Used => {
                        used_children += 1;
                        None
                    }
                    UnusedSpanResult::Unused { mut spans, remove } => {
                        unused_spans.append(&mut spans);
                        Some(remove)
                    }
                    UnusedSpanResult::PartialUnused { mut spans, remove: mut to_remove_extra } => {
                        used_children += 1;
                        unused_spans.append(&mut spans);
                        to_remove.append(&mut to_remove_extra);
                        None
                    }
                };
                if let Some(remove) = remove {
                    let remove_span = if nested.len() == 1 {
                        remove
                    } else if pos == nested.len() - 1 || used_children > 0 {
                        // Delete everything from the end of the last import, to delete the
                        // previous comma
                        nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span)
                    } else {
                        // Delete everything until the next import, to delete the trailing commas
                        use_tree.span.to(nested[pos + 1].0.span.shrink_to_lo())
                    };

                    // Try to collapse adjacent spans into a single one. This prevents all cases of
                    // overlapping removals, which are not supported by rustfix
                    if previous_unused && !to_remove.is_empty() {
                        let previous = to_remove.pop().unwrap();
                        to_remove.push(previous.to(remove_span));
                    } else {
                        to_remove.push(remove_span);
                    }
                }
                contains_self |= use_tree.prefix == kw::SelfLower
                    && matches!(use_tree.kind, ast::UseTreeKind::Simple(_))
                    && !unused_import.unused.contains(&use_tree_id);
                previous_unused = remove.is_some();
            }
            if unused_spans.is_empty() {
                UnusedSpanResult::Used
            } else if used_children == 0 {
                UnusedSpanResult::Unused { spans: unused_spans, remove: full_span }
            } else {
                // If there is only one remaining child that is used, the braces around the use
                // tree are not needed anymore. In that case, we determine the span of the left
                // brace and the right brace, and tell rustfix to remove them as well.
                //
                // This means that `use a::{B, C};` will be turned into `use a::B;` rather than
                // `use a::{B};`, removing a rustfmt roundtrip.
                //
                // Note that we cannot remove the braces if the only item inside the use tree is
                // `self`: `use foo::{self};` is valid Rust syntax, while `use foo::self;` errors
                // out. We also cannot turn `use foo::{self}` into `use foo`, as the former doesn't
                // import types with the same name as the module.
                if used_children == 1 && !contains_self {
                    // Left brace, from the start of the nested group to the first item.
                    to_remove.push(
                        tree_span.shrink_to_lo().to(nested.first().unwrap().0.span.shrink_to_lo()),
                    );
                    // Right brace, from the end of the last item to the end of the nested group.
                    to_remove.push(
                        nested.last().unwrap().0.span.shrink_to_hi().to(tree_span.shrink_to_hi()),
                    );
                }

                UnusedSpanResult::PartialUnused { spans: unused_spans, remove: to_remove }
            }
        }
    }
}

impl Resolver<'_, '_> {
    pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
        let tcx = self.tcx;
        let mut maybe_unused_extern_crates = FxHashMap::default();

        for import in self.potentially_unused_imports.iter() {
            match import.kind {
                _ if import.vis.is_public()
                    || import.span.is_dummy()
                    || self.import_use_map.contains_key(import) =>
                {
                    if let ImportKind::MacroUse { .. } = import.kind {
                        if !import.span.is_dummy() {
                            self.lint_buffer.buffer_lint(
                                MACRO_USE_EXTERN_CRATE,
                                import.root_id,
                                import.span,
                                crate::errors::MacroUseDeprecated,
                            );
                        }
                    }
                }
                ImportKind::ExternCrate { id, .. } => {
                    let def_id = self.local_def_id(id);
                    if self.extern_crate_map.get(&def_id).is_none_or(|&cnum| {
                        !tcx.is_compiler_builtins(cnum)
                            && !tcx.is_panic_runtime(cnum)
                            && !tcx.has_global_allocator(cnum)
                            && !tcx.has_panic_handler(cnum)
                    }) {
                        maybe_unused_extern_crates.insert(id, import.span);
                    }
                }
                ImportKind::MacroUse { .. } => {
                    self.lint_buffer.buffer_lint(
                        UNUSED_IMPORTS,
                        import.root_id,
                        import.span,
                        crate::errors::UnusedMacroUse,
                    );
                }
                _ => {}
            }
        }

        let mut visitor = UnusedImportCheckVisitor {
            r: self,
            unused_imports: Default::default(),
            extern_crate_items: Default::default(),
            base_use_tree: None,
            base_id: ast::DUMMY_NODE_ID,
            item_span: DUMMY_SP,
        };
        visit::walk_crate(&mut visitor, krate);

        visitor.report_unused_extern_crate_items(maybe_unused_extern_crates);

        for unused in visitor.unused_imports.values() {
            let (spans, remove_spans) =
                match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
                    UnusedSpanResult::Used => continue,
                    UnusedSpanResult::Unused { spans, remove } => (spans, vec![remove]),
                    UnusedSpanResult::PartialUnused { spans, remove } => (spans, remove),
                };

            let ms = MultiSpan::from_spans(spans);

            let mut span_snippets = ms
                .primary_spans()
                .iter()
                .filter_map(|span| tcx.sess.source_map().span_to_snippet(*span).ok())
                .map(|s| format!("`{s}`"))
                .collect::<Vec<String>>();
            span_snippets.sort();

            let remove_whole_use = remove_spans.len() == 1 && remove_spans[0] == unused.item_span;
            let num_to_remove = ms.primary_spans().len();

            // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
            // attribute; however, if not, suggest adding the attribute. There is no way to
            // retrieve attributes here because we do not have a `TyCtxt` yet.
            let test_module_span = if tcx.sess.is_test_crate() {
                None
            } else {
                let parent_module = visitor.r.get_nearest_non_block_module(
                    visitor.r.local_def_id(unused.use_tree_id).to_def_id(),
                );
                match module_to_string(parent_module) {
                    Some(module)
                        if module == "test"
                            || module == "tests"
                            || module.starts_with("test_")
                            || module.starts_with("tests_")
                            || module.ends_with("_test")
                            || module.ends_with("_tests") =>
                    {
                        Some(parent_module.span)
                    }
                    _ => None,
                }
            };

            visitor.r.lint_buffer.buffer_lint(
                UNUSED_IMPORTS,
                unused.use_tree_id,
                ms,
                BuiltinLintDiag::UnusedImports {
                    remove_whole_use,
                    num_to_remove,
                    remove_spans,
                    test_module_span,
                    span_snippets,
                },
            );
        }

        let unused_imports = visitor.unused_imports;
        let mut check_redundant_imports = FxIndexSet::default();
        for module in self.arenas.local_modules().iter() {
            for (_key, resolution) in self.resolutions(*module).borrow().iter() {
                if let Some(binding) = resolution.borrow().best_binding()
                    && let NameBindingKind::Import { import, .. } = binding.kind
                    && let ImportKind::Single { id, .. } = import.kind
                {
                    if let Some(unused_import) = unused_imports.get(&import.root_id)
                        && unused_import.unused.contains(&id)
                    {
                        continue;
                    }

                    check_redundant_imports.insert(import);
                }
            }
        }

        let mut redundant_imports = UnordSet::default();
        for import in check_redundant_imports {
            if self.check_for_redundant_imports(import)
                && let Some(id) = import.id()
            {
                redundant_imports.insert(id);
            }
        }

        // The lint fixes for unused_import and unnecessary_qualification may conflict.
        // Deleting both unused imports and unnecessary segments of an item may result
        // in the item not being found.
        for unn_qua in &self.potentially_unnecessary_qualifications {
            if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding
                && let NameBindingKind::Import { import, .. } = name_binding.kind
                && (is_unused_import(import, &unused_imports)
                    || is_redundant_import(import, &redundant_imports))
            {
                continue;
            }

            self.lint_buffer.buffer_lint(
                UNUSED_QUALIFICATIONS,
                unn_qua.node_id,
                unn_qua.path_span,
                BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span },
            );
        }

        fn is_redundant_import(
            import: Import<'_>,
            redundant_imports: &UnordSet<ast::NodeId>,
        ) -> bool {
            if let Some(id) = import.id()
                && redundant_imports.contains(&id)
            {
                return true;
            }
            false
        }

        fn is_unused_import(
            import: Import<'_>,
            unused_imports: &FxIndexMap<ast::NodeId, UnusedImport>,
        ) -> bool {
            if let Some(unused_import) = unused_imports.get(&import.root_id)
                && let Some(id) = import.id()
                && unused_import.unused.contains(&id)
            {
                return true;
            }
            false
        }
    }
}
