Skip to content

Extract the qualified name from already imported module #1445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 26, 2021
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
38 changes: 37 additions & 1 deletion ghcide/src/Development/IDE/Plugin/CodeAction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,11 @@ suggestNewImport packageExportsMap ParsedModule {pm_parsed_source = L _ HsModule
| msg <- unifySpaces _message
, Just thingMissing <- extractNotInScopeName msg
, qual <- extractQualifiedModuleName msg
, qual' <-
extractDoesNotExportModuleName msg
>>= (findImportDeclByModuleName hsmodImports . T.unpack)
>>= ideclAs . unLoc
<&> T.pack . moduleNameString . unLoc
, Just insertLine <- case hsmodImports of
[] -> case srcSpanStart $ getLoc (head hsmodDecls) of
RealSrcLoc s -> Just $ srcLocLine s - 1
Expand All @@ -1206,7 +1211,7 @@ suggestNewImport packageExportsMap ParsedModule {pm_parsed_source = L _ HsModule
, extendImportSuggestions <- matchRegexUnifySpaces msg
"Perhaps you want to add ‘[^’]*’ to the import list in the import of ‘([^’]*)’"
= [(imp, [TextEdit (Range insertPos insertPos) (imp <> "\n")])
| imp <- sort $ constructNewImportSuggestions packageExportsMap (qual, thingMissing) extendImportSuggestions
| imp <- sort $ constructNewImportSuggestions packageExportsMap (qual <|> qual', thingMissing) extendImportSuggestions
]
suggestNewImport _ _ _ = []

Expand Down Expand Up @@ -1272,6 +1277,37 @@ extractQualifiedModuleName x
| otherwise
= Nothing

-- | If a module has been imported qualified, and we want to ues the same qualifier for other modules
-- which haven't been imported, 'extractQualifiedModuleName' won't work. Thus we need extract the qualifier
-- from the imported one.
--
-- For example, we write f = T.putStrLn, where putStrLn comes from Data.Text.IO, with the following import(s):
-- 1.
-- import qualified Data.Text as T
--
-- Module ‘Data.Text’ does not export ‘putStrLn’.
--
-- 2.
-- import qualified Data.Text as T
-- import qualified Data.Functor as T
--
-- Neither ‘Data.Functor’ nor ‘Data.Text’ exports ‘putStrLn’.
--
-- 3.
-- import qualified Data.Text as T
-- import qualified Data.Functor as T
-- import qualified Data.Function as T
--
-- Neither ‘Data.Function’,
-- ‘Data.Functor’ nor ‘Data.Text’ exports ‘putStrLn’.
extractDoesNotExportModuleName :: T.Text -> Maybe T.Text
extractDoesNotExportModuleName x
| Just [m] <-
matchRegexUnifySpaces x "Module ‘([^’]*)’ does not export"
<|> matchRegexUnifySpaces x "nor ‘([^’]*)’ exports"
= Just m
| otherwise
= Nothing
-------------------------------------------------------------------------------------------------


Expand Down
13 changes: 13 additions & 0 deletions ghcide/test/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,19 @@ suggestImportTests = testGroup "suggest import actions"
, test True [] "f = (&) [] id" [] "import Data.Function ((&))"
, test True [] "f = (.|.)" [] "import Data.Bits (Bits((.|.)))"
, test True [] "f = (.|.)" [] "import Data.Bits ((.|.))"
, test True
["qualified Data.Text as T"
] "f = T.putStrLn" [] "import qualified Data.Text.IO as T"
, test True
[ "qualified Data.Text as T"
, "qualified Data.Function as T"
] "f = T.putStrLn" [] "import qualified Data.Text.IO as T"
, test True
[ "qualified Data.Text as T"
, "qualified Data.Function as T"
, "qualified Data.Functor as T"
, "qualified Data.Data as T"
] "f = T.putStrLn" [] "import qualified Data.Text.IO as T"
]
]
where
Expand Down