Skip to content

Commit 96d2c04

Browse files
authored
Fix #2612 - hlint plugin - Apply fixities to parsed source before sending to apply-refact (#2624)
* fix #2612. apply fixities to parsed source before sent to apply-refact * fix tests * dont hardcode getApplyHintText * try and fix pedantic warning * fix cpp * fix cpp 2 * actually fix pendantic warnings because import is not used when hlint_ghc_lib is on
1 parent ffd0f34 commit 96d2c04

File tree

4 files changed

+54
-13
lines changed

4 files changed

+54
-13
lines changed

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,16 @@ import Development.IDE.Core.Rules (defineNoFil
5151
getParsedModuleWithComments,
5252
usePropertyAction)
5353
import Development.IDE.Core.Shake (getDiagnostics)
54-
import Refact.Apply
54+
import qualified Refact.Apply as Refact
5555

5656
#ifdef HLINT_ON_GHC_LIB
5757
import Data.List (nub)
5858
import Development.IDE.GHC.Compat (BufSpan,
5959
DynFlags,
60+
WarningFlag (Opt_WarnUnrecognisedPragmas),
6061
extensionFlags,
6162
ms_hspp_opts,
6263
topDir,
63-
WarningFlag(Opt_WarnUnrecognisedPragmas),
6464
wopt)
6565
import qualified Development.IDE.GHC.Compat.Util as EnumSet
6666
import "ghc-lib" GHC hiding
@@ -83,11 +83,12 @@ import System.IO.Temp
8383
#else
8484
import Development.IDE.GHC.Compat hiding
8585
(setEnv)
86+
import GHC.Generics (Associativity (LeftAssociative, NotAssociative, RightAssociative))
8687
import Language.Haskell.GHC.ExactPrint.Delta (deltaOptions)
8788
import Language.Haskell.GHC.ExactPrint.Parsers (postParseTransform)
8889
import Language.Haskell.GHC.ExactPrint.Types (Rigidity (..))
8990
import Language.Haskell.GhclibParserEx.Fixity as GhclibParserEx (applyFixities)
90-
import GHC.Generics (Associativity (LeftAssociative, NotAssociative, RightAssociative))
91+
import qualified Refact.Fixity as Refact
9192
#endif
9293

