Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit bafdc10

Browse files
committed
Implement TypeDefinitionRequest
Works for variables, not for explicit constructors. However, for explicit constructors, findDef works. Implement tests for `data`, `newtype` and `type`. For type defs, the original type definition will be found. May be improved. If the data type definition is not in scope, empty result will be sent. Also add new dependency, hopefully this can be removed again
1 parent 2403f70 commit bafdc10

File tree

6 files changed

+201
-7
lines changed

6 files changed

+201
-7
lines changed

haskell-ide-engine.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ library
8787
, safe
8888
, sorted-list >= 0.2.1.0
8989
, stm
90+
, syb
9091
, tagsoup
9192
, text
9293
, transformers

src/Haskell/Ide/Engine/Plugin/HieExtras.hs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Haskell.Ide.Engine.Plugin.HieExtras
1212
, getReferencesInDoc
1313
, getModule
1414
, findDef
15+
, findTypeDef
1516
, showName
1617
, safeTyThingId
1718
, PosPrefixInfo(..)
@@ -31,6 +32,7 @@ import Control.Monad.Reader
3132
import Data.Aeson
3233
import qualified Data.Aeson.Types as J
3334
import Data.Char
35+
import qualified Data.Generics as SYB
3436
import Data.IORef
3537
import qualified Data.List as List
3638
import qualified Data.Map as Map
@@ -537,6 +539,101 @@ getModule df n = do
537539
return (pkg, T.pack $ moduleNameString $ moduleName m)
538540

539541
-- ---------------------------------------------------------------------
542+
-- TODO: there has to be a simpler way, using the appropriate GHC internals
543+
findIdForName :: GHC.TypecheckedModule -> GHC.Name -> IdeM (Maybe GHC.Id)
544+
findIdForName tm n = do
545+
let t = GHC.tm_typechecked_source tm
546+
let r = SYB.something (SYB.mkQ Nothing worker) t
547+
worker (i :: GHC.Id) | nameUnique n == varUnique i = Just i
548+
worker _ = Nothing
549+
return r
550+
551+
-- ---------------------------------------------------------------------
552+
553+
getTypeForName' :: GHC.TypecheckedModule -> GHC.Name -> IdeM (Maybe GHC.Type)
554+
getTypeForName' tm n = do
555+
mId <- findIdForName tm n
556+
case mId of
557+
Nothing -> return Nothing
558+
Just i -> return $ Just (varType i)
559+
560+
-- | Return the type definition
561+
findTypeDef :: Uri -> Position -> IdeDeferM (IdeResult [Location])
562+
findTypeDef uri pos = pluginGetFile "findTypeDef: " uri $ \file -> do
563+
liftIO $ putStrLn "pluginGetFile"
564+
ifCachedModuleAndData
565+
file
566+
(IdeResultOk [])
567+
(\tm info NMD{} -> do
568+
let rfm = revMap info
569+
lm = locMap info
570+
mm = moduleMap info
571+
oldPos = newPosToOld info pos
572+
liftIO $ putStrLn "withCachedModuleAndData"
573+
case (\x -> Just $ getArtifactsAtPos x mm) =<< oldPos of
574+
Just ((_, mn) : _) -> gotoModule rfm mn
575+
_ -> case symbolFromTypecheckedModule lm =<< oldPos of
576+
Nothing -> return $ IdeResultOk []
577+
Just (_, n) -> do
578+
mayType <- lift $ getTypeForName' tm n
579+
case mayType of
580+
Nothing -> do
581+
liftIO $ putStrLn "No Type found :/"
582+
return $ IdeResultOk []
583+
Just t -> case tyConAppTyCon_maybe t of
584+
Nothing -> do
585+
liftIO $ putStrLn "Not a typeCon :("
586+
return $ IdeResultOk []
587+
Just tyCon ->
588+
case nameSrcSpan (getName tyCon) of
589+
UnhelpfulSpan _ -> return $ IdeResultOk []
590+
realSpan -> do
591+
liftIO $ putStrLn "Found real span"
592+
res <- srcSpan2Loc rfm realSpan
593+
case res of
594+
Right l@(J.Location luri range) -> case uriToFilePath luri of
595+
Nothing -> return $ IdeResultOk [l]
596+
Just fp ->
597+
ifCachedModule fp (IdeResultOk [l])
598+
$ \(_ :: ParsedModule) info' ->
599+
case oldRangeToNew info' range of
600+
Just r ->
601+
return $ IdeResultOk [J.Location luri r]
602+
Nothing -> return $ IdeResultOk [l]
603+
Left x -> do
604+
debugm "findTypeDef: name srcspan not found/valid"
605+
pure
606+
(IdeResultFail
607+
(IdeError PluginError
608+
("hare:findTypeDef" <> ": \"" <> x <> "\"")
609+
Null
610+
)
611+
)
612+
)
613+
where
614+
gotoModule
615+
:: (FilePath -> FilePath) -> ModuleName -> IdeDeferM (IdeResult [Location])
616+
gotoModule rfm mn = do
617+
618+
hscEnvRef <- ghcSession <$> readMTS
619+
mHscEnv <- liftIO $ traverse readIORef hscEnvRef
620+
621+
case mHscEnv of
622+
Just env -> do
623+
fr <- liftIO $ do
624+
-- Flush cache or else we get temporary files
625+
flushFinderCaches env
626+
findImportedModule env mn Nothing
627+
case fr of
628+
Found (ModLocation (Just src) _ _) _ -> do
629+
fp <- reverseMapFile rfm src
630+
631+
let r = Range (Position 0 0) (Position 0 0)
632+
loc = Location (filePathToUri fp) r
633+
return (IdeResultOk [loc])
634+
_ -> return (IdeResultOk [])
635+
Nothing -> return $ IdeResultFail
636+
(IdeError PluginError "Couldn't get hscEnv when finding import" Null)
540637

