/src/Haskell/Ide/Engine/Support/FromHaRe.hs

https://github.com/haskell/haskell-ide-engine · Haskell · 221 lines · 142 code · 43 blank · 36 comment · 6 complexity · 49041e5c436bef1be4b3bb2d22f22b8f MD5 · raw file

  1. {-# LANGUAGE ScopedTypeVariables #-}
  2. {-# LANGUAGE CPP #-}
  3. module Haskell.Ide.Engine.Support.FromHaRe
  4. (
  5. initRdrNameMap
  6. , NameMap
  7. , hsNamessRdr
  8. ) where
  9. -- Code migrated from HaRe, until HaRe comes back
  10. -- import Control.Monad.State
  11. import Data.List
  12. import Data.Maybe
  13. import qualified GHC as GHC
  14. -- import qualified GhcMonad as GHC
  15. -- import qualified Haskell.Ide.Engine.PluginApi as HIE (makeRevRedirMapFunc)
  16. import qualified Module as GHC
  17. import qualified Name as GHC
  18. import qualified Unique as GHC
  19. -- import qualified HscTypes as GHC (md_exports)
  20. -- import qualified TcRnTypes as GHC (tcg_rdr_env)
  21. #if __GLASGOW_HASKELL__ > 710
  22. import qualified Var
  23. #endif
  24. import qualified Data.Generics as SYB
  25. -- import Language.Haskell.GHC.ExactPrint
  26. -- import Language.Haskell.GHC.ExactPrint.Annotate
  27. -- import Language.Haskell.GHC.ExactPrint.Parsers
  28. import Language.Haskell.GHC.ExactPrint.Utils
  29. import Language.Haskell.GHC.ExactPrint.Types
  30. -- import Language.Haskell.Refact.Utils.Monad
  31. -- import Language.Haskell.Refact.Utils.TypeSyn
  32. -- import Language.Haskell.Refact.Utils.Types
  33. import qualified Data.Map as Map
  34. -- import Outputable
  35. -- ---------------------------------------------------------------------
  36. type NameMap = Map.Map GHC.SrcSpan GHC.Name
  37. -- ---------------------------------------------------------------------
  38. -- |We need the ParsedSource because it more closely reflects the actual source
  39. -- code, but must be able to work with the renamed representation of the names
  40. -- involved. This function constructs a map from every Located RdrName in the
  41. -- ParsedSource to its corresponding name in the RenamedSource. It also deals
  42. -- with the wrinkle that we need to Location of the RdrName to make sure we have
  43. -- the right Name, but not all RdrNames have a Location.
  44. -- This function is called before the RefactGhc monad is active.
  45. initRdrNameMap :: GHC.TypecheckedModule -> NameMap
  46. initRdrNameMap tm = r
  47. where
  48. parsed = GHC.pm_parsed_source $ GHC.tm_parsed_module tm
  49. renamed = GHC.tm_renamed_source tm
  50. #if __GLASGOW_HASKELL__ > 710
  51. typechecked = GHC.tm_typechecked_source tm
  52. #endif
  53. checkRdr :: GHC.Located GHC.RdrName -> Maybe [(GHC.SrcSpan,GHC.RdrName)]
  54. checkRdr (GHC.L l n@(GHC.Unqual _)) = Just [(l,n)]
  55. checkRdr (GHC.L l n@(GHC.Qual _ _)) = Just [(l,n)]
  56. checkRdr (GHC.L _ _)= Nothing
  57. checkName :: GHC.Located GHC.Name -> Maybe [GHC.Located GHC.Name]
  58. checkName ln = Just [ln]
  59. rdrNames = gfromJust "initRdrNameMap" $ SYB.everything mappend (nameSybQuery checkRdr ) parsed
  60. #if __GLASGOW_HASKELL__ >= 806
  61. names1 = gfromJust "initRdrNameMap" $ SYB.everything mappend (nameSybQuery checkName) renamed
  62. names2 = names1 ++ SYB.everything (++) ([] `SYB.mkQ` fieldOcc
  63. `SYB.extQ` hsRecFieldN) renamed
  64. names = names2 ++ SYB.everything (++) ([] `SYB.mkQ` hsRecFieldT) typechecked
  65. fieldOcc :: GHC.FieldOcc GhcRn -> [GHC.Located GHC.Name]
  66. fieldOcc (GHC.FieldOcc n (GHC.L l _)) = [(GHC.L l n)]
  67. fieldOcc (GHC.XFieldOcc _) = []
  68. hsRecFieldN :: GHC.LHsExpr GhcRn -> [GHC.Located GHC.Name]
  69. hsRecFieldN (GHC.L _ (GHC.HsRecFld _ (GHC.Unambiguous n (GHC.L l _) ) )) = [GHC.L l n]
  70. hsRecFieldN _ = []
  71. hsRecFieldT :: GHC.LHsExpr GhcTc -> [GHC.Located GHC.Name]
  72. hsRecFieldT (GHC.L _ (GHC.HsRecFld _ (GHC.Ambiguous n (GHC.L l _)) )) = [GHC.L l (Var.varName n)]
  73. hsRecFieldT _ = []
  74. #elif __GLASGOW_HASKELL__ > 710
  75. names1 = gfromJust "initRdrNameMap" $ SYB.everything mappend (nameSybQuery checkName) renamed
  76. names2 = names1 ++ SYB.everything (++) ([] `SYB.mkQ` fieldOcc
  77. `SYB.extQ` hsRecFieldN) renamed
  78. names = names2 ++ SYB.everything (++) ([] `SYB.mkQ` hsRecFieldT) typechecked
  79. fieldOcc :: GHC.FieldOcc GhcRn -> [GHC.Located GHC.Name]
  80. fieldOcc (GHC.FieldOcc (GHC.L l _) n) = [(GHC.L l n)]
  81. hsRecFieldN :: GHC.LHsExpr GhcRn -> [GHC.Located GHC.Name]
  82. hsRecFieldN (GHC.L _ (GHC.HsRecFld (GHC.Unambiguous (GHC.L l _) n) )) = [GHC.L l n]
  83. hsRecFieldN _ = []
  84. hsRecFieldT :: GHC.LHsExpr GhcTc -> [GHC.Located GHC.Name]
  85. hsRecFieldT (GHC.L _ (GHC.HsRecFld (GHC.Ambiguous (GHC.L l _) n) )) = [GHC.L l (Var.varName n)]
  86. hsRecFieldT _ = []
  87. #else
  88. names = gfromJust "initRdrNameMap" $ SYB.everything mappend (nameSybQuery checkName) renamed
  89. #endif
  90. #if __GLASGOW_HASKELL__ >= 806
  91. namesIe = names
  92. #elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(8,2,1,0)))
  93. -- This is a workaround for https://ghc.haskell.org/trac/ghc/ticket/14189
  94. -- namesIeParsedL = SYB.everything (++) ([] `SYB.mkQ` ieThingWith) (GHC.hsmodExports $ GHC.unLoc parsed)
  95. namesIeParsed = Map.fromList $ SYB.everything (++) ([] `SYB.mkQ` ieThingWith) (GHC.hsmodExports $ GHC.unLoc parsed)
  96. ieThingWith :: GHC.IE GhcPs -> [(GHC.SrcSpan, [GHC.SrcSpan])]
  97. ieThingWith (GHC.IEThingWith l _ sub_rdrs _) = [(GHC.getLoc l,map GHC.getLoc sub_rdrs)]
  98. ieThingWith _ = []
  99. renamedExports = case renamed of
  100. Nothing -> Nothing
  101. Just (_,_,es,_) -> es
  102. namesIeRenamed = SYB.everything (++) ([] `SYB.mkQ` ieThingWithNames) renamedExports
  103. ieThingWithNames :: GHC.IE GhcRn -> [GHC.Located GHC.Name]
  104. ieThingWithNames (GHC.IEThingWith l _ sub_rdrs _) = (GHC.ieLWrappedName l:nameSubs)
  105. where
  106. rdrSubLocs = gfromJust "ieThingWithNames" $ Map.lookup (GHC.getLoc l) namesIeParsed
  107. nameSubs = map (\(loc,GHC.L _ lwn) -> GHC.L loc (GHC.ieWrappedName lwn)) $ zip rdrSubLocs sub_rdrs
  108. ieThingWithNames _ = []
  109. namesIe = case SYB.everything mappend (nameSybQuery checkName) namesIeRenamed of
  110. Nothing -> names
  111. Just ns -> names ++ ns
  112. #else
  113. namesIe = names
  114. #endif
  115. nameMap = Map.fromList $ map (\(GHC.L l n) -> (l,n)) namesIe
  116. -- If the name does not exist (e.g. a TH Splice that has been expanded, make a new one)
  117. -- No attempt is made to make sure that equivalent ones have equivalent names.
  118. lookupName l n i = case Map.lookup l nameMap of
  119. Just v -> v
  120. Nothing -> case n of
  121. GHC.Unqual u -> mkNewGhcNamePure 'h' i Nothing (GHC.occNameString u)
  122. #if __GLASGOW_HASKELL__ <= 710
  123. GHC.Qual q u -> mkNewGhcNamePure 'h' i (Just (GHC.Module (GHC.stringToPackageKey "") q)) (GHC.occNameString u)
  124. #else
  125. GHC.Qual q u -> mkNewGhcNamePure 'h' i (Just (GHC.Module (GHC.stringToUnitId "") q)) (GHC.occNameString u)
  126. #endif
  127. _ -> error "initRdrNameMap:should not happen"
  128. r = Map.fromList $ map (\((l,n),i) -> (l,lookupName l n i)) $ zip rdrNames [1..]
  129. -- ---------------------------------------------------------------------
  130. nameSybQuery :: (SYB.Typeable a, SYB.Typeable t)
  131. => (GHC.Located a -> Maybe r) -> t -> Maybe r
  132. nameSybQuery checker = q
  133. where
  134. q = Nothing `SYB.mkQ` worker
  135. #if __GLASGOW_HASKELL__ <= 710
  136. `SYB.extQ` workerBind
  137. `SYB.extQ` workerExpr
  138. `SYB.extQ` workerHsTyVarBndr
  139. `SYB.extQ` workerLHsType
  140. #endif
  141. worker (pnt :: (GHC.Located a))
  142. = checker pnt
  143. #if __GLASGOW_HASKELL__ <= 710
  144. workerBind (GHC.L l (GHC.VarPat name))
  145. = checker (GHC.L l name)
  146. workerBind _ = Nothing
  147. workerExpr ((GHC.L l (GHC.HsVar name)))
  148. = checker (GHC.L l name)
  149. workerExpr _ = Nothing
  150. -- workerLIE ((GHC.L _l (GHC.IEVar (GHC.L ln name))) :: (GHC.LIE a))
  151. -- = checker (GHC.L ln name)
  152. -- workerLIE _ = Nothing
  153. workerHsTyVarBndr ((GHC.L l (GHC.UserTyVar name)))
  154. = checker (GHC.L l name)
  155. workerHsTyVarBndr _ = Nothing
  156. workerLHsType ((GHC.L l (GHC.HsTyVar name)))
  157. = checker (GHC.L l name)
  158. workerLHsType _ = Nothing
  159. #endif
  160. -- ---------------------------------------------------------------------
  161. mkNewGhcNamePure :: Char -> Int -> Maybe GHC.Module -> String -> GHC.Name
  162. mkNewGhcNamePure c i maybeMod name =
  163. let un = GHC.mkUnique c i -- H for HaRe :)
  164. n = case maybeMod of
  165. Nothing -> GHC.mkInternalName un (GHC.mkVarOcc name) GHC.noSrcSpan
  166. Just modu -> GHC.mkExternalName un modu (GHC.mkVarOcc name) GHC.noSrcSpan
  167. in n
  168. -- ---------------------------------------------------------------------
  169. -- |Get all the names in the given syntax element
  170. hsNamessRdr :: (SYB.Data t) => t -> [GHC.Located GHC.RdrName]
  171. hsNamessRdr t = nub $ fromMaybe [] r
  172. where
  173. r = (SYB.everything mappend (inName) t)
  174. checker :: GHC.Located GHC.RdrName -> Maybe [GHC.Located GHC.RdrName]
  175. checker x = Just [x]
  176. inName :: (SYB.Typeable a) => a -> Maybe [GHC.Located GHC.RdrName]
  177. inName = nameSybQuery checker
  178. -- ---------------------------------------------------------------------