packages feed

hs-bindgen-1.0.0.0: src-internal/HsBindgen/Frontend/Analysis/UseDeclGraph.hs

-- | Usage-declaration graph
--
-- Intended for qualified import.
--
-- > import HsBindgen.Frontend.Analysis.UseDeclGraph (UseDeclGraph)
-- > import HsBindgen.Frontend.Analysis.UseDeclGraph qualified as UseDeclGraph
module HsBindgen.Frontend.Analysis.UseDeclGraph (
    -- * Definition
    UseDeclGraph -- opaque
    -- * Construction
  , fromDeclUseGraph
    -- * Query
  , getTransitiveDeps
  , getStrictTransitiveDeps
    -- * Visualization
  , renderMermaid
  ) where

import Data.Digraph (Digraph)
import Data.Digraph qualified as Digraph
import Data.Set qualified as Set

import HsBindgen.Frontend.Analysis
import HsBindgen.Frontend.Analysis.DeclUseGraph.Definition (DeclUseGraph)
import HsBindgen.Frontend.Analysis.DeclUseGraph.Definition qualified as DeclUseGraph
import HsBindgen.Imports
import HsBindgen.IR.C qualified as C

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

-- | Declaration usage-definition graph
--
-- Whenever declaration @A@ uses (depends on) declaration @B@, there is an edge
-- from @A@ to @B@ in this graph.
data UseDeclGraph = UseDeclGraph {
      graph :: Digraph Dependency C.DeclId
    }
  deriving stock (Show, Eq)

{-------------------------------------------------------------------------------
  Construction
-------------------------------------------------------------------------------}

fromDeclUseGraph :: DeclUseGraph -> UseDeclGraph
fromDeclUseGraph declUseGraph = UseDeclGraph{
      graph = Digraph.transpose $ DeclUseGraph.toDigraph declUseGraph
    }

{-------------------------------------------------------------------------------
  Query
-------------------------------------------------------------------------------}

getTransitiveDeps :: UseDeclGraph -> Set C.DeclId -> Set C.DeclId
getTransitiveDeps useDeclGraph decls = Digraph.reaches decls useDeclGraph.graph

getStrictTransitiveDeps :: UseDeclGraph -> Set C.DeclId -> Set C.DeclId
getStrictTransitiveDeps graph decls = getTransitiveDeps graph decls Set.\\ decls

{-------------------------------------------------------------------------------
  Visualization
-------------------------------------------------------------------------------}

renderMermaid :: UseDeclGraph -> String
renderMermaid useDeclGraph = Digraph.renderMermaid opts useDeclGraph.graph
  where
    opts :: Digraph.VisOptions Dependency C.DeclId
    opts = Digraph.VisOptions{
        visVertex = \v -> Digraph.VisVertex{
            label = Just (show v)
          }
      , visEdge   = \e -> Digraph.VisEdge{
            label = Just (show e)
          , style = Digraph.Solid
          }
      , reverseEdges = False
      }