541638
-- | Return the definition
542639
findDef :: Uri -> Position -> IdeDeferM (IdeResult [Location])

src/Haskell/Ide/Engine/Transport/LspStdio.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ reactor inp diagIn = do
713713
pos = params ^. J.position
714714
callback = reactorSend . RspTypeDefinition . Core.makeResponseMessage req
715715
let hreq = IReq tn (req ^. J.id) callback
716-
$ fmap J.MultiLoc <$> Hie.findDef doc pos
716+
$ fmap J.MultiLoc <$> Hie.findTypeDef doc pos
717717
makeRequest hreq
718718

719719
ReqFindReferences req -> do

test/testdata/gototest/src/Lib.hs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
module Lib
2-
( someFunc
3-
) where
2+
3+
where
44

55
someFunc :: IO ()
66
someFunc = putStrLn "someFunc"
7+
8+
data DataType = DataType Int
9+
10+
dataTypeId :: DataType -> DataType
11+
dataTypeId dataType = dataType
12+
13+
newtype NewType = NewType Int
14+
15+
newTypeId :: NewType -> NewType
16+
newTypeId newType = newType
17+
18+
data Enu = First | Second
19+
20+
enuId :: Enu -> Enu
21+
enuId enu = enu
22+
23+
toNum :: Enu -> Int
24+
toNum First = 1
25+
toNum Second = 2
26+
27+
type MyInt = Int
28+
29+
myIntId :: MyInt -> MyInt
30+
myIntId myInt = myInt
31+
32+
type TypEnu = Enu
33+
34+
typEnuId :: TypEnu -> TypEnu
35+
typEnuId enu = enu

test/testdata/gototest/src/Lib2.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ g = do
88
where z = 1+2
99
y = z+z
1010
x = y*z
11+
12+
otherId :: DataType -> DataType
13+
otherId dataType = dataType

