Skip to content

Commit 7f00abb

Browse files
authored
Fix hlint parsing file with disabled extension (#2671)
* fix hlint parsing file with disabled extension * maybe test is magically fixed? * remove useness nub, add comments to getExtensions, add Known differences section to hlint plugin readme * remove redundant import
1 parent 47cb213 commit 7f00abb

File tree

3 files changed

+23
-11
lines changed

3 files changed

+23
-11
lines changed

plugins/hls-hlint-plugin/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@
55
This is typically done through an [HLint configuration file](https://github.com/ndmitchell/hlint#customizing-the-hints).
66
You can also change the behavior of HLint by adding a list of flags to `haskell.plugin.hlint.config.flags`
77
if your configuration is in a non-standard location or you want to change settings globally.
8+
9+
## Known Differences from the `hlint` executable
10+
11+
- The `hlint` executable by default turns on many extensions when parsing a file because it is not certain about the exact extensions that apply to the file (they may come from project files). This differs from HLS which uses only the extensions the file needs to parse the file. Hence it is possible for the `hlint` executable to report a parse error on a file, but the `hlint` plugin to work just fine on the same file. This does mean that the turning on/off of extensions in the hlint config may be ignored by the `hlint` plugin.
12+
- Hlint restrictions do not work (yet). This [PR](https://github.com/ndmitchell/hlint/pull/1340) should enable that functionality, but this requires a newer version of hlint to be used in HLS.
13+

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ import Development.IDE.Core.Shake (getDiagnost
5555
import qualified Refact.Apply as Refact
5656

5757
#ifdef HLINT_ON_GHC_LIB
58-
import Data.List (nub)
5958
import Development.IDE.GHC.Compat (BufSpan,
6059
DynFlags,
6160
WarningFlag (Opt_WarnUnrecognisedPragmas),
@@ -284,16 +283,26 @@ getIdeas nfp = do
284283
Just <$> liftIO (parseModuleEx flags' fp contents')
285284

286285
setExtensions flags = do
287-
hlintExts <- getExtensions flags nfp
286+
hlintExts <- getExtensions nfp
288287
debugm $ "hlint:getIdeas:setExtensions:" ++ show hlintExts
289288
return $ flags { enabledExtensions = hlintExts }
290289

291-
getExtensions :: ParseFlags -> NormalizedFilePath -> Action [Extension]
292-
getExtensions pflags nfp = do
290+
-- Gets extensions from ModSummary dynflags for the file.
291+
-- Previously this would concatenate extensions from both hlint's parsedFlags
292+
-- and the ModSummary dynflags. However using the parsedFlags extensions
293+
-- can sometimes interfere with the hlint parsing of the file.
294+
-- See https://github.com/haskell/haskell-language-server/issues/1279
295+
--
296+
-- Note: this is used when HLINT_ON_GHC_LIB is not defined. We seem to need
297+
-- these extensions to construct dynflags to parse the file again. Therefore
298+
-- using hlint default extensions doesn't seem to be a problem when
299+
-- HLINT_ON_GHC_LIB is not defined because we don't parse the file again.
300+
getExtensions :: NormalizedFilePath -> Action [Extension]
301+
getExtensions nfp = do
293302
dflags <- getFlags
294303
let hscExts = EnumSet.toList (extensionFlags dflags)
295304
let hscExts' = mapMaybe (GhclibParserEx.readExtension . show) hscExts
296-
let hlintExts = nub $ enabledExtensions pflags ++ hscExts'
305+
let hlintExts = hscExts'
297306
return hlintExts
298307
where getFlags :: Action DynFlags
299308
getFlags = do
@@ -538,8 +547,7 @@ applyHint ide nfp mhint =
538547
liftIO $ withSystemTempFile (takeFileName fp) $ \temp h -> do
539548
hClose h
540549
writeFileUTF8NoNewLineTranslation temp oldContent
541-
(pflags, _, _) <- runAction' $ useNoFile_ GetHlintSettings
542-
exts <- runAction' $ getExtensions pflags nfp
550+
exts <- runAction' $ getExtensions nfp
543551
-- We have to reparse extensions to remove the invalid ones
544552
let (enabled, disabled, _invalid) = Refact.parseExtensions $ map show exts
545553
let refactExts = map show $ enabled ++ disabled

plugins/hls-hlint-plugin/test/Main.hs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ suggestionsTests =
134134
changeDoc doc [change']
135135
testHlintDiagnostics doc
136136

137-
, knownBrokenForHlintOnGhcLib "hlint doesn't take in account cpp flag as ghc -D argument" $
138-
testCase "[#554] hlint diagnostics works with CPP via ghc -XCPP argument" $ runHlintSession "cpp" $ do
137+
, testCase "[#554] hlint diagnostics works with CPP via ghc -XCPP argument" $ runHlintSession "cpp" $ do
139138
doc <- openDoc "CppCond.hs" "haskell"
140139
testHlintDiagnostics doc
141140

@@ -212,8 +211,7 @@ suggestionsTests =
212211
length diags @?= 1
213212
unusedExt ^. L.code @?= Just (InR "refact:Unused LANGUAGE pragma")
214213

215-
, knownBrokenForHlintOnGhcLib "[#1279] hlint uses a fixed set of extensions" $
216-
testCase "hlint should not activate extensions like PatternSynonyms" $ runHlintSession "" $ do
214+
, testCase "[#1279] hlint should not activate extensions like PatternSynonyms" $ runHlintSession "" $ do
217215
doc <- openDoc "PatternKeyword.hs" "haskell"
218216

219217
waitForAllProgressDone

0 commit comments

Comments
 (0)