Skip to content

Commit fb59ce3

Browse files
committed
Include let-bindings in context detection
1 parent c9626da commit fb59ce3

2 files changed

Lines changed: 124 additions & 3 deletions

File tree

ghcide-test/exe/CompletionTests.hs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
module CompletionTests (tests) where
99

1010
import Config
11-
import Control.Lens ((^.))
11+
import Control.Lens (view, (^.))
1212
import qualified Control.Lens as Lens
1313
import Control.Monad
1414
import Control.Monad.IO.Class (liftIO)
@@ -629,6 +629,110 @@ contextCompletionTests =
629629
]
630630
(Position 4 8)
631631
[("Xxxtype", CompletionItemKind_Struct, "Xxxtype", False, True, Nothing)]
632+
633+
-- where-clause / local binding context tests
634+
635+
, completionTest
636+
"type sig in where-clause gives type completions"
637+
[ "{-# OPTIONS_GHC -Wunused-binds #-}"
638+
, "module A () where"
639+
, "data Xxxtype = Xxxcon"
640+
, "xxxval = ()"
641+
, "foo x = bar"
642+
, " where"
643+
, " helper :: Xxx"
644+
, " helper = bar"
645+
]
646+
(Position 6 17) -- after "Xxx" in " helper :: Xxx"
647+
[("Xxxtype", CompletionItemKind_Struct, "Xxxtype", False, True, Nothing)]
648+
649+
, testSessionSingleFile "value binding in where-clause gives value completions" "A.hs"
650+
[ "{-# OPTIONS_GHC -Wunused-binds #-}"
651+
, "module A () where"
652+
, "data Xxxtype = Xxxcon"
653+
, "xxxval = ()"
654+
, "foo x = bar"
655+
, " where"
656+
, " helper = xxxv"
657+
] $ do
658+
doc <- openDoc "A.hs" "haskell"
659+
_ <- waitForDiagnostics
660+
compls <- getCompletions doc (Position 6 16) -- after "xxxv"
661+
let labels = map (view L.label) compls
662+
liftIO $ assertBool "xxxval should appear in value context" ("xxxval" `elem` labels)
663+
liftIO $ assertBool "Xxxtype should not appear in value context"
664+
(not ("Xxxtype" `elem` labels))
665+
666+
, testSessionSingleFile "no snippets in where-clause" "A.hs"
667+
[ "module A where"
668+
, "foo x = bar"
669+
, " where"
670+
, " helper = imp"
671+
] $ do
672+
doc <- openDoc "A.hs" "haskell"
673+
_ <- waitForDiagnostics
674+
compls <- getCompletions doc (Position 3 15) -- after "imp" in " helper = imp"
675+
let snippets = [ c | c@CompletionItem{..} <- compls
676+
, _kind == Just CompletionItemKind_Snippet
677+
, _label == "import" ]
678+
liftIO $ snippets @?= []
679+
680+
, completionTest
681+
"type sig in nested where-clause gives type completions"
682+
[ "{-# OPTIONS_GHC -Wunused-binds #-}"
683+
, "module A () where"
684+
, "data Xxxtype = Xxxcon"
685+
, "xxxval = ()"
686+
, "foo x = outer"
687+
, " where"
688+
, " inner y = result"
689+
, " where"
690+
, " sig :: Xxx"
691+
, " sig = undefined"
692+
]
693+
(Position 8 19) -- after "Xxx" in " sig :: Xxx"
694+
[("Xxxtype", CompletionItemKind_Struct, "Xxxtype", False, True, Nothing)]
695+
696+
, completionTest
697+
"type sig in match alternative where-clause gives type completions"
698+
[ "{-# OPTIONS_GHC -Wunused-binds #-}"
699+
, "module A () where"
700+
, "data Xxxtype = Xxxcon"
701+
, "xxxval = ()"
702+
, "foo 0 = bar"
703+
, " where helper :: Xxx"
704+
, "foo _ = baz"
705+
]
706+
(Position 5 21) -- after "Xxx" in " where helper :: Xxx"
707+
[("Xxxtype", CompletionItemKind_Struct, "Xxxtype", False, True, Nothing)]
708+
709+
, completionTest
710+
"type sig in pattern binding where-clause gives type completions"
711+
[ "{-# OPTIONS_GHC -Wunused-binds #-}"
712+
, "module A () where"
713+
, "data Xxxtype = Xxxcon"
714+
, "xxxval = ()"
715+
, "(a, b) = (undefined, undefined)"
716+
, " where"
717+
, " helper :: Xxx"
718+
, " helper = undefined"
719+
]
720+
(Position 6 17) -- after "Xxx" in " helper :: Xxx"
721+
[("Xxxtype", CompletionItemKind_Struct, "Xxxtype", False, True, Nothing)]
722+
723+
, completionTest
724+
"type sig in let expression gives type completions"
725+
[ "{-# OPTIONS_GHC -Wunused-binds #-}"
726+
, "module A () where"
727+
, "data Xxxtype = Xxxcon"
728+
, "xxxval = ()"
729+
, "foo ="
730+
, " let helper :: Xxx"
731+
, " helper = undefined"
732+
, " in helper"
733+
]
734+
(Position 5 19) -- after "Xxx" in " let helper :: Xxx"
735+
[("Xxxtype", CompletionItemKind_Struct, "Xxxtype", False, True, Nothing)]
632736
]
633737

