/src/FindSymbol.hs

https://github.com/hdevtools/hdevtools · Haskell · 96 lines · 79 code · 16 blank · 1 comment · 3 complexity · 9b0c69640efedb3f7178dd5ea6655fec MD5 · raw file

  1. {-# Language ScopedTypeVariables, CPP #-}
  2. module FindSymbol
  3. ( findSymbol
  4. ) where
  5. #if __GLASGOW_HASKELL__ >= 802
  6. import GhcMonad (liftIO)
  7. #elif __GLASGOW_HASKELL__ >= 710
  8. import GHC.PackageDb (exposedName)
  9. import GhcMonad (liftIO)
  10. #else
  11. import Control.Applicative ((<$>))
  12. import qualified UniqFM
  13. #endif
  14. import Control.Exception
  15. import Control.Monad (filterM)
  16. import Data.List (find, nub)
  17. import Data.Maybe (catMaybes, isJust)
  18. import Exception (ghandle)
  19. import qualified GHC
  20. import qualified Packages as PKG
  21. import qualified Name
  22. import GhcTypes (getModSummaries)
  23. type SymbolName = String
  24. type ModuleName = String
  25. findSymbol :: SymbolName -> GHC.Ghc [ModuleName]
  26. findSymbol symbol = do
  27. fileMods <- findSymbolInFile symbol
  28. pkgsMods <- findSymbolInPackages symbol
  29. return . nub . map (GHC.moduleNameString . GHC.moduleName) $ fileMods ++ pkgsMods
  30. findSymbolInFile :: SymbolName -> GHC.Ghc [GHC.Module]
  31. findSymbolInFile symbol =
  32. filterM (containsSymbol symbol) =<< map GHC.ms_mod <$> getModSummaries
  33. findSymbolInPackages :: SymbolName -> GHC.Ghc [GHC.Module]
  34. findSymbolInPackages symbol =
  35. filterM (containsSymbol symbol) =<< allExposedModules
  36. where
  37. allExposedModules :: GHC.Ghc [GHC.Module]
  38. allExposedModules = do
  39. modNames <- exposedModuleNames
  40. catMaybes <$> mapM findModule modNames
  41. where
  42. exposedModuleNames :: GHC.Ghc [GHC.ModuleName]
  43. #if __GLASGOW_HASKELL__ >= 802
  44. exposedModuleNames = do
  45. dynFlags <- GHC.getSessionDynFlags
  46. pkgConfigs <- liftIO $ fmap concat
  47. . (fmap . fmap) snd . PKG.readPackageConfigs $ dynFlags
  48. return $ map fst (concatMap exposedModules pkgConfigs)
  49. #elif __GLASGOW_HASKELL__ >= 800
  50. exposedModuleNames = do
  51. dynFlags <- GHC.getSessionDynFlags
  52. pkgConfigs <- liftIO $ fmap concat
  53. . (fmap . fmap) snd . PKG.readPackageConfigs $ dynFlags
  54. return $ map exposedName (concatMap exposedModules pkgConfigs)
  55. #elif __GLASGOW_HASKELL__ >= 710
  56. exposedModuleNames = do
  57. dynFlags <- GHC.getSessionDynFlags
  58. pkgConfigs <- liftIO $ PKG.readPackageConfigs dynFlags
  59. return $ map exposedName (concatMap exposedModules pkgConfigs)
  60. #else
  61. exposedModuleNames =
  62. concatMap exposedModules
  63. . UniqFM.eltsUFM
  64. . PKG.pkgIdMap
  65. . GHC.pkgState
  66. <$> GHC.getSessionDynFlags
  67. #endif
  68. exposedModules pkg = if PKG.exposed pkg then PKG.exposedModules pkg else []
  69. findModule :: GHC.ModuleName -> GHC.Ghc (Maybe GHC.Module)
  70. findModule moduleName =
  71. ghandle (\(_ :: SomeException) -> return Nothing)
  72. (Just <$> GHC.findModule moduleName Nothing)
  73. containsSymbol :: SymbolName -> GHC.Module -> GHC.Ghc Bool
  74. containsSymbol symbol module_ =
  75. isJust . find (== symbol) <$> allExportedSymbols
  76. where
  77. allExportedSymbols =
  78. ghandle (\(_ :: SomeException) -> return [])
  79. (do info <- GHC.getModuleInfo module_
  80. return $ maybe [] (map Name.getOccString . GHC.modInfoExports) info)