Skip to content

Commit dc13d98

Browse files
authored
Trigger extending import only when the item is not in scope (#1309)
* Trigger extending import only when it's not in scope * Extract GlobalRdrElts before getting into the producer * Fix macros * Compare only elements' name * Rollback due to performance
1 parent ab79a4a commit dc13d98

File tree

3 files changed

+40
-16
lines changed

3 files changed

+40
-16
lines changed

Diff for: ghcide/src/Development/IDE/Plugin/Completions.hs

+5-4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import Ide.Plugin.Config (Config (completionSnippetsOn))
3535
import Ide.PluginUtils (getClientConfig)
3636
import Ide.Types
3737
import TcRnDriver (tcRnImportDecls)
38+
import Control.Concurrent.Async (concurrently)
3839
#if defined(GHC_LIB)
3940
import Development.IDE.Import.DependencyInformation
4041
#endif
@@ -76,11 +77,11 @@ produceCompletions = do
7677
(Just (ms,imps), Just sess) -> do
7778
let env = hscEnv sess
7879
-- We do this to be able to provide completions of items that are not restricted to the explicit list
79-
res <- liftIO $ tcRnImportDecls env (dropListFromImportDecl <$> imps)
80-
case res of
81-
(_, Just rdrEnv) -> do
80+
(global, inScope) <- liftIO $ tcRnImportDecls env (dropListFromImportDecl <$> imps) `concurrently` tcRnImportDecls env imps
81+
case (global, inScope) of
82+
((_, Just globalEnv), (_, Just inScopeEnv)) -> do
8283
let uri = fromNormalizedUri $ normalizedFilePathToUri file
83-
cdata <- liftIO $ cacheDataProducer uri env (ms_mod ms) rdrEnv imps parsedDeps
84+
cdata <- liftIO $ cacheDataProducer uri env (ms_mod ms) globalEnv inScopeEnv imps parsedDeps
8485
return ([], Just cdata)
8586
(_diag, _) ->
8687
return ([], Nothing)

Diff for: ghcide/src/Development/IDE/Plugin/Completions/Logic.hs

+6-5
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,9 @@ mkPragmaCompl label insertText =
293293
Nothing Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet)
294294
Nothing Nothing Nothing Nothing Nothing
295295

296-
cacheDataProducer :: Uri -> HscEnv -> Module -> GlobalRdrEnv -> [LImportDecl GhcPs] -> [ParsedModule] -> IO CachedCompletions
297-
cacheDataProducer uri packageState curMod rdrEnv limports deps = do
296+
297+
cacheDataProducer :: Uri -> HscEnv -> Module -> GlobalRdrEnv-> GlobalRdrEnv -> [LImportDecl GhcPs] -> [ParsedModule] -> IO CachedCompletions
298+
cacheDataProducer uri packageState curMod globalEnv inScopeEnv limports deps = do
298299
let dflags = hsc_dflags packageState
299300
curModName = moduleName curMod
300301

@@ -314,7 +315,7 @@ cacheDataProducer uri packageState curMod rdrEnv limports deps = do
314315
-- The given namespaces for the imported modules (ie. full name, or alias if used)
315316
allModNamesAsNS = map (showModName . asNamespace) importDeclerations
316317

317-
rdrElts = globalRdrEnvElts rdrEnv
318+
rdrElts = globalRdrEnvElts globalEnv
318319

319320
foldMapM :: (Foldable f, Monad m, Monoid b) => (a -> m b) -> f a -> m b
320321
foldMapM f xs = foldr step return xs mempty where
@@ -328,7 +329,8 @@ cacheDataProducer uri packageState curMod rdrEnv limports deps = do
328329
(, mempty) <$> toCompItem par curMod curModName n Nothing
329330
getComplsForOne (GRE n par False prov) =
330331
flip foldMapM (map is_decl prov) $ \spec -> do
331-
let originalImportDecl = Map.lookup (is_dloc spec) importMap
332+
-- we don't want to extend import if it's already in scope
333+
let originalImportDecl = if null $ lookupGRE_Name inScopeEnv n then Map.lookup (is_dloc spec) importMap else Nothing
332334
compItem <- toCompItem par curMod (is_mod spec) n originalImportDecl
333335
let unqual
334336
| is_qual spec = []
@@ -371,7 +373,6 @@ cacheDataProducer uri packageState curMod rdrEnv limports deps = do
371373
, importableModules = moduleNames
372374
}
373375

