55{-# LANGUAGE RecordWildCards #-}
66{-# LANGUAGE ScopedTypeVariables #-}
77{-# LANGUAGE StandaloneDeriving #-}
8+
89module Ide.Plugin.CallHierarchy.Internal (
910 prepareCallHierarchy
1011, incomingCalls
1112, outgoingCalls
1213) where
1314
15+ import Control.Concurrent
1416import Control.Lens ((^.) )
1517import Control.Monad.Extra
1618import Control.Monad.IO.Class
1719import Data.Aeson as A
20+ import qualified Data.ByteString as BS
1821import qualified Data.HashMap.Strict as HM
1922import Data.List (groupBy , sortBy )
2023import qualified Data.Map as M
2124import Data.Maybe
2225import qualified Data.Set as S
2326import qualified Data.Text as T
27+ import qualified Data.Text.Encoding as T
2428import Data.Tuple.Extra
2529import Development.IDE
30+ import Development.IDE.Core.Compile
2631import Development.IDE.Core.Shake
2732import Development.IDE.GHC.Compat
2833import Development.IDE.Spans.AtPoint
29- import Development.IDE.Spans.Common
3034import HieDb (Symbol (Symbol ))
3135import qualified Ide.Plugin.CallHierarchy.Query as Q
3236import Ide.Plugin.CallHierarchy.Types
3337import Ide.Types
3438import Language.LSP.Types
3539import qualified Language.LSP.Types.Lens as L
36- import Maybes
3740import Name
38- import SrcLoc
3941import Text.Read (readMaybe )
4042
43+ -- | Render prepare call hierarchy request.
4144prepareCallHierarchy :: PluginMethodHandler IdeState TextDocumentPrepareCallHierarchy
4245prepareCallHierarchy state pluginId param
4346 | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri =
@@ -92,11 +95,11 @@ construct nfp (ident, contexts, ssp)
9295
9396 | Just ctx <- declInfo contexts
9497 = Just $ case ctx of
95- Decl ClassDec span -> mkCallHierarchyItem' ident SkInterface (renderSpan span ) ssp
96- Decl ConDec span -> mkCallHierarchyItem' ident SkConstructor (renderSpan span ) ssp
97- Decl DataDec span -> mkCallHierarchyItem' ident SkStruct (renderSpan span ) ssp
98- Decl FamDec span -> mkCallHierarchyItem' ident SkFunction (renderSpan span ) ssp
99- Decl InstDec span -> mkCallHierarchyItem' ident SkInterface (renderSpan span ) ssp
98+ Decl ClassDec span -> mkCallHierarchyItem' ident SkInterface (renderSpan span ) ssp
99+ Decl ConDec span -> mkCallHierarchyItem' ident SkConstructor (renderSpan span ) ssp
100+ Decl DataDec span -> mkCallHierarchyItem' ident SkStruct (renderSpan span ) ssp
101+ Decl FamDec span -> mkCallHierarchyItem' ident SkFunction (renderSpan span ) ssp
102+ Decl InstDec span -> mkCallHierarchyItem' ident SkInterface (renderSpan span ) ssp
100103 Decl SynDec span -> mkCallHierarchyItem' ident SkTypeParameter (renderSpan span ) ssp
101104 _ -> mkCallHierarchyItem' ident skUnknown ssp ssp
102105
@@ -125,7 +128,7 @@ construct nfp (ident, contexts, ssp)
125128mkCallHierarchyItem :: NormalizedFilePath -> Identifier -> SymbolKind -> Span -> Span -> CallHierarchyItem
126129mkCallHierarchyItem nfp ident kind span selSpan =
127130 CallHierarchyItem
128- (T. pack $ identifierName ident)
131+ (T. pack $ optimize $ identifierName ident)
129132 kind
130133 Nothing
131134 (Just $ T. pack $ identifierToDetail ident)
@@ -144,12 +147,16 @@ mkCallHierarchyItem nfp ident kind span selSpan =
144147 Left modName -> moduleNameString modName
145148 Right name -> occNameString $ nameOccName name
146149
150+ optimize :: String -> String
151+ optimize name -- optimize display for DuplicateRecordFields
152+ | " $sel:" == take 5 name = drop 5 name
153+ | otherwise = name
154+
147155mkSymbol :: Identifier -> Maybe Symbol
148156mkSymbol = \ case
149157 Left _ -> Nothing
150158 Right name -> Just $ Symbol (occName name) (nameModule name)
151159
152-
153160----------------------------------------------------------------------
154161-------------- Incoming calls and outgoing calls ---------------------
155162----------------------------------------------------------------------
@@ -158,11 +165,12 @@ deriving instance Ord SymbolKind
158165deriving instance Ord SymbolTag
159166deriving instance Ord CallHierarchyItem
160167
168+ -- | Render incoming calls request.
161169incomingCalls :: PluginMethodHandler IdeState CallHierarchyIncomingCalls
162170incomingCalls state pluginId param = do
163171 liftIO $ runAction " CallHierarchy.incomingCalls" state $
164172 queryCalls (param ^. L. item) Q. incomingCalls mkCallHierarchyIncomingCall
165- foiIncomingCalls mergeIncomingCalls >>=
173+ mergeIncomingCalls >>=
166174 \ case
167175 Just x -> pure $ Right $ Just $ List x
168176 Nothing -> pure $ Left $ responseError " CallHierarchy: IncomingCalls internal error"
@@ -178,11 +186,12 @@ incomingCalls state pluginId param = do
178186 merge calls = let ranges = concatMap ((\ (List x) -> x) . (^. L. fromRanges)) calls
179187 in CallHierarchyIncomingCall (head calls ^. L. from) (List ranges)
180188
189+ -- Render outgoing calls request.
181190outgoingCalls :: PluginMethodHandler IdeState CallHierarchyOutgoingCalls
182191outgoingCalls state pluginId param = do
183192 liftIO $ runAction " CallHierarchy.outgoingCalls" state $
184193 queryCalls (param ^. L. item) Q. outgoingCalls mkCallHierarchyOutgoingCall
185- foiOutgoingCalls mergeOutgoingCalls >>=
194+ mergeOutgoingCalls >>=
186195 \ case
187196 Just x -> pure $ Right $ Just $ List x
188197 Nothing -> pure $ Left $ responseError " CallHierarchy: OutgoingCalls internal error"
@@ -223,21 +232,20 @@ queryCalls :: (Show a)
223232 => CallHierarchyItem
224233 -> (HieDb -> Symbol -> IO [Vertex ])
225234 -> (Vertex -> Action (Maybe a ))
226- -> (NormalizedFilePath -> Position -> Action (Maybe [a ]))
227235 -> ([a ] -> [a ])
228236 -> Action (Maybe [a ])
229- queryCalls item queryFunc makeFunc foiCalls merge
237+ queryCalls item queryFunc makeFunc merge
230238 | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri = do
239+ refreshHieDb
240+
231241 ShakeExtras {hiedb} <- getShakeExtras
232242 maySymbol <- getSymbol nfp
233243 case maySymbol of
234244 Nothing -> error " CallHierarchy.Impossible"
235245 Just symbol -> do
236246 vs <- liftIO $ queryFunc hiedb symbol
237- nonFOIItems <- mapM makeFunc vs
238- foiRes <- foiCalls nfp pos
239- let nonFOIRes = Just $ catMaybes nonFOIItems
240- pure $ merge <$> (nonFOIRes <> foiRes)
247+ items <- Just . catMaybes <$> mapM makeFunc vs
248+ pure $ merge <$> items
241249 | otherwise = pure Nothing
242250 where
243251 uri = item ^. L. uri
@@ -266,43 +274,30 @@ queryCalls item queryFunc makeFunc foiCalls merge
266274 Just res -> pure res
267275 Nothing -> pure Nothing
268276
269- foiIncomingCalls :: NormalizedFilePath -> Position -> Action (Maybe [CallHierarchyIncomingCall ])
270- foiIncomingCalls nfp pos =
271- use GetHieAst nfp >>=
272- \ case
273- Nothing -> pure Nothing
274- Just (HAR _ hf _ _ _) -> do
275- case listToMaybe $ pointCommand hf pos id of
276- Nothing -> pure Nothing
277- Just ast -> do
278- fs <- HM. keys <$> getFilesOfInterestUntracked
279- Just . concatMap (`callers` ast) <$> mapMaybeM (use GetHieAst ) fs
280- where
281- callers :: HieAstResult -> HieAST a -> [CallHierarchyIncomingCall ]
282- callers (HAR _ hf _ _ _) ast = mkIncomingCalls $ filter (sameAst ast) $ M. elems (getAsts hf)
283-
284- sameAst :: HieAST a -> HieAST b -> Bool
285- sameAst ast1 ast2 = (M. keys . nodeIdentifiers . nodeInfo) ast1
286- == (M. keys . nodeIdentifiers . nodeInfo) ast2
287-
288- mkIncomingCalls asts = let infos = concatMap extract asts
289- items = mapMaybe (construct nfp) infos
290- in map (\ item ->
291- CallHierarchyIncomingCall item
292- (List [item ^. L. selectionRange])) items
293-
294- foiOutgoingCalls :: NormalizedFilePath -> Position -> Action (Maybe [CallHierarchyOutgoingCall ])
295- foiOutgoingCalls nfp pos =
296- use GetHieAst nfp >>=
297- \ case
298- Nothing -> pure Nothing
299- Just (HAR _ hf _ _ _) -> do
300- case listToMaybe $ pointCommand hf pos nodeChildren of
301- Nothing -> pure Nothing
302- Just children -> pure $ Just $ mkOutgoingCalls children
303- where
304- mkOutgoingCalls asts = let infos = concatMap extract asts
305- items = mapMaybe (construct nfp) infos
306- in map (\ item ->
307- CallHierarchyOutgoingCall item
308- (List [item ^. L. selectionRange]) ) items
277+ -- Write modified foi files before queries.
278+ refreshHieDb :: Action ()
279+ refreshHieDb = do
280+ fs <- HM. keys . HM. filter (/= OnDisk ) <$> getFilesOfInterestUntracked
281+ forM_ fs (\ f -> do
282+ tmr <- use_ TypeCheck f
283+ hsc <- hscEnv <$> use_ GhcSession f
284+ (_, masts) <- liftIO $ generateHieAsts hsc tmr
285+ se <- getShakeExtras
286+ case masts of
287+ Nothing -> pure ()
288+ Just asts -> do
289+ source <- getSourceFileSource f
290+ let exports = tcg_exports $ tmrTypechecked tmr
291+ msum = tmrModSummary tmr
292+ liftIO $ writeAndIndexHieFile hsc se msum f exports asts source
293+ pure ()
294+ )
295+ liftIO $ threadDelay 100000 -- delay 0.1 sec to make more exact results.
296+
297+ -- Copy unexport function form `ghcide/src/Development/IDE/Core/Rules.hs`
298+ getSourceFileSource :: NormalizedFilePath -> Action BS. ByteString
299+ getSourceFileSource nfp = do
300+ (_, msource) <- getFileContents nfp
301+ case msource of
302+ Nothing -> liftIO $ BS. readFile (fromNormalizedFilePath nfp)
303+ Just source -> pure $ T. encodeUtf8 source
0 commit comments