//! This pass is only used for the UNIT TESTS and DEBUGGING NEEDS
//! around dependency graph construction. It serves two purposes; it
//! will dump graphs in graphviz form to disk, and it searches for
//! `#[rustc_if_this_changed]` and `#[rustc_then_this_would_need]`
//! annotations. These annotations can be used to test whether paths
//! exist in the graph. These checks run after codegen, so they view the
//! the final state of the dependency graph. Note that there are
//! similar assertions found in `persist::clean` which check the
//! **initial** state of the dependency graph, just after it has been
//! loaded from disk.
//!
//! In this code, we report errors on each `rustc_if_this_changed`
//! annotation. If a path exists in all cases, then we would report
//! "all path(s) exist". Otherwise, we report: "no path to `foo`" for
//! each case where no path exists. `ui` tests can then be
//! used to check when paths exist or do not.
//!
//! The full form of the `rustc_if_this_changed` annotation is
//! `#[rustc_if_this_changed("foo")]`, which will report a
//! source node of `foo(def_id)`. The `"foo"` is optional and
//! defaults to `"Hir"` if omitted.
//!
//! Example:
//!
//! ```ignore (needs flags)
//! #[rustc_if_this_changed(Hir)]
//! fn foo() { }
//!
//! #[rustc_then_this_would_need(codegen)] //~ ERROR no path from `foo`
//! fn bar() { }
//!
//! #[rustc_then_this_would_need(codegen)] //~ ERROR OK
//! fn baz() { foo(); }
//! ```

use std::env;
use std::fs::{self, File};
use std::io::Write;

use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, NodeIndex, OUTGOING};
use rustc_graphviz as dot;
use rustc_hir as hir;
use rustc_hir::Attribute;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::bug;
use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeFilter, EdgeFilter, RetainedDepGraph};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::{Span, Symbol, sym};
use tracing::debug;

use crate::diagnostics;

#[allow(missing_docs)]
pub(crate) fn assert_dep_graph(tcx: TyCtxt<'_>) {
    tcx.dep_graph.with_ignore(|| {
        // Clone the retained dep graph once and share it between the graph dump and the path
        // checks below, rather than locking and cloning it separately for each.
        let retained_dep_graph = tcx.dep_graph.retained_dep_graph();

        if tcx.sess.opts.unstable_opts.dump_dep_graph {
            if let Some(graph) = &retained_dep_graph {
                dump_graph(graph);
            }
        }

        if !tcx.sess.opts.unstable_opts.query_dep_graph {
            return;
        }

        // if the `rustc_attrs` feature is not enabled, then the
        // attributes we are interested in cannot be present anyway, so
        // skip the walk.
        if !tcx.features().rustc_attrs() {
            return;
        }

        // Find annotations supplied by user (if any).
        let (if_this_changed, then_this_would_need) = {
            let mut visitor =
                IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
            visitor.process_attrs(CRATE_DEF_ID);
            tcx.hir_visit_all_item_likes_in_crate(&mut visitor);
            (visitor.if_this_changed, visitor.then_this_would_need)
        };

        if !if_this_changed.is_empty() || !then_this_would_need.is_empty() {
            assert!(
                tcx.sess.opts.unstable_opts.query_dep_graph,
                "cannot use the `#[{}]` or `#[{}]` annotations \
                    without supplying `-Z query-dep-graph`",
                sym::rustc_if_this_changed,
                sym::rustc_then_this_would_need
            );
        }

        // Check paths.
        check_paths(tcx, retained_dep_graph.as_ref(), &if_this_changed, &then_this_would_need);
    })
}

type Sources = Vec<(Span, DefId, DepNode)>;
type Targets = Vec<(Span, Symbol, hir::HirId, DepNode)>;

struct IfThisChanged<'tcx> {
    tcx: TyCtxt<'tcx>,
    if_this_changed: Sources,
    then_this_would_need: Targets,
}

impl<'tcx> IfThisChanged<'tcx> {
    fn process_attrs(&mut self, def_id: LocalDefId) {
        let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
        let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
        let attrs = self.tcx.hir_attrs(hir_id);
        for attr in attrs {
            if let Attribute::Parsed(AttributeKind::RustcIfThisChanged(span, dep_node)) = *attr {
                let dep_node = match dep_node {
                    None => {
                        DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
                    }
                    Some(n) => {
                        match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
                            Ok(n) => n,
                            Err(()) => self
                                .tcx
                                .dcx()
                                .emit_fatal(diagnostics::UnrecognizedDepNode { span, name: n }),
                        }
                    }
                };
                self.if_this_changed.push((span, def_id.to_def_id(), dep_node));
            } else if let Attribute::Parsed(AttributeKind::RustcThenThisWouldNeed(dep_nodes)) = attr
            {
                for &n in dep_nodes {
                    let Ok(dep_node) =
                        DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash)
                    else {
                        self.tcx.dcx().emit_fatal(diagnostics::UnrecognizedDepNode {
                            span: n.span,
                            name: n.name,
                        });
                    };
                    self.then_this_would_need.push((n.span, n.name, hir_id, dep_node));
                }
            }
        }
    }
}

impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> {
    type NestedFilter = nested_filter::OnlyBodies;

    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
        self.tcx
    }

    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
        self.process_attrs(item.owner_id.def_id);
        intravisit::walk_item(self, item);
    }

    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
        self.process_attrs(trait_item.owner_id.def_id);
        intravisit::walk_trait_item(self, trait_item);
    }

    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
        self.process_attrs(impl_item.owner_id.def_id);
        intravisit::walk_impl_item(self, impl_item);
    }

    fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
        self.process_attrs(s.def_id);
        intravisit::walk_field_def(self, s);
    }
}

fn check_paths<'tcx>(
    tcx: TyCtxt<'tcx>,
    retained_dep_graph: Option<&RetainedDepGraph>,
    if_this_changed: &Sources,
    then_this_would_need: &Targets,
) {
    if if_this_changed.is_empty() {
        for &(target_span, _, _, _) in then_this_would_need {
            tcx.dcx().emit_err(diagnostics::MissingIfThisChanged { span: target_span });
        }
        return;
    }
    let Some(query) = retained_dep_graph else { return };
    for &(_, source_def_id, ref source_dep_node) in if_this_changed {
        let dependents = query.transitive_predecessors(source_dep_node);
        for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
            if !dependents.contains(&target_dep_node) {
                tcx.dcx().emit_err(diagnostics::NoPath {
                    span: target_span,
                    source: tcx.def_path_str(source_def_id),
                    target: *target_pass,
                });
            } else {
                tcx.dcx().emit_err(diagnostics::Ok { span: target_span });
            }
        }
    }
}

fn dump_graph(graph: &RetainedDepGraph) {
    let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| "dep_graph".to_string());

    let nodes = match env::var("RUST_DEP_GRAPH_FILTER") {
        Ok(string) => {
            // Expect one of: "-> target", "source -> target", or "source ->".
            let edge_filter =
                EdgeFilter::new(&string).unwrap_or_else(|e| bug!("invalid filter: {}", e));
            let sources = node_set(graph, &edge_filter.source);
            let targets = node_set(graph, &edge_filter.target);
            filter_nodes(graph, &sources, &targets)
        }
        Err(_) => graph.nodes().into_iter().map(|n| n.kind).collect(),
    };
    let edges = filter_edges(graph, &nodes);

    {
        // dump a .txt file with just the edges:
        let txt_path = format!("{path}.txt");
        let mut file = File::create_buffered(&txt_path).unwrap();
        for (source, target) in &edges {
            write!(file, "{source:?} -> {target:?}\n").unwrap();
        }
    }

    {
        // dump a .dot file in graphviz format:
        let dot_path = format!("{path}.dot");
        let mut v = Vec::new();
        dot::render(&GraphvizDepGraph(nodes, edges), &mut v).unwrap();
        fs::write(dot_path, v).unwrap();
    }
}

#[allow(missing_docs)]
struct GraphvizDepGraph(FxIndexSet<DepKind>, Vec<(DepKind, DepKind)>);

impl<'a> dot::GraphWalk<'a> for GraphvizDepGraph {
    type Node = DepKind;
    type Edge = (DepKind, DepKind);
    fn nodes(&self) -> dot::Nodes<'_, DepKind> {
        let nodes: Vec<_> = self.0.iter().cloned().collect();
        nodes.into()
    }
    fn edges(&self) -> dot::Edges<'_, (DepKind, DepKind)> {
        self.1[..].into()
    }
    fn source(&self, edge: &(DepKind, DepKind)) -> DepKind {
        edge.0
    }
    fn target(&self, edge: &(DepKind, DepKind)) -> DepKind {
        edge.1
    }
}

impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
    type Node = DepKind;
    type Edge = (DepKind, DepKind);
    fn graph_id(&self) -> dot::Id<'_> {
        dot::Id::new("DependencyGraph").unwrap()
    }
    fn node_id(&self, n: &DepKind) -> dot::Id<'_> {
        let s: String = format!("{n:?}")
            .chars()
            .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
            .collect();
        debug!("n={:?} s={:?}", n, s);
        dot::Id::new(s).unwrap()
    }
    fn node_label(&self, n: &DepKind) -> dot::LabelText<'_> {
        dot::LabelText::label(format!("{n:?}"))
    }
}

// Given an optional filter like `"x,y,z"`, returns either `None` (no
// filter) or the set of nodes whose labels contain all of those
// substrings.
fn node_set<'g>(
    graph: &'g RetainedDepGraph,
    filter: &DepNodeFilter,
) -> Option<FxIndexSet<&'g DepNode>> {
    debug!("node_set(filter={:?})", filter);

    if filter.accepts_all() {
        return None;
    }

    Some(graph.nodes().into_iter().filter(|n| filter.test(n)).collect())
}

fn filter_nodes<'g>(
    graph: &'g RetainedDepGraph,
    sources: &Option<FxIndexSet<&'g DepNode>>,
    targets: &Option<FxIndexSet<&'g DepNode>>,
) -> FxIndexSet<DepKind> {
    if let Some(sources) = sources {
        if let Some(targets) = targets {
            walk_between(graph, sources, targets)
        } else {
            walk_nodes(graph, sources, OUTGOING)
        }
    } else if let Some(targets) = targets {
        walk_nodes(graph, targets, INCOMING)
    } else {
        graph.nodes().into_iter().map(|n| n.kind).collect()
    }
}

fn walk_nodes<'g>(
    graph: &'g RetainedDepGraph,
    starts: &FxIndexSet<&'g DepNode>,
    direction: Direction,
) -> FxIndexSet<DepKind> {
    let mut set = FxIndexSet::default();
    for &start in starts {
        debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
        if set.insert(start.kind) {
            let mut stack = vec![graph.indices[start]];
            while let Some(index) = stack.pop() {
                for (_, edge) in graph.inner.adjacent_edges(index, direction) {
                    let neighbor_index = edge.source_or_target(direction);
                    let neighbor = graph.inner.node_data(neighbor_index);
                    if set.insert(neighbor.kind) {
                        stack.push(neighbor_index);
                    }
                }
            }
        }
    }
    set
}

fn walk_between<'g>(
    graph: &'g RetainedDepGraph,
    sources: &FxIndexSet<&'g DepNode>,
    targets: &FxIndexSet<&'g DepNode>,
) -> FxIndexSet<DepKind> {
    // This is a bit tricky. We want to include a node only if it is:
    // (a) reachable from a source and (b) will reach a target. And we
    // have to be careful about cycles etc. Luckily efficiency is not
    // a big concern!

    #[derive(Copy, Clone, PartialEq)]
    enum State {
        Undecided,
        Deciding,
        Included,
        Excluded,
    }

    let mut node_states = vec![State::Undecided; graph.inner.len_nodes()];

    for &target in targets {
        node_states[graph.indices[target].0] = State::Included;
    }

    for source in sources.iter().map(|&n| graph.indices[n]) {
        recurse(graph, &mut node_states, source);
    }

    return graph
        .nodes()
        .into_iter()
        .filter(|&n| {
            let index = graph.indices[n];
            node_states[index.0] == State::Included
        })
        .map(|n| n.kind)
        .collect();

    fn recurse(graph: &RetainedDepGraph, node_states: &mut [State], node: NodeIndex) -> bool {
        match node_states[node.0] {
            // known to reach a target
            State::Included => return true,

            // known not to reach a target
            State::Excluded => return false,

            // backedge, not yet known, say false
            State::Deciding => return false,

            State::Undecided => {}
        }

        node_states[node.0] = State::Deciding;

        for neighbor_index in graph.inner.successor_nodes(node) {
            if recurse(graph, node_states, neighbor_index) {
                node_states[node.0] = State::Included;
            }
        }

        // if we didn't find a path to target, then set to excluded
        if node_states[node.0] == State::Deciding {
            node_states[node.0] = State::Excluded;
            false
        } else {
            assert!(node_states[node.0] == State::Included);
            true
        }
    }
}

fn filter_edges(graph: &RetainedDepGraph, nodes: &FxIndexSet<DepKind>) -> Vec<(DepKind, DepKind)> {
    let uniq: FxIndexSet<_> = graph
        .edges()
        .into_iter()
        .map(|(s, t)| (s.kind, t.kind))
        .filter(|(source, target)| nodes.contains(source) && nodes.contains(target))
        .collect();
    uniq.into_iter().collect()
}