374-
375376
-- | Produces completions from the top level declarations of a module.
376377
localCompletionsForParsedModule :: Uri -> ParsedModule -> CachedCompletions
377378
localCompletionsForParsedModule uri pm@ParsedModule{pm_parsed_source = L _ HsModule{hsmodDecls, hsmodName}} =

Diff for: ghcide/test/exe/Main.hs

+29-7
Original file line numberDiff line numberDiff line change
@@ -3454,6 +3454,26 @@ completionCommandTest name src pos wanted expected = testSession name $ do
34543454
expectMessages @ApplyWorkspaceEditRequest 1 $ \edit ->
34553455
liftIO $ assertFailure $ "Expected no edit but got: " <> show edit
34563456

3457+
completionNoCommandTest ::
3458+
String ->
3459+
[T.Text] ->
3460+
Position ->
3461+
T.Text ->
3462+
TestTree
3463+
completionNoCommandTest name src pos wanted = testSession name $ do
3464+
docId <- createDoc "A.hs" "haskell" (T.unlines src)
3465+
_ <- waitForDiagnostics
3466+
compls <- getCompletions docId pos
3467+
let wantedC = find ( \case
3468+
CompletionItem {_insertText = Just x} -> wanted `T.isPrefixOf` x
3469+
_ -> False
3470+
) compls
3471+
case wantedC of
3472+
Nothing ->
3473+
liftIO $ assertFailure $ "Cannot find expected completion in: " <> show [_label | CompletionItem {_label} <- compls]
3474+
Just CompletionItem{..} -> liftIO . assertBool ("Expected no command but got: " <> show _command) $ null _command
3475+
3476+
34573477
topLevelCompletionTests :: [TestTree]
34583478
topLevelCompletionTests = [
34593479
completionTest
@@ -3674,18 +3694,21 @@ nonLocalCompletionTests =
36743694
(Position 2 4)
36753695
"ZeroPad"
36763696
["module A where", "import Text.Printf (FormatAdjustment (ZeroPad))", "ZeroPad"]
3677-
, completionCommandTest
3697+
, completionNoCommandTest
36783698
"parent imported all"
36793699
["module A where", "import Text.Printf (FormatAdjustment (..))", "ZeroPad"]
36803700
(Position 2 4)
36813701
"ZeroPad"
3682-
["module A where", "import Text.Printf (FormatAdjustment (..))", "ZeroPad"]
3683-
, completionCommandTest
3702+
, completionNoCommandTest
36843703
"already imported"
36853704
["module A where", "import Text.Printf (FormatAdjustment (ZeroPad))", "ZeroPad"]
36863705
(Position 2 4)
3687-
"ZeroPad"
3688-
["module A where", "import Text.Printf (FormatAdjustment (ZeroPad))", "ZeroPad"]
3706+
"ZeroPad"
3707+
, completionNoCommandTest
3708+
"function from Prelude"
3709+
["module A where", "import Data.Maybe ()", "Nothing"]
3710+
(Position 2 4)
3711+
"Nothing"
36893712
]
36903713
, testGroup "Record completion"
36913714
[ completionCommandTest
@@ -3700,12 +3723,11 @@ nonLocalCompletionTests =
37003723
(Position 2 10)
37013724
"FormatParse {"
37023725
["module A where", "import Text.Printf (FormatParse (FormatParse))", "FormatParse"]
3703-
, completionCommandTest
3726+
, completionNoCommandTest
37043727
"already imported"
37053728
["module A where", "import Text.Printf (FormatParse (FormatParse))", "FormatParse"]
37063729
(Position 2 10)
37073730
"FormatParse {"
3708-
["module A where", "import Text.Printf (FormatParse (FormatParse))", "FormatParse"]
37093731
]
37103732
],
37113733
-- we need this test to make sure the ghcide completions module does not return completions for language pragmas. this functionality is turned on in hls

0 commit comments

Comments
 (0)