@@ -14,27 +14,39 @@ import Development.IDE.Functions.GHCError
1414import Development.IDE.Orphans()
1515
1616-- DAML compiler and infrastructure
17+import Development.Shake
18+import Development.IDE.UtilGHC
19+import Development.IDE.State.Shake
20+import Development.IDE.State.RuleTypes
1721import Development.IDE.Types.Diagnostics
1822import Development.IDE.Types.LSP
23+import Development.IDE.Types.Options
1924import Development.IDE.Types.SpanInfo as SpanInfo
2025
2126-- GHC API imports
27+import Avail
2228import GHC
2329import DynFlags
24−import Outputable hiding ((<>))
30+import HieTypes
31+import FastString
2532import Name
33+import Outputable hiding ((<>))
2634
35+import Control.Monad.Extra
36+import Control.Monad.Trans.Maybe
2737import Data.Maybe
2838import Data.List
2939import qualified Data.Text as T
3040
3141-- | Locate the definition of the name at a given position.
3242gotoDefinition
33− :: [SpanInfo]
43+ :: IdeOptions
44+ -> PackageDynFlags
45+ -> [SpanInfo]
3446 -> Position
35− -> Maybe Location
36−gotoDefinition srcSpans pos =
37− listToMaybe $ locationsAtPoint pos srcSpans
47+ -> Action (Maybe Location)
48+gotoDefinition ideOpts pkgState srcSpans pos =
49+ listToMaybe <$> locationsAtPoint ideOpts pkgState pos srcSpans
3850
3951-- | Synopsis for the name at a given position.
4052atPoint
@@ -74,10 +86,37 @@ atPoint tcs srcSpans pos = do
7486 Just name -> any (`isInfixOf` show name) ["==", "showsPrec"]
7587 Nothing -> False
7688
77−locationsAtPoint :: Position -> [SpanInfo] -> [Location]
78−locationsAtPoint pos = map srcSpanToLocation
79− . mapMaybe (SpanInfo.getSrcSpan . spaninfoSource)
80− . spansAtPoint pos
89+locationsAtPoint :: IdeOptions -> PackageDynFlags -> Position -> [SpanInfo] -> Action [Location]
90+locationsAtPoint IdeOptions{..} pkgState pos =
91+ fmap (map srcSpanToLocation) .
92+ mapMaybeM (getSpan . spaninfoSource) .
93+ spansAtPoint pos
94+ where getSpan :: SpanSource -> Action (Maybe SrcSpan)
95+ getSpan NoSource = pure Nothing
96+ getSpan (Span sp) = pure $ Just sp
97+ getSpan (Named name) = case nameSrcSpan name of
98+ sp@(RealSrcSpan _) -> pure $ Just sp
99+ UnhelpfulSpan _ -> runMaybeT $ do
100+ -- This case usually arises when the definition is in an external package.
101+ -- In this case the interface files contain garbage source spans
102+ -- so we instead read the .hie files to get useful source spans.
103+ let mod = nameModule name
104+ let unitId = moduleUnitId mod
105+ pkgConfig <- MaybeT $ pure $ lookupPackageConfig unitId pkgState
106+ hiePath <- MaybeT $ liftIO $ optLocateHieFile optPkgLocationOpts pkgConfig mod
107+ hieFile <- MaybeT $ use (GetHieFile hiePath) ""
108+ avail <- MaybeT $ pure $ listToMaybe (filterAvails (eqName name) $ hie_exports hieFile)
109+ srcPath <- MaybeT $ liftIO $ optLocateSrcFile optPkgLocationOpts pkgConfig mod
110+ -- The location will point to the source file used during compilation.
111+ -- This file might no longer exists and even if it does the path will be relative
112+ -- to the compilation directory which we don’t know.
113+ let span = setFileName srcPath $ nameSrcSpan $ availName avail
114+ pure span
115+ -- We ignore uniques and source spans and only compare the name and the module.
116+ eqName :: Name -> Name -> Bool
117+ eqName n n' = nameOccName n == nameOccName n' && nameModule n == nameModule n'
118+ setFileName f (RealSrcSpan span) = RealSrcSpan (span { srcSpanFile = mkFastString f })
119+ setFileName _ span@(UnhelpfulSpan _) = span
81120
82121spansAtPoint :: Position -> [SpanInfo] -> [SpanInfo]
83122spansAtPoint pos = filter atp where