packages feed

SourceGraph-0.1: Analyse/Everything.hs

{-
Copyright (C) 2008 Ivan Lazar Miljenovic <Ivan.Miljenovic@gmail.com>

This file is part of SourceGraph.

SourceGraph is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-}

{- |
   Module      : Analyse.Software
   Description : Analyse Haskell software
   Copyright   : (c) Ivan Lazar Miljenovic 2008
   License     : GPL-3 or later.
   Maintainer  : Ivan.Miljenovic@gmail.com

   Analysis of the entire overall piece of software.
 -}
module Analyse.Everything where

import Parsing.Types
import Analyse.Utils

import Data.Graph.Analysis

import Data.Maybe
import Text.Printf
import System.Random

type CodeData = GraphData Function


-- | Performs analysis of the entire codebase.
analyseEverything :: (RandomGen g) => g -> [ModuleName] -> HaskellModules
                  -> DocElement
analyseEverything g exps hm = Section title elems
    where
      cd = codeToGraph exps hm
      title = Text "Analysis of the entire codebase"
      elems = catMaybes
              $ map ($cd) [ graphOf
                          , clustersOf g
                          , collapseAnal
                          , coreAnal
                          , cycleCompAnal
                          , rootAnal
                          , componentAnal
                          , cliqueAnal
                          , cycleAnal
                          , chainAnal
                          ]


codeToGraph          :: [ModuleName] -> HaskellModules -> CodeData
codeToGraph exps hms = importData params
    where
      exps' = concat . catMaybes $ map (fmap exports . getModule hms) exps
      fl = combineCalls .map functions $ hModulesIn hms
      params = Params { dataPoints    = functionsIn fl
                      , relationships = functionEdges fl
                      , roots         = exps'
                      , directed      = True
                      }

graphOf    :: CodeData -> Maybe DocElement
graphOf cd = Just $ Section title [gc]
    where
      title = Text "Visualisation of the entire software"
      gc = GraphImage $ applyAlg dg cd
      dg g = toGraph "code" label g
      label = "Software visualisation"

clustersOf      :: (RandomGen g) => g -> CodeData -> Maybe DocElement
clustersOf g cd = Just $ Section title [text, gc, textAfter, cw, rng]
    where
      title = Text "Visualisation of overall function calls"
      gc = GraphImage $ applyAlg dg cd
      text = Paragraph
             [Text "Here is the current module grouping of functions:"]
      dg gr = toClusters "codeCluster" label gr
      label = "Module groupings"
      textAfter = Paragraph [Text "Here are two proposed module groupings:"]
      cw = GraphImage
           . toClusters "codeCW" "Chinese Whispers module suggestions"
           $ applyAlg (chineseWhispers g) cd
      rng = GraphImage
            . toClusters "codeRNG" "Relative Neighbourhood module suggestions"
            $ applyAlg relativeNeighbourhood cd

componentAnal :: CodeData -> Maybe DocElement
componentAnal cd
    | single comp = Nothing
    | otherwise   = Just elem
    where
      comp = applyAlg componentsOf cd
      len = length comp
      elem = Section title [Paragraph [Text text]]
      title = Text "Function component analysis"
      text = printf "The functions are split up into %d components.  \
                     \You may wish to consider splitting the code up \
                     \into multiple libraries." len

cliqueAnal :: CodeData -> Maybe DocElement
cliqueAnal cd
    | null clqs = Nothing
    | otherwise = Just elem
    where
      clqs = applyAlg cliquesIn cd
      clqs' = map (Paragraph . return . Text . showNodes) clqs
      text = Text "The code has the following cliques:"
      elem = Section title $ (Paragraph [text]) : clqs'
      title = Text "Overall clique analysis"

cycleAnal :: CodeData -> Maybe DocElement
cycleAnal cd
    | null cycs = Nothing
    | otherwise = Just elem
    where
      cycs = applyAlg uniqueCycles cd
      cycs' = map (Paragraph . return . Text . showCycle) cycs
      text = Text "The code has the following non-clique cycles:"
      elem = Section title $ (Paragraph [text]) : cycs'
      title = Text "Overall cycle analysis"

chainAnal :: CodeData -> Maybe DocElement
chainAnal cd
    | null chns = Nothing
    | otherwise = Just elem
    where
      chns = applyAlg chainsIn cd
      chns' = map (Paragraph .return . Text . showPath) chns
      text = Text "The functions have the following chains:"
      textAfter = Text "These chains can all be compressed down to \
                       \a single function."
      elem = Section title $
             [Paragraph [text]] ++ chns' ++ [Paragraph [textAfter]]
      title = Text "Overall chain analysis"

rootAnal :: CodeData -> Maybe DocElement
rootAnal cd
    | asExpected = Nothing
    | otherwise  = Just elem
    where
      (wntd, ntRs, ntWd) = classifyRoots cd
      asExpected = (null ntRs) && (null ntWd)
      rpt (s,ns) = if (null ns)
                   then Nothing
                   else Just [ Paragraph
                               [Text
                                $ concat ["These functions are those that are "
                                         , s, ":"]]
                             , Paragraph [Text $ showNodes ns]]
      ps = concat . catMaybes
           $ map rpt [ ("available for use and roots",wntd)
                     , ("available for use but not roots",ntWd)
                     , ("not available for use but roots",ntRs)]
      elem = Section title ps
      title = Text "Import root analysis"


cycleCompAnal    :: CodeData -> Maybe DocElement
cycleCompAnal cd = Just $ Section title [par]
    where
      cc = cyclomaticComplexity cd
      title = Text "Overall Cyclomatic Complexity"
      par = Paragraph [text, textAfter, link]
      text = Text
             $ printf "The overall cyclomatic complexity is: %d" cc
      textAfter = Text "For more information on cyclomatic complexity, \
                       \please see:"
      link = DocLink (Text "Wikipedia: Cyclomatic Complexity")
                     (URL "http://en.wikipedia.org/wiki/Cyclomatic_complexity")


coreAnal    :: CodeData -> Maybe DocElement
coreAnal cd = Just elem
    where
      core = applyAlg coreOf cd
      p = "codeCore"
      label = "Overall core"
      hdr = Paragraph [Text "The core of software can be thought of as \
                             \the part where all the work is actually done."]
      empMsg = Paragraph [Text "The code is a tree."]
      anal = if (isEmpty core)
             then empMsg
             else GraphImage (toGraph p label core)
      elem = Section title [hdr, anal]
      title = Text "Overall Core analysis"


collapseAnal    :: CodeData -> Maybe DocElement
collapseAnal cd = Just elem
    where
      gc = applyAlg collapseGraph cd
      p = "codeCollapsed"
      label = "Collapsed view of the entire codebase"
      hdr = Paragraph [Text "The collapsed view of code collapses \
                            \down all cliques, cycles, chains, etc. to \
                            \make the graph tree-like." ]
      gr = GraphImage (toGraph p label gc)
      elem = Section title [hdr, gr]
      title = Text "Collapsed view of the entire codebase"