9394
import Ide.Logger
@@ -539,9 +540,9 @@ applyHint ide nfp mhint =
539540
(pflags, _, _) <- runAction' $ useNoFile_ GetHlintSettings
540541
exts <- runAction' $ getExtensions pflags nfp
541542
-- We have to reparse extensions to remove the invalid ones
542-
let (enabled, disabled, _invalid) = parseExtensions $ map show exts
543+
let (enabled, disabled, _invalid) = Refact.parseExtensions $ map show exts
543544
let refactExts = map show $ enabled ++ disabled
544-
(Right <$> withRuntimeLibdir (applyRefactorings position commands temp refactExts))
545+
(Right <$> withRuntimeLibdir (Refact.applyRefactorings position commands temp refactExts))
545546
`catches` errorHandlers
546547
#else
547548
mbParsedModule <- liftIO $ runAction' $ getParsedModuleWithComments nfp
@@ -554,8 +555,9 @@ applyHint ide nfp mhint =
554555
-- apply-refact uses RigidLayout
555556
let rigidLayout = deltaOptions RigidLayout
556557
(anns', modu') <-
557-
ExceptT $ return $ postParseTransform (Right (anns, [], dflags, modu)) rigidLayout
558-
liftIO $ (Right <$> withRuntimeLibdir (applyRefactorings' position commands anns' modu'))
558+
ExceptT $ mapM (uncurry Refact.applyFixities)
559+
$ postParseTransform (Right (anns, [], dflags, modu)) rigidLayout
560+
liftIO $ (Right <$> withRuntimeLibdir (Refact.applyRefactorings' position commands anns' modu'))
559561
`catches` errorHandlers
560562
#endif
561563
case res of

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ module Main
77
) where
88

99
import Control.Lens ((^.))
10+
import Control.Monad (when)
1011
import Data.Aeson (Value (..), object, toJSON, (.=))
12+
import Data.Functor (void)
1113
import Data.List (find)
1214
import qualified Data.Map as Map
1315
import Data.Maybe (fromJust, isJust)
@@ -30,26 +32,40 @@ tests = testGroup "hlint" [
3032
suggestionsTests
3133
, configTests
3234
, ignoreHintTests
35+
, applyHintTests
3336
]
3437

3538
getIgnoreHintText :: T.Text -> T.Text
3639
getIgnoreHintText name = "Ignore hint \"" <> name <> "\" in this module"
3740

41+
getApplyHintText :: T.Text -> T.Text
42+
getApplyHintText name = "Apply hint \"" <> name <> "\""
43+
3844
ignoreHintTests :: TestTree
3945
ignoreHintTests = testGroup "hlint ignore hint tests"
4046
[
41-
ignoreGoldenTest
47+
ignoreHintGoldenTest
4248
"Ignore hint in this module inserts -Wno-unrecognised-pragmas and hlint ignore pragma if warn unrecognized pragmas is off"
4349
"UnrecognizedPragmasOff"
4450
(Point 3 8)
4551
"Eta reduce"
46-
, ignoreGoldenTest
52+
, ignoreHintGoldenTest
4753
"Ignore hint in this module inserts only hlint ignore pragma if warn unrecognized pragmas is on"
4854
"UnrecognizedPragmasOn"
4955
(Point 3 9)
5056
"Eta reduce"
5157
]
5258

59+
applyHintTests :: TestTree
60+
applyHintTests = testGroup "hlint apply hint tests"
61+
[
62+
applyHintGoldenTest
63+
"[#2612] Apply hint works when operator fixities go right-to-left"
64+
"RightToLeftFixities"
65+
(Point 6 13)
66+
"Avoid reverse"
67+
]
68+
5369
suggestionsTests :: TestTree
5470
suggestionsTests =
5571
testGroup "hlint suggestions" [
@@ -378,13 +394,24 @@ makeCodeActionFoundAtString :: Point -> String
378394
makeCodeActionFoundAtString Point {..} =
379395
"CodeAction found at line: " <> show line <> ", column: " <> show column
380396

381-
ignoreGoldenTest :: TestName -> FilePath -> Point -> T.Text -> TestTree
382-
ignoreGoldenTest testCaseName goldenFilename point hintName =
397+
ignoreHintGoldenTest :: TestName -> FilePath -> Point -> T.Text -> TestTree
398+
ignoreHintGoldenTest testCaseName goldenFilename point hintName =
399+
goldenTest testCaseName goldenFilename point (getIgnoreHintText hintName)
400+
401+
applyHintGoldenTest :: TestName -> FilePath -> Point -> T.Text -> TestTree
402+
applyHintGoldenTest testCaseName goldenFilename point hintName = do
403+
goldenTest testCaseName goldenFilename point (getApplyHintText hintName)
404+
405+
goldenTest :: TestName -> FilePath -> Point -> T.Text -> TestTree
406+
goldenTest testCaseName goldenFilename point hintText =
383407
setupGoldenHlintTest testCaseName goldenFilename $ \document -> do
384408
waitForDiagnosticsFromSource document "hlint"
385409
actions <- getCodeActions document $ pointToRange point
386-
case find ((== Just (getIgnoreHintText hintName)) . getCodeActionTitle) actions of
387-
Just (InR codeAction) -> executeCodeAction codeAction
410+
case find ((== Just hintText) . getCodeActionTitle) actions of
411+
Just (InR codeAction) -> do
412+
executeCodeAction codeAction
413+
when (isJust (codeAction ^. L.command)) $
414+
void $ skipManyTill anyMessage $ getDocumentEdit document
388415
_ -> liftIO $ assertFailure $ makeCodeActionNotFoundAtString point
389416

390417
setupGoldenHlintTest :: TestName -> FilePath -> (TextDocumentIdentifier -> Session ()) -> TestTree
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module RightToLeftFixities where
2+
import Data.List (sortOn)
3+
import Control.Arrow ((&&&))
4+
import Data.Ord (Down(Down))
5+
functionB :: [String] -> [(Char,Int)]
6+
functionB = sortOn (Down . snd) . map (head &&& length) . id
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module RightToLeftFixities where
2+
import Data.List (sortOn)
3+
import Control.Arrow ((&&&))
4+
import Data.Ord (Down(Down))
5+
functionB :: [String] -> [(Char,Int)]
6+
functionB = reverse . sortOn snd . map (head &&& length) . id

0 commit comments

Comments
 (0)