634738
completionDocTests :: [TestTree]

ghcide/src/Development/IDE/Plugin/Completions/Context.hs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE CPP #-}
12
{-# LANGUAGE DerivingStrategies #-}
23
{-# LANGUAGE NoFieldSelectors #-}
34
{-# LANGUAGE TypeFamilies #-}
@@ -174,19 +175,35 @@ getContextMap pm =
174175
bindEntries :: HsBind GhcPs -> [(Range, Context)]
175176
bindEntries FunBind { fun_matches = MG { mg_alts = L _ alts } } =
176177
concatMap matchLocalEntries alts
177-
bindEntries PatBind { pat_rhs = GRHSs { grhssLocalBinds } } =
178+
bindEntries PatBind { pat_rhs = GRHSs { grhssLocalBinds, grhssGRHSs } } =
178179
localBindEntries grhssLocalBinds
180+
++ concatMap exprLocalEntries [ body | L _ (GRHS _ _ body) <- grhssGRHSs ]
179181
bindEntries _ = []
180182

181183
matchLocalEntries :: LMatch GhcPs (LHsExpr GhcPs) -> [(Range, Context)]
182-
matchLocalEntries (L _ Match { m_grhss = GRHSs { grhssLocalBinds } }) =
184+
matchLocalEntries (L _ Match { m_grhss = GRHSs { grhssLocalBinds, grhssGRHSs } }) =
183185
localBindEntries grhssLocalBinds
186+
++ concatMap exprLocalEntries [ body | L _ (GRHS _ _ body) <- grhssGRHSs ]
184187

185188
localBindEntries :: HsLocalBinds GhcPs -> [(Range, Context)]
186189
localBindEntries (HsValBinds _ (ValBinds _ binds sigs)) =
187190
sigsAndBindEntries sigs binds
188191
localBindEntries _ = []
189192

193+
exprLocalEntries :: LHsExpr GhcPs -> [(Range, Context)]
194+
exprLocalEntries (L _ expr) = case expr of
195+
#if !MIN_VERSION_ghc(9,9,0)
196+
HsLet _ _ binds _ body -> localBindEntries binds ++ exprLocalEntries body
197+
#else
198+
HsLet _ binds body -> localBindEntries binds ++ exprLocalEntries body
199+
#endif
200+
HsDo _ _ stmts ->
201+
[ entry
202+
| L _ (LetStmt _ lbs) <- unLoc stmts
203+
, entry <- localBindEntries lbs
204+
]
205+
_ -> []
206+
190207
-- | Look up the completion context at a given position.
191208
-- Returns the innermost (most specific) context that contains the position.
192209
--

0 commit comments

Comments
 (0)