@@ -14,27 +14,39 @@ import Development.IDE.Functions.GHCError
14import Development.IDE.Orphans()
14import Development.IDE.Orphans()
16-- DAML compiler and infrastructure
16-- 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
17import Development.IDE.Types.Diagnostics
21import Development.IDE.Types.Diagnostics
18import Development.IDE.Types.LSP
22import Development.IDE.Types.LSP
23+import Development.IDE.Types.Options
19import Development.IDE.Types.SpanInfo as SpanInfo
24import Development.IDE.Types.SpanInfo as SpanInfo
21-- GHC API imports
26-- GHC API imports
23import DynFlags
29import DynFlags
24−import Outputable hiding ((<>))
30+import HieTypes
25import Name
32import Name
33+import Outputable hiding ((<>))
35+import Control.Monad.Extra
36+import Control.Monad.Trans.Maybe
27import Data.Maybe
37import Data.Maybe
28import Data.List
38import Data.List
29import qualified Data.Text as T
39import qualified Data.Text as T
31-- | Locate the definition of the name at a given position.
41-- | Locate the definition of the name at a given position.
32gotoDefinition
42gotoDefinition
33− :: [SpanInfo]
45+ -> [SpanInfo]
34 -> Position
46 -> Position
35− -> Maybe Location
47+ -> Action (Maybe Location)
36−gotoDefinition srcSpans pos =
48+gotoDefinition ideOpts pkgState srcSpans pos =
37− listToMaybe $ locationsAtPoint pos srcSpans
49+ listToMaybe <$> locationsAtPoint ideOpts pkgState pos srcSpans
39-- | Synopsis for the name at a given position.
51-- | Synopsis for the name at a given position.
@@ -74,10 +86,37 @@ atPoint tcs srcSpans pos = do
74 Just name -> any (`isInfixOf` show name) ["==", "showsPrec"]
86 Just name -> any (`isInfixOf` show name) ["==", "showsPrec"]
75 Nothing -> False
87 Nothing -> False
77−locationsAtPoint :: Position -> [SpanInfo] -> [Location]
89+locationsAtPoint :: IdeOptions -> PackageDynFlags -> Position -> [SpanInfo] -> Action [Location]
90+locationsAtPoint IdeOptions{..} pkgState pos =
78−locationsAtPoint pos = map srcSpanToLocation
91+ fmap (map srcSpanToLocation) .
79− . mapMaybe (SpanInfo.getSrcSpan . spaninfoSource)
92+ mapMaybeM (getSpan . spaninfoSource) .
80− . spansAtPoint pos
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
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
82spansAtPoint :: Position -> [SpanInfo] -> [SpanInfo]
121spansAtPoint :: Position -> [SpanInfo] -> [SpanInfo]
83spansAtPoint pos = filter atp where
122spansAtPoint pos = filter atp where