Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ghcide-test/data/hover/Constructors.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Constructors where

data A = A
data B = B Int Word Bool
data C = C ![Int] {-# UNPACK #-} !Bool
data D = D { da :: Int, db :: Bool }
data E = E { ea :: !Int, eb :: {-# UNPACK #-} ![Bool] }
newtype F = F Int
9 changes: 9 additions & 0 deletions ghcide-test/data/hover/ConstructorsLinear.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{-# LANGUAGE LinearTypes #-}
module ConstructorsLinear where

data A = A
data B = B Int Word Bool
data C = C ![Int] {-# UNPACK #-} !Bool
data D = D { da :: Int, db :: Bool }
data E = E { ea :: !Int, eb :: {-# UNPACK #-} ![Bool] }
newtype F = F Int
2 changes: 1 addition & 1 deletion ghcide-test/data/hover/hie.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cradle: {direct: {arguments: ["Foo", "Bar", "GotoHover", "RecordDotSyntax", "GotoImplementation"]}}
cradle: {direct: {arguments: ["Foo", "Bar", "GotoHover", "RecordDotSyntax", "GotoImplementation", "Constructors", "ConstructorsLinear"]}}
40 changes: 40 additions & 0 deletions ghcide-test/exe/ConstructorHoverTests.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{-# LANGUAGE OverloadedStrings #-}

module ConstructorHoverTests (tests) where

import Config
import Hover
import Test.Hls
import Test.Hls.FileSystem (copyDir)

tests :: TestTree
tests =
testGroup
"constructor hover (#2904)"
[ testGroup
"Constructors.hs"
[ test "A" "Constructors.hs" (Position 2 9) [ExpectHoverText ["A :: A"]]
, test "B" "Constructors.hs" (Position 3 9) [ExpectHoverText ["B :: Int -> Word -> Bool -> B"], ExpectHoverExcludeText ["%1 ->"]]
, test "C" "Constructors.hs" (Position 4 9) [ExpectHoverText ["C :: [Int] -> Bool -> C"], ExpectHoverExcludeText ["%1 ->"]]
, test "D" "Constructors.hs" (Position 5 9) [ExpectHoverText ["D :: Int -> Bool -> D"], ExpectHoverExcludeText ["%1 ->"]]
, test "E" "Constructors.hs" (Position 6 9) [ExpectHoverText ["E :: Int -> [Bool] -> E"], ExpectHoverExcludeText ["%1 ->"]]
, test "F" "Constructors.hs" (Position 7 12) [ExpectHoverText ["F :: Int -> F"], ExpectHoverExcludeText ["%1 ->"]]
]
, testGroup
"ConstructorsLinear.hs"
[ test "A" "ConstructorsLinear.hs" (Position 3 9) [ExpectHoverText ["A :: A"]]
, test "B" "ConstructorsLinear.hs" (Position 4 9) [ExpectHoverText ["B :: Int %1 -> Word %1 -> Bool %1 -> B"]]
, test "C" "ConstructorsLinear.hs" (Position 5 9) [ExpectHoverText ["C :: [Int] %1 -> Bool %1 -> C"]]
, test "D" "ConstructorsLinear.hs" (Position 6 9) [ExpectHoverText ["D :: Int %1 -> Bool %1 -> D"]]
, test "E" "ConstructorsLinear.hs" (Position 7 9) [ExpectHoverText ["E :: Int %1 -> [Bool] %1 -> E"]]
, test "F" "ConstructorsLinear.hs" (Position 8 12) [ExpectHoverText ["F :: Int %1 -> F"]]
]
]

test :: String -> FilePath -> Position -> [Expect] -> TestTree
test title fileName pos expectations =
testWithDummyPlugin title (mkIdeTestFs [copyDir "hover"]) $ do
doc <- openDoc fileName "haskell"
waitForProgressDone
hover <- getHover doc pos
checkHover hover expectations
11 changes: 1 addition & 10 deletions ghcide-test/exe/FindDefinitionAndHoverTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Control.Category ((>>>))
import Control.Lens ((^.))
import Development.IDE.Test (expectDiagnostics,
standardizeQuotes)
import Hover
import Test.Hls
import Test.Hls.FileSystem (copyDir)
import Text.Regex.TDFA ((=~))
Expand Down Expand Up @@ -91,16 +92,6 @@ tests = let
"expected: " <> show ("[...]" <> sourceFileName <> ":<LINE>:<COL>**[...]", Just expectedRange) <>
"\n but got: " <> show (msg, rangeInHover)

assertFoundIn :: T.Text -> T.Text -> Assertion
assertFoundIn part whole = assertBool
(T.unpack $ "failed to find: `" <> part <> "` in hover message:\n" <> whole)
(part `T.isInfixOf` whole)

assertNotFoundIn :: T.Text -> T.Text -> Assertion
assertNotFoundIn part whole = assertBool
(T.unpack $ "found unexpected: `" <> part <> "` in hover message:\n" <> whole)
(not . T.isInfixOf part $ whole)

sourceFilePath = T.unpack sourceFileName
sourceFileName = "GotoHover.hs"

Expand Down
11 changes: 1 addition & 10 deletions ghcide-test/exe/FindImplementationAndHoverTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Text.Regex.TDFA ((=~))

import Config
import Development.IDE.Test (standardizeQuotes)
import Hover
import Test.Hls
import Test.Hls.FileSystem (copyDir)

Expand Down Expand Up @@ -47,16 +48,6 @@ tests = let
_ -> pure () -- all other expectations not relevant to hover
_ -> liftIO $ assertFailure $ "test not expecting this kind of hover info" <> show hover

assertFoundIn :: T.Text -> T.Text -> Assertion
assertFoundIn part whole = assertBool
(T.unpack $ "failed to find: `" <> part <> "` in hover message:\n" <> whole)
(part `T.isInfixOf` whole)

assertNotFoundIn :: T.Text -> T.Text -> Assertion
assertNotFoundIn part whole = assertBool
(T.unpack $ "found unexpected: `" <> part <> "` in hover message:\n" <> whole)
(not . T.isInfixOf part $ whole)

sourceFilePath = T.unpack sourceFileName
sourceFileName = "GotoImplementation.hs"

Expand Down
40 changes: 40 additions & 0 deletions ghcide-test/exe/Hover.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Hover where

import Config
import Control.Monad
import Data.Foldable
import qualified Data.Text as T
import Development.IDE.Test
import Test.Hls
import Text.Regex.TDFA

assertFoundIn :: T.Text -> T.Text -> Assertion
assertFoundIn part whole =
assertBool
(T.unpack $ "failed to find: `" <> part <> "` in hover message:\n" <> whole)
(part `T.isInfixOf` whole)

assertNotFoundIn :: T.Text -> T.Text -> Assertion
assertNotFoundIn part whole =
assertBool
(T.unpack $ "found unexpected: `" <> part <> "` in hover message:\n" <> whole)
(not . T.isInfixOf part $ whole)

checkHover :: (HasCallStack) => Maybe Hover -> [Expect] -> Session ()
checkHover hover expectations = traverse_ check expectations
where
check :: (HasCallStack) => Expect -> Session ()
check expected =
case hover of
Nothing -> unless (expected == ExpectNoHover) $ liftIO $ assertFailure "no hover found"
Just Hover{_contents = (InL MarkupContent{_value = standardizeQuotes -> msg})
,_range = _rangeInHover } ->
case expected of
ExpectRange _expectedRange -> liftIO $ assertFailure $ "ExpectRange assertion not implemented, yet."
ExpectHoverRange _expectedRange -> liftIO $ assertFailure $ "ExpectHoverRange assertion not implemented, yet."
ExpectHoverText snippets -> liftIO $ traverse_ (`assertFoundIn` msg) snippets
ExpectHoverExcludeText snippets -> liftIO $ traverse_ (`assertNotFoundIn` msg) snippets
ExpectHoverTextRegex re -> liftIO $ assertBool ("Regex not found in " <> T.unpack msg) (msg =~ re :: Bool)
ExpectNoHover -> liftIO $ assertFailure $ "Expected no hover but got " <> show hover
_ -> pure () -- all other expectations not relevant to hover
_ -> liftIO $ assertFailure $ "test not expecting this kind of hover info" <> show hover
2 changes: 2 additions & 0 deletions ghcide-test/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import BootTests
import ClientSettingsTests
import CodeLensTests
import CompletionTests
import ConstructorHoverTests
import CPPTests
import CradleTests
import DependentFileTest
Expand Down Expand Up @@ -79,6 +80,7 @@ main = do
, CodeLensTests.tests
, OutlineTests.tests
, HighlightTests.tests
, ConstructorHoverTests.tests
, FindDefinitionAndHoverTests.tests
, FindImplementationAndHoverTests.tests
, PluginSimpleTests.tests
Expand Down
6 changes: 5 additions & 1 deletion ghcide/src/Development/IDE/Core/Actions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import Development.IDE.Core.PositionMapping
import Development.IDE.Core.RuleTypes
import Development.IDE.Core.Service
import Development.IDE.Core.Shake
import Development.IDE.GHC.Compat (DynFlags (..),
ms_hspp_opts)
import Development.IDE.Graph
import qualified Development.IDE.Spans.AtPoint as AtPoint
import Development.IDE.Types.HscEnvEq (hscEnv)
Expand Down Expand Up @@ -52,12 +54,14 @@ getAtPoint file pos = runMaybeT $ do
shakeExtras <- lift askShake

env <- hscEnv . fst <$> useWithStaleFastMT GhcSession file
modSummary <- fst <$> useWithStaleFastMT GetModSummary file
dkMap <- lift $ maybe (DKMap mempty mempty mempty) fst <$> runMaybeT (useWithStaleFastMT GetDocMap file)
let enabledExtensions = extensionFlags (ms_hspp_opts (msrModSummary modSummary))

!pos' <- MaybeT (return $ fromCurrentPosition mapping pos)

MaybeT $ liftIO $ fmap (first (toCurrentRange mapping =<<)) <$>
AtPoint.atPoint opts shakeExtras hf dkMap env pos'
AtPoint.atPoint opts shakeExtras hf dkMap env pos' enabledExtensions

-- | Converts locations in the source code to their current positions,
-- taking into account changes that may have occurred due to edits.
Expand Down
1 change: 1 addition & 0 deletions ghcide/src/Development/IDE/GHC/Compat/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module Development.IDE.GHC.Compat.Util (
Pair(..),
-- * EnumSet
EnumSet,
member,
toList,
-- * FastString exports
FastString,
Expand Down
7 changes: 5 additions & 2 deletions ghcide/src/Development/IDE/GHC/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module Development.IDE.GHC.Util(
printOutputable,
printOutputableOneLine,
getExtensions,
getExtensionsSet,
stripOccNamePrefix,
) where

Expand Down Expand Up @@ -279,7 +280,10 @@ printOutputable' print =
{-# INLINE printOutputable #-}

getExtensions :: ParsedModule -> [Extension]
getExtensions = toList . extensionFlags . ms_hspp_opts . pm_mod_summary
getExtensions = toList . getExtensionsSet

getExtensionsSet :: ParsedModule -> EnumSet Extension
getExtensionsSet = extensionFlags . ms_hspp_opts . pm_mod_summary

-- | When e.g. DuplicateRecordFields is enabled, compiler generates
-- names like "$sel:accessor:One" and "$sel:accessor:Two" to
Expand Down Expand Up @@ -331,4 +335,3 @@ occNamePrefixes =
, "$c"
, "$m"
]

4 changes: 2 additions & 2 deletions ghcide/src/Development/IDE/Plugin/Completions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ resolveCompletion ide _pid comp@CompletionItem{_detail,_documentation,_data_} ur
Nothing -> liftIO $ spanDocToMarkdown . fst <$> getDocumentationTryGhc (hscEnv sess) name
typ <- case lookupNameEnv km name of
_ | not needType -> pure Nothing
Just ty -> pure (safeTyThingType ty)
Just ty -> pure (safeTyThingType True ty)
Nothing -> do
(safeTyThingType =<<) <$> liftIO (lookupName (hscEnv sess) name)
(safeTyThingType True =<<) <$> liftIO (lookupName (hscEnv sess) name)
let det1 = case typ of
Just ty -> Just (":: " <> printOutputable (stripForall ty) <> "\n")
Nothing -> Nothing
Expand Down
5 changes: 3 additions & 2 deletions ghcide/src/Development/IDE/Spans/AtPoint.hs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,9 @@ atPoint
-> DocAndTyThingMap
-> HscEnv
-> Position
-> Util.EnumSet Extension
-> IO (Maybe (Maybe Range, [T.Text]))
atPoint opts@IdeOptions{} shakeExtras@ShakeExtras{ withHieDb, hiedbWriter } har@(HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (DKMap dm km _am) env pos =
atPoint opts@IdeOptions{} shakeExtras@ShakeExtras{ withHieDb, hiedbWriter } har@(HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (DKMap dm km _am) env pos enabledExtensions =
listToMaybe <$> sequence (pointCommand hf pos hoverInfo)
where
-- Hover info for values/data
Expand Down Expand Up @@ -318,7 +319,7 @@ atPoint opts@IdeOptions{} shakeExtras@ShakeExtras{ withHieDb, hiedbWriter } har@
let
typeSig = case identType dets of
Just t -> prettyType (Just n) locationsMap t
Nothing -> case safeTyThingType =<< lookupNameEnv km n of
Nothing -> case safeTyThingType (Util.member LinearTypes enabledExtensions) =<< lookupNameEnv km n of
Just kind -> prettyTypeFromType (Just n) locationsMap kind
Nothing -> wrapHaskell (printOutputable n)
definitionLoc = maybeToList (pretty (definedAt n) (prettyPackageName n))
Expand Down
18 changes: 6 additions & 12 deletions ghcide/src/Development/IDE/Spans/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

module Development.IDE.Spans.Common (
unqualIEWrapName
, safeTyThingId
, safeTyThingType
, SpanDoc(..)
, SpanDocUris(..)
Expand Down Expand Up @@ -44,17 +43,12 @@ type ArgDocMap = NameEnv (IntMap SpanDoc)
unqualIEWrapName :: IEWrappedName GhcPs -> T.Text
unqualIEWrapName = printOutputable . rdrNameOcc . ieWrappedName

-- From haskell-ide-engine/src/Haskell/Ide/Engine/Support/HieExtras.hs
safeTyThingType :: TyThing -> Maybe Type
safeTyThingType thing
| Just i <- safeTyThingId thing = Just (varType i)
safeTyThingType (ATyCon tycon) = Just (tyConKind tycon)
safeTyThingType _ = Nothing

safeTyThingId :: TyThing -> Maybe Id
safeTyThingId (AnId i) = Just i
safeTyThingId (AConLike (RealDataCon dataCon)) = Just (dataConWrapId dataCon)
safeTyThingId _ = Nothing
safeTyThingType :: Bool -> TyThing -> Maybe Type
safeTyThingType showLinearType (AConLike (RealDataCon dataCon))
= Just (dataConDisplayType showLinearType dataCon)
safeTyThingType _ (AnId i) = Just (varType i)
safeTyThingType _ (ATyCon tycon) = Just (tyConKind tycon)
safeTyThingType _ _ = Nothing

-- Possible documentation for an element in the code
data SpanDoc
Expand Down
2 changes: 2 additions & 0 deletions haskell-language-server.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,7 @@ test-suite ghcide-tests
ClientSettingsTests
CodeLensTests
CompletionTests
ConstructorHoverTests
CPPTests
CradleTests
DependentFileTest
Expand All @@ -2158,6 +2159,7 @@ test-suite ghcide-tests
HaddockTests
HieDbRetry
HighlightTests
Hover
IfaceTests
InitializeResponseTests
LogType
Expand Down
Loading