Skip to content

Commit 7610872

Browse files
authored
Reintroduce ghc-lib flag for hlint plugin (#3757)
* Remove bitrotted CPP gated code A lot of the HLINT_ON_GHC_LIB gated code has been bitrotting since this flag was removed. This could be reintroduced if we wanted to directly work on the same parsed AST, but as the hlint ghc plugin showed this may not make much difference: https://www.haskellforall.com/2023/09/ghc-plugin-for-hlint.html * Reintroduce ghc-lib flag for hlint plugin The ghc-lib flag was removed in #3015, but it's still useful to be able to compile hls-hlint-plugin using the GHC API if you've done so for hlint and ghc-lib-parser-ex, rather than using ghc-lib-parser as it simplifies the build and dependencies.
1 parent 79e36f5 commit 7610872

File tree

2 files changed

+23
-72
lines changed

2 files changed

+23
-72
lines changed

Diff for: haskell-language-server.cabal

+15-2
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,13 @@ test-suite hls-retrie-plugin-tests
593593
-- hlint plugin
594594
-----------------------------
595595

596+
flag ghc-lib
597+
description:
598+
Use ghc-lib-parser rather than the ghc library (requires hlint and
599+
ghc-lib-parser-ex to also be built with it)
600+
default: True
601+
manual: True
602+
596603
flag hlint
597604
description: Enable hlint plugin
598605
default: True
@@ -628,11 +635,17 @@ library hls-hlint-plugin
628635
, text
629636
, transformers
630637
, unordered-containers
631-
, ghc-lib-parser
632638
, ghc-lib-parser-ex
633639
, apply-refact
634640

635-
cpp-options: -DHLINT_ON_GHC_LIB
641+
if flag(ghc-lib)
642+
cpp-options: -DGHC_LIB
643+
build-depends:
644+
ghc-lib-parser
645+
else
646+
build-depends:
647+
ghc
648+
, ghc-boot
636649

637650
default-extensions:
638651
DataKinds

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

+8-70
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
-- lots of CPP, we just disable the warning until later.
1919
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
2020

21-
#ifdef HLINT_ON_GHC_LIB
21+
#ifdef GHC_LIB
2222
#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc_lib_parser(x,y,z)
2323
#else
2424
#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc(x,y,z)
@@ -61,7 +61,6 @@ import Development.IDE.Core.Shake (getDiagnost
6161
import qualified Refact.Apply as Refact
6262
import qualified Refact.Types as Refact
6363

64-
#ifdef HLINT_ON_GHC_LIB
6564
import Development.IDE.GHC.Compat (DynFlags,
6665
WarningFlag (Opt_WarnUnrecognisedPragmas),
6766
extensionFlags,
@@ -71,18 +70,18 @@ import Development.IDE.GHC.Compat (DynFlags,
7170
import qualified Development.IDE.GHC.Compat.Util as EnumSet
7271

7372
#if MIN_GHC_API_VERSION(9,4,0)
74-
import qualified "ghc-lib-parser" GHC.Data.Strict as Strict
73+
import qualified GHC.Data.Strict as Strict
7574
#endif
7675
#if MIN_GHC_API_VERSION(9,0,0)
77-
import "ghc-lib-parser" GHC.Types.SrcLoc hiding
76+
import GHC.Types.SrcLoc hiding
7877
(RealSrcSpan)
79-
import qualified "ghc-lib-parser" GHC.Types.SrcLoc as GHC
78+
import qualified GHC.Types.SrcLoc as GHC
8079
#else
81-
import "ghc-lib-parser" SrcLoc hiding
80+
import qualified SrcLoc as GHC
81+
import SrcLoc hiding
8282
(RealSrcSpan)
83-
import qualified "ghc-lib-parser" SrcLoc as GHC
8483
#endif
85-
import "ghc-lib-parser" GHC.LanguageExtensions (Extension)
84+
import GHC.LanguageExtensions (Extension)
8685
import Language.Haskell.GhclibParserEx.GHC.Driver.Session as GhclibParserEx (readExtension)
8786
import System.FilePath (takeFileName)
8887
import System.IO (IOMode (WriteMode),
@@ -94,21 +93,7 @@ import System.IO (IOMode (Wri
9493
utf8,
9594
withFile)
9695
import System.IO.Temp
97-
#else
98-
import Development.IDE.GHC.Compat hiding
99-
(setEnv,
100-
(<+>))
101-
import GHC.Generics (Associativity (LeftAssociative, NotAssociative, RightAssociative))
102-
#if MIN_GHC_API_VERSION(9,2,0)
103-
import Language.Haskell.GHC.ExactPrint.ExactPrint (deltaOptions)
104-
#else
105-
import Language.Haskell.GHC.ExactPrint.Delta (deltaOptions)
106-
#endif
107-
import Language.Haskell.GHC.ExactPrint.Parsers (postParseTransform)
108-
import Language.Haskell.GHC.ExactPrint.Types (Rigidity (..))
109-
import Language.Haskell.GhclibParserEx.Fixity as GhclibParserEx (applyFixities)
110-
import qualified Refact.Fixity as Refact
111-
#endif
96+
11297
import Ide.Plugin.Config hiding
11398
(Config)
11499
import Ide.Plugin.Error
@@ -159,7 +144,6 @@ instance Pretty Log where
159144
LogGetIdeas fp -> "Getting hlint ideas for " <+> viaShow fp
160145
LogResolve msg -> pretty msg
161146

162-
#ifdef HLINT_ON_GHC_LIB
163147
-- Reimplementing this, since the one in Development.IDE.GHC.Compat isn't for ghc-lib
164148
#if !MIN_GHC_API_VERSION(9,0,0)
165149
type BufSpan = ()
@@ -173,7 +157,6 @@ pattern RealSrcSpan x y = GHC.RealSrcSpan x y
173157
pattern RealSrcSpan x y <- ((,Nothing) -> (GHC.RealSrcSpan x, y))
174158
#endif
175159
{-# COMPLETE RealSrcSpan, UnhelpfulSpan #-}
176-
#endif
177160

178161
#if MIN_GHC_API_VERSION(9,4,0)
179162
fromStrictMaybe :: Strict.Maybe a -> Maybe a
@@ -316,28 +299,6 @@ getIdeas recorder nfp = do
316299
fmap applyHints' (moduleEx flags)
317300

318301
where moduleEx :: ParseFlags -> Action (Maybe (Either ParseError ModuleEx))
319-
#ifndef HLINT_ON_GHC_LIB
320-
moduleEx _flags = do
321-
mbpm <- getParsedModuleWithComments nfp
322-
return $ createModule <$> mbpm
323-
where
324-
createModule pm = Right (createModuleEx anns (applyParseFlagsFixities modu))
325-
where anns = pm_annotations pm
326-
modu = pm_parsed_source pm
327-
328-
applyParseFlagsFixities :: ParsedSource -> ParsedSource
329-
applyParseFlagsFixities modul = GhclibParserEx.applyFixities (parseFlagsToFixities _flags) modul
330-
331-
parseFlagsToFixities :: ParseFlags -> [(String, Fixity)]
332-
parseFlagsToFixities = map toFixity . Hlint.fixities
333-
334-
toFixity :: FixityInfo -> (String, Fixity)
335-
toFixity (name, dir, i) = (name, Fixity NoSourceText i $ f dir)
336-
where
337-
f LeftAssociative = InfixL
338-
f RightAssociative = InfixR
339-
f NotAssociative = InfixN
340-
#else
341302
moduleEx flags = do
342303
mbpm <- getParsedModuleWithComments nfp
343304
-- If ghc was not able to parse the module, we disable hlint diagnostics
@@ -360,11 +321,6 @@ getIdeas recorder nfp = do
360321
-- and the ModSummary dynflags. However using the parsedFlags extensions
361322
-- can sometimes interfere with the hlint parsing of the file.
362323
-- See https://github.com/haskell/haskell-language-server/issues/1279
363-
--
364-
-- Note: this is used when HLINT_ON_GHC_LIB is defined. We seem to need
365-
-- these extensions to construct dynflags to parse the file again. Therefore
366-
-- using hlint default extensions doesn't seem to be a problem when
367-
-- HLINT_ON_GHC_LIB is not defined because we don't parse the file again.
368324
getExtensions :: NormalizedFilePath -> Action [Extension]
369325
getExtensions nfp = do
370326
dflags <- getFlags
@@ -375,7 +331,6 @@ getExtensions nfp = do
375331
getFlags = do
376332
modsum <- use_ GetModSummary nfp
377333
return $ ms_hspp_opts $ msrModSummary modsum
378-
#endif
379334

380335
-- ---------------------------------------------------------------------
381336

@@ -573,7 +528,6 @@ applyHint recorder ide nfp mhint verTxtDocId =
573528
-- But "Idea"s returned by HLint point to starting position of the expressions
574529
-- that contain refactorings, so they are often outside the refactorings' boundaries.
575530
let position = Nothing
576-
#ifdef HLINT_ON_GHC_LIB
577531
let writeFileUTF8NoNewLineTranslation file txt =
578532
withFile file WriteMode $ \h -> do
579533
hSetEncoding h utf8
@@ -589,22 +543,6 @@ applyHint recorder ide nfp mhint verTxtDocId =
589543
let refactExts = map show $ enabled ++ disabled
590544
(Right <$> applyRefactorings (topDir dflags) position commands temp refactExts)
591545
`catches` errorHandlers
592-
#else
593-
mbParsedModule <- liftIO $ runAction' $ getParsedModuleWithComments nfp
594-
res <-
595-
case mbParsedModule of
596-
Nothing -> throwError "Apply hint: error parsing the module"
597-
Just pm -> do
598-
let anns = pm_annotations pm
599-
let modu = pm_parsed_source pm
600-
-- apply-refact uses RigidLayout
601-
let rigidLayout = deltaOptions RigidLayout
602-
(anns', modu') <-
603-
ExceptT $ mapM (uncurry Refact.applyFixities)
604-
$ postParseTransform (Right (anns, [], dflags, modu)) rigidLayout
605-
liftIO $ (Right <$> Refact.applyRefactorings' position commands anns' modu')
606-
`catches` errorHandlers
607-
#endif
608546
case res of
609547
Right appliedFile -> do
610548
let wsEdit = diffText' True (verTxtDocId, oldContent) (T.pack appliedFile) IncludeDeletions

0 commit comments

Comments
 (0)