Skip to content

Commit b807b10

Browse files
committed
Parse module with ghc session extensions
1 parent 2d137bb commit b807b10

File tree

1 file changed

+52
-51
lines changed
  • plugins/hlint-hls-plugin/src/Ide/Plugin

1 file changed

+52
-51
lines changed

plugins/hlint-hls-plugin/src/Ide/Plugin/Hlint.hs

+52-51
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
module Ide.Plugin.Hlint
1414
(
1515
descriptor
16-
--, provider
16+
--, provider
1717
) where
1818
import Refact.Apply
1919
import Control.Arrow ((&&&))
@@ -50,18 +50,30 @@ import Development.IDE.Core.RuleTypes
5050
import Development.IDE.Core.Rules
5151
import Development.IDE.Core.Service
5252
import Development.IDE.Core.Shake
53+
import Development.IDE.GHC.Util (hscEnv)
5354
import Development.IDE.LSP.Server
5455
import Development.IDE.Plugin
5556
import Development.IDE.Types.Diagnostics as D
5657
import Development.IDE.Types.Location
5758
import Development.IDE.Types.Logger
5859
import Development.Shake
5960
-- import Development.Shake hiding ( Diagnostic )
60-
import GHC
61+
import GHC hiding (DynFlags(..))
6162
import GHC.Generics
6263
import GHC.Generics (Generic)
6364
import SrcLoc
6465
import HscTypes (ModIface, ModSummary)
66+
67+
#ifndef GHC_LIB
68+
import GHC (DynFlags(..))
69+
import HscTypes (hsc_dflags)
70+
#else
71+
import RealGHC (DynFlags(..))
72+
import RealGHC.HscTypes (hsc_dflags)
73+
import qualified RealGHC.EnumSet as EnumSet
74+
import Language.Haskell.GhclibParserEx.GHC.Driver.Session as GhclibParserEx (readExtension)
75+
#endif
76+
6577
import Ide.Logger
6678
import Ide.Types
6779
import Ide.Plugin
@@ -106,9 +118,7 @@ rules = do
106118
ideas <- getIdeas file
107119
return $ (diagnostics file ideas, Just ())
108120

109-
hlintDataDir <- liftIO getExecutablePath
110-
111-
getHlintSettingsRule (HlintEnabled hlintDataDir True)
121+
getHlintSettingsRule (HlintEnabled [])
112122

113123
action $ do
114124
files <- getFilesOfInterest
@@ -117,9 +127,9 @@ rules = do
117127
where
118128

119129
diagnostics :: NormalizedFilePath -> Either ParseError [Idea] -> [FileDiagnostic]
120-
diagnostics file (Right ideas) =
130+
diagnostics file (Right ideas) =
121131
[(file, ShowDiag, ideaToDiagnostic i) | i <- ideas, ideaSeverity i /= Ignore]
122-
diagnostics file (Left parseErr) =
132+
diagnostics file (Left parseErr) =
123133
[(file, ShowDiag, parseErrorToDiagnostic parseErr)]
124134

125135
ideaToDiagnostic :: Idea -> Diagnostic
@@ -131,17 +141,19 @@ rules = do
131141
, _source = Just "hlint"
132142
, _message = T.pack $ show idea
133143
, _relatedInformation = Nothing
144+
, _tags = Nothing
134145
}
135-
146+
136147
parseErrorToDiagnostic :: ParseError -> Diagnostic
137148
parseErrorToDiagnostic (Hlint.ParseError l msg contents) =
138-
LSP.Diagnostic {
149+
LSP.Diagnostic {
139150
_range = srcSpanToRange l
140151
, _severity = Just LSP.DsInfo
141152
, _code = Just (LSP.StringValue "parser")
142153
, _source = Just "hlint"
143154
, _message = T.unlines [T.pack msg,T.pack contents]
144155
, _relatedInformation = Nothing
156+
, _tags = Nothing
145157
}
146158
-- This one is defined in Development.IDE.GHC.Error but here
147159
-- the types could come from ghc-lib or ghc
@@ -158,24 +170,35 @@ rules = do
158170

159171
getIdeas :: NormalizedFilePath -> Action (Either ParseError [Idea])
160172
getIdeas nfp = do
161-
(classify, hint) <- useNoFile_ GetHlintSettings
173+
logm $ "getIdeas:file:" ++ show nfp
174+
(flags, classify, hint) <- useNoFile_ GetHlintSettings
162175
let applyHints' modEx = applyHints classify hint [modEx]
163-
fmap (fmap applyHints') moduleEx
164-
where moduleEx :: Action (Either ParseError ModuleEx)
165-
moduleEx = do
176+
fmap (fmap applyHints') (moduleEx flags)
177+
where moduleEx :: ParseFlags -> Action (Either ParseError ModuleEx)
178+
moduleEx flags = do
166179
#ifndef GHC_LIB
167-
pm <- getParsedModule fnp
180+
pm <- getParsedModule nfp
168181
let anns = pm_annotations pm
169182
let modu = pm_parsed_source pm
170183
return $ Right (createModuleEx anns modu)
171184
#else
172-
liftIO $ parseModuleEx defaultParseFlags (fromNormalizedFilePath nfp) Nothing
185+
flags' <- setExtensions flags
186+
liftIO $ parseModuleEx flags' (fromNormalizedFilePath nfp) Nothing
187+
188+
setExtensions flags = do
189+
hsc <- hscEnv <$> use_ GhcSession nfp
190+
let dflags = hsc_dflags hsc
191+
let hscExts = EnumSet.toList (extensionFlags dflags)
192+
logm $ "getIdeas:setExtensions:hscExtensions:" ++ show hscExts
193+
let hlintExts = mapMaybe (GhclibParserEx.readExtension . show) hscExts
194+
logm $ "getIdeas:setExtensions:hlintExtensions:" ++ show hlintExts
195+
return $ flags { enabledExtensions = hlintExts }
173196
#endif
174197

175198
-- ---------------------------------------------------------------------
176199

177200
data HlintUsage
178-
= HlintEnabled { hlintUseDataDir :: FilePath, hlintAllowOverrides :: Bool }
201+
= HlintEnabled { cmdArgs :: [String] }
179202
| HlintDisabled
180203
deriving Show
181204

@@ -185,42 +208,20 @@ instance Hashable GetHlintSettings
185208
instance NFData GetHlintSettings
186209
instance NFData Hint where rnf = rwhnf
187210
instance NFData Classify where rnf = rwhnf
211+
instance NFData ParseFlags where rnf = rwhnf
188212
instance Show Hint where show = const "<hint>"
213+
instance Show ParseFlags where show = const "<parseFlags>"
189214
instance Binary GetHlintSettings
190215

191-
type instance RuleResult GetHlintSettings = ([Classify], Hint)
216+
type instance RuleResult GetHlintSettings = (ParseFlags, [Classify], Hint)
192217

193218
getHlintSettingsRule :: HlintUsage -> Rules ()
194219
getHlintSettingsRule usage =
195220
defineNoFile $ \GetHlintSettings ->
196221
liftIO $ case usage of
197-
HlintEnabled dir enableOverrides -> hlintSettings dir enableOverrides
222+
HlintEnabled cmdArgs -> argsSettings cmdArgs
198223
HlintDisabled -> fail "hlint configuration unspecified"
199224

200-
hlintSettings :: FilePath -> Bool -> IO ([Classify], Hint)
201-
hlintSettings hlintDataDir enableOverrides = do
202-
curdir <- getCurrentDirectory
203-
home <- ((:[]) <$> getHomeDirectory) `catchIOError` (const $ return [])
204-
hlintYaml <- if enableOverrides
205-
then
206-
findM Dir.doesFileExist $
207-
map (</> ".hlint.yaml") (ancestors curdir ++ home)
208-
else
209-
return Nothing
210-
(_, cs, hs) <- foldMapM parseSettings $
211-
(hlintDataDir </> "hlint.yaml") : maybeToList hlintYaml
212-
return (cs, hs)
213-
where
214-
ancestors = init . map joinPath . reverse . inits . splitPath
215-
-- `findSettings` calls `readFilesConfig` which in turn calls
216-
-- `readFileConfigYaml` which finally calls `decodeFileEither` from
217-
-- the `yaml` library. Annoyingly that function catches async
218-
-- exceptions and in particular, it ends up catching
219-
-- `ThreadKilled`. So, we have to mask to stop it from doing that.
220-
parseSettings f = mask $ \unmask ->
221-
findSettings (unmask . const (return (f, Nothing))) (Just f)
222-
foldMapM f = foldlM (\acc a -> do w <- f a; return $! mappend acc w) mempty
223-
224225
-- ---------------------------------------------------------------------
225226

226227
codeActionProvider :: CodeActionProvider
@@ -253,8 +254,8 @@ codeActionProvider _ _ plId docId _ context = (Right . LSP.List . map CACodeActi
253254

254255
applyAllCmd :: CommandFunction Uri
255256
applyAllCmd _lf ide uri = do
256-
let file = maybe (error $ show uri ++ " is not a file")
257-
toNormalizedFilePath'
257+
let file = maybe (error $ show uri ++ " is not a file.")
258+
toNormalizedFilePath'
258259
(uriToFilePath' uri)
259260
logm $ "applyAllCmd:file=" ++ show file
260261
res <- applyHint ide file Nothing
@@ -283,12 +284,12 @@ data OneHint = OneHint
283284
applyOneCmd :: CommandFunction ApplyOneParams
284285
applyOneCmd _lf ide (AOP uri pos title) = do
285286
let oneHint = OneHint pos title
286-
let file = maybe (error $ show uri ++ " is not a file") toNormalizedFilePath'
287+
let file = maybe (error $ show uri ++ " is not a file.") toNormalizedFilePath'
287288
(uriToFilePath' uri)
288289
res <- applyHint ide file (Just oneHint)
289290
logm $ "applyOneCmd:file=" ++ show file
290291
logm $ "applyOneCmd:res=" ++ show res
291-
return $
292+
return $
292293
case res of
293294
Left err -> (Left (responseError (T.pack $ "applyOne: " ++ show err)), Nothing)
294295
Right fs -> (Right Null, Just (WorkspaceApplyEdit, ApplyWorkspaceEditParams fs))
@@ -297,7 +298,7 @@ applyHint :: IdeState -> NormalizedFilePath -> Maybe OneHint -> IO (Either Strin
297298
applyHint ide nfp mhint =
298299
runExceptT $ do
299300
ideas <- bimapExceptT showParseError id $ ExceptT $ liftIO $ runAction "applyHint" ide $ getIdeas nfp
300-
let ideas' = maybe ideas (`filterIdeas` ideas) mhint
301+
let ideas' = maybe ideas (`filterIdeas` ideas) mhint
301302
let commands = map (show &&& ideaRefactoring) ideas'
302303
liftIO $ logm $ "applyHint:apply=" ++ show commands
303304
-- set Nothing as "position" for "applyRefactorings" because
@@ -328,8 +329,8 @@ applyHint ide nfp mhint =
328329
liftIO $ logm $ "applyHint:diff=" ++ show wsEdit
329330
ExceptT $ Right <$> (return wsEdit)
330331
Left err ->
331-
throwE (show err)
332-
where
332+
throwE (show err)
333+
where
333334
-- | If we are only interested in applying a particular hint then
334335
-- let's filter out all the irrelevant ideas
335336
filterIdeas :: OneHint -> [Idea] -> [Idea]
@@ -339,7 +340,7 @@ applyHint ide nfp mhint =
339340
in filter (\i -> ideaHint i == title' && ideaPos i == (l+1, c+1)) ideas
340341

341342
toRealSrcSpan (RealSrcSpan real) = real
342-
toRealSrcSpan (UnhelpfulSpan _) = error "No real souce span"
343+
toRealSrcSpan (UnhelpfulSpan x) = error $ "No real source span: " ++ show x
343344

344345
showParseError :: Hlint.ParseError -> String
345346
showParseError (Hlint.ParseError location message content) =
@@ -350,7 +351,7 @@ bimapExceptT :: Functor m => (e -> f) -> (a -> b) -> ExceptT e m a -> ExceptT f
350351
bimapExceptT f g (ExceptT m) = ExceptT (fmap h m) where
351352
h (Left e) = Left (f e)
352353
h (Right a) = Right (g a)
353-
{-# INLINE bimapExceptT #-}
354+
{-# INLINE bimapExceptT #-}
354355
-- ---------------------------------------------------------------------
355356
{-
356357
{-# LANGUAGE CPP #-}

0 commit comments

Comments
 (0)