5
5
{-# LANGUAGE RecordWildCards #-}
6
6
{-# LANGUAGE ScopedTypeVariables #-}
7
7
{-# LANGUAGE StandaloneDeriving #-}
8
+
8
9
module Ide.Plugin.CallHierarchy.Internal (
9
10
prepareCallHierarchy
10
11
, incomingCalls
11
12
, outgoingCalls
12
13
) where
13
14
15
+ import Control.Concurrent
14
16
import Control.Lens ((^.) )
15
17
import Control.Monad.Extra
16
18
import Control.Monad.IO.Class
17
19
import Data.Aeson as A
20
+ import qualified Data.ByteString as BS
18
21
import qualified Data.HashMap.Strict as HM
19
22
import Data.List (groupBy , sortBy )
20
23
import qualified Data.Map as M
21
24
import Data.Maybe
22
25
import qualified Data.Set as S
23
26
import qualified Data.Text as T
27
+ import qualified Data.Text.Encoding as T
24
28
import Data.Tuple.Extra
25
29
import Development.IDE
30
+ import Development.IDE.Core.Compile
26
31
import Development.IDE.Core.Shake
27
32
import Development.IDE.GHC.Compat
28
33
import Development.IDE.Spans.AtPoint
29
- import Development.IDE.Spans.Common
30
34
import HieDb (Symbol (Symbol ))
31
35
import qualified Ide.Plugin.CallHierarchy.Query as Q
32
36
import Ide.Plugin.CallHierarchy.Types
33
37
import Ide.Types
34
38
import Language.LSP.Types
35
39
import qualified Language.LSP.Types.Lens as L
36
- import Maybes
37
40
import Name
38
- import SrcLoc
39
41
import Text.Read (readMaybe )
40
42
43
+ -- | Render prepare call hierarchy request.
41
44
prepareCallHierarchy :: PluginMethodHandler IdeState TextDocumentPrepareCallHierarchy
42
45
prepareCallHierarchy state pluginId param
43
46
| Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri =
@@ -92,11 +95,11 @@ construct nfp (ident, contexts, ssp)
92
95
93
96
| Just ctx <- declInfo contexts
94
97
= 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
100
103
Decl SynDec span -> mkCallHierarchyItem' ident SkTypeParameter (renderSpan span ) ssp
101
104
_ -> mkCallHierarchyItem' ident skUnknown ssp ssp
102
105
@@ -125,7 +128,7 @@ construct nfp (ident, contexts, ssp)
125
128
mkCallHierarchyItem :: NormalizedFilePath -> Identifier -> SymbolKind -> Span -> Span -> CallHierarchyItem
126
129
mkCallHierarchyItem nfp ident kind span selSpan =
127
130
CallHierarchyItem
128
- (T. pack $ identifierName ident)
131
+ (T. pack $ optimize $ identifierName ident)
129
132
kind
130
133
Nothing
131
134
(Just $ T. pack $ identifierToDetail ident)
@@ -144,12 +147,16 @@ mkCallHierarchyItem nfp ident kind span selSpan =
144
147
Left modName -> moduleNameString modName
145
148
Right name -> occNameString $ nameOccName name
146
149
150
+ optimize :: String -> String
151
+ optimize name -- optimize display for DuplicateRecordFields
152
+ | " $sel:" == take 5 name = drop 5 name
153
+ | otherwise = name
154
+
147
155
mkSymbol :: Identifier -> Maybe Symbol
148
156
mkSymbol = \ case
149
157
Left _ -> Nothing
150
158
Right name -> Just $ Symbol (occName name) (nameModule name)
151
159
152
-
153
160
----------------------------------------------------------------------
154
161
-------------- Incoming calls and outgoing calls ---------------------
155
162
----------------------------------------------------------------------
@@ -158,11 +165,12 @@ deriving instance Ord SymbolKind
158
165
deriving instance Ord SymbolTag
159
166
deriving instance Ord CallHierarchyItem
160
167
168
+ -- | Render incoming calls request.
161
169
incomingCalls :: PluginMethodHandler IdeState CallHierarchyIncomingCalls
162
170
incomingCalls state pluginId param = do
163
171
liftIO $ runAction " CallHierarchy.incomingCalls" state $
164
172
queryCalls (param ^. L. item) Q. incomingCalls mkCallHierarchyIncomingCall
165
- foiIncomingCalls mergeIncomingCalls >>=
173
+ mergeIncomingCalls >>=
166
174
\ case
167
175
Just x -> pure $ Right $ Just $ List x
168
176
Nothing -> pure $ Left $ responseError " CallHierarchy: IncomingCalls internal error"
@@ -178,11 +186,12 @@ incomingCalls state pluginId param = do
178
186
merge calls = let ranges = concatMap ((\ (List x) -> x) . (^. L. fromRanges)) calls
179
187
in CallHierarchyIncomingCall (head calls ^. L. from) (List ranges)
180
188
189
+ -- Render outgoing calls request.
181
190
outgoingCalls :: PluginMethodHandler IdeState CallHierarchyOutgoingCalls
182
191
outgoingCalls state pluginId param = do
183
192
liftIO $ runAction " CallHierarchy.outgoingCalls" state $
184
193
queryCalls (param ^. L. item) Q. outgoingCalls mkCallHierarchyOutgoingCall
185
- foiOutgoingCalls mergeOutgoingCalls >>=
194
+ mergeOutgoingCalls >>=
186
195
\ case
187
196
Just x -> pure $ Right $ Just $ List x
188
197
Nothing -> pure $ Left $ responseError " CallHierarchy: OutgoingCalls internal error"
@@ -223,21 +232,20 @@ queryCalls :: (Show a)
223
232
=> CallHierarchyItem
224
233
-> (HieDb -> Symbol -> IO [Vertex ])
225
234
-> (Vertex -> Action (Maybe a ))
226
- -> (NormalizedFilePath -> Position -> Action (Maybe [a ]))
227
235
-> ([a ] -> [a ])
228
236
-> Action (Maybe [a ])
229
- queryCalls item queryFunc makeFunc foiCalls merge
237
+ queryCalls item queryFunc makeFunc merge
230
238
| Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri = do
239
+ refreshHieDb
240
+
231
241
ShakeExtras {hiedb} <- getShakeExtras
232
242
maySymbol <- getSymbol nfp
233
243
case maySymbol of
234
244
Nothing -> error " CallHierarchy.Impossible"
235
245
Just symbol -> do
236
246
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
241
249
| otherwise = pure Nothing
242
250
where
243
251
uri = item ^. L. uri
@@ -266,43 +274,30 @@ queryCalls item queryFunc makeFunc foiCalls merge
266
274
Just res -> pure res
267
275
Nothing -> pure Nothing
268
276
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