test/unit/HaRePluginSpec.hs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@ import Language.Haskell.LSP.Types ( Location(..)
2121
import System.Directory
2222
import System.FilePath
2323
import TestUtils
24-
2524
import Test.Hspec
25+
import Test.Hspec.Runner
2626

2727
-- ---------------------------------------------------------------------
2828
{-# ANN module ("hlint: ignore Eta reduce" :: String) #-}
2929
{-# ANN module ("hlint: ignore Redundant do" :: String) #-}
3030
-- ---------------------------------------------------------------------
3131

3232
main :: IO ()
33-
main = hspec spec
33+
main = do
34+
setupStackFiles
35+
config <- getHspecFormattedConfig "unit"
36+
hspecWith config spec
3437

3538
spec :: Spec
3639
spec = do
@@ -199,12 +202,73 @@ hareSpec = do
199202
req = liftToGhc $ TestDeferM $ findDef u (toPos (7,11))
200203
r <- dispatchRequestPGoto $ lreq >> req
201204
r `shouldBe` IdeResultOk [Location (filePathToUri $ cwd </> "test/testdata/gototest/src/Lib2.hs")
202-
(Range (toPos (10,9)) (toPos (10,10)))]
205+
(Range (toPos (10,9)) (toPos (10,10)))]
203206
let req2 = liftToGhc $ TestDeferM $ findDef u (toPos (10,13))
204207
r2 <- dispatchRequestPGoto $ lreq >> req2
205208
r2 `shouldBe` IdeResultOk [Location (filePathToUri $ cwd </> "test/testdata/gototest/src/Lib2.hs")
206209
(Range (toPos (9,9)) (toPos (9,10)))]
207-
210+
it "finds local definition of record variable" $ do
211+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs"
212+
lreq = setTypecheckedModule u
213+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (11, 23))
214+
r <- dispatchRequestPGoto $ lreq >> req
215+
r `shouldBe` IdeResultOk
216+
[ Location
217+
(filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs")
218+
(Range (toPos (8, 1)) (toPos (8, 29)))
219+
]
220+
it "finds local definition of newtype variable" $ do
221+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs"
222+
lreq = setTypecheckedModule u
223+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (16, 21))
224+
r <- dispatchRequestPGoto $ lreq >> req
225+
r `shouldBe` IdeResultOk
226+
[ Location
227+
(filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs")
228+
(Range (toPos (13, 1)) (toPos (13, 30)))
229+
]
230+
it "finds local definition of sum type variable" $ do
231+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs"
232+
lreq = setTypecheckedModule u
233+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (21, 13))
234+
r <- dispatchRequestPGoto $ lreq >> req
235+
r `shouldBe` IdeResultOk
236+
[ Location
237+
(filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs")
238+
(Range (toPos (18, 1)) (toPos (18, 26)))
239+
]
240+
it "finds local definition of sum type contructor" $ do
241+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs"
242+
lreq = setTypecheckedModule u
243+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (24, 7))
244+
r <- dispatchRequestPGoto $ lreq >> req
245+
r `shouldBe` IdeResultOk []
246+
it "can not find non-local definition of type def" $ do
247+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs"
248+
lreq = setTypecheckedModule u
249+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (30, 17))
250+
r <- dispatchRequestPGoto $ lreq >> req
251+
r `shouldBe` IdeResultOk []
252+
it "find local definition of type def" $ do
253+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs"
254+
lreq = setTypecheckedModule u
255+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (35, 16))
256+
r <- dispatchRequestPGoto $ lreq >> req
257+
r `shouldBe` IdeResultOk
258+
[ Location
259+
(filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs")
260+
(Range (toPos (18, 1)) (toPos (18, 26)))
261+
]
262+
it "find type-definition of type def in component" $ do
263+
let u = filePathToUri $ cwd </> "test/testdata/gototest/src/Lib2.hs"
264+
lreq = setTypecheckedModule u
265+
req = liftToGhc $ TestDeferM $ findTypeDef u (toPos (13, 20))
266+
r <- dispatchRequestPGoto $ lreq >> req
267+
r `shouldBe` IdeResultOk
268+
[ Location
269+
(filePathToUri $ cwd </> "test/testdata/gototest/src/Lib.hs")
270+
(Range (toPos (8, 1)) (toPos (8, 29)))
271+
]
208272

209273
-- ---------------------------------
210274

0 commit comments

Comments
 (0)