@@ -4,17 +4,18 @@ module Main
4
4
) where
5
5
6
6
import Control.Lens ((^.) )
7
- import Data.Aeson (toJSON , Value (.. ), object , (.=) )
7
+ import Data.Aeson (Value (.. ), object , toJSON , (.=) )
8
8
import Data.List (find )
9
9
import qualified Data.Map as Map
10
10
import Data.Maybe (fromJust , isJust )
11
11
import qualified Data.Text as T
12
+ import Ide.Plugin.Config (Config (.. ), PluginConfig (.. ),
13
+ hlintOn )
14
+ import qualified Ide.Plugin.Config as Plugin
12
15
import qualified Ide.Plugin.Hlint as HLint
13
- import Ide.Plugin.Config (hlintOn , Config (.. ), PluginConfig (.. ))
14
16
import qualified Language.LSP.Types.Lens as L
15
17
import System.FilePath ((</>) )
16
18
import Test.Hls
17
- import qualified Ide.Plugin.Config as Plugin
18
19
19
20
main :: IO ()
20
21
main = defaultTestRunner tests
@@ -32,7 +33,7 @@ suggestionsTests :: TestTree
32
33
suggestionsTests =
33
34
testGroup " hlint suggestions" [
34
35
testCase " provides 3.8 code actions including apply all" $ runHlintSession " " $ do
35
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
36
+ doc <- openDoc " Base .hs" " haskell"
36
37
diags@ (reduceDiag: _) <- waitForDiagnosticsFromSource doc " hlint"
37
38
38
39
liftIO $ do
@@ -58,7 +59,7 @@ suggestionsTests =
58
59
liftIO $ contents @?= " main = undefined\n foo x = x\n "
59
60
60
61
, testCase " falls back to pre 3.8 code actions" $ runSessionWithServer' [hlintPlugin] def def noLiteralCaps " test/testdata" $ do
61
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
62
+ doc <- openDoc " Base .hs" " haskell"
62
63
63
64
_ <- waitForDiagnosticsFromSource doc " hlint"
64
65
@@ -71,7 +72,7 @@ suggestionsTests =
71
72
liftIO $ contents @?= " main = undefined\n foo = id\n "
72
73
73
74
, testCase " changing document contents updates hlint diagnostics" $ runHlintSession " " $ do
74
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
75
+ doc <- openDoc " Base .hs" " haskell"
75
76
testHlintDiagnostics doc
76
77
77
78
let change = TextDocumentContentChangeEvent
@@ -86,60 +87,63 @@ suggestionsTests =
86
87
changeDoc doc [change']
87
88
testHlintDiagnostics doc
88
89
89
- , knownBrokenForGhcVersions [ GHC88 , GHC86 ] " hlint doesn't take in account cpp flag as ghc -D argument" $
90
- testCase " hlint diagnostics works with CPP via ghc -XCPP argument (#554) " $ runHlintSession " cpp" $ do
91
- doc <- openDoc " ApplyRefact3 .hs" " haskell"
90
+ , knownBrokenForHlintOnGhcLib " hlint doesn't take in account cpp flag as ghc -D argument" $
91
+ testCase " [#554] hlint diagnostics works with CPP via ghc -XCPP argument" $ runHlintSession " cpp" $ do
92
+ doc <- openDoc " CppCond .hs" " haskell"
92
93
testHlintDiagnostics doc
93
94
94
- , knownBrokenForGhcVersions [ GHC88 , GHC86 ] " hlint doesn't take in account cpp flag as ghc -D argument" $
95
- testCase " hlint diagnostics works with CPP via language pragma (#554) " $ runHlintSession " " $ do
96
- doc <- openDoc " ApplyRefact3 .hs" " haskell"
95
+ , knownBrokenForHlintOnGhcLib " hlint doesn't take in account cpp flag as ghc -D argument" $
96
+ testCase " [#554] hlint diagnostics works with CPP via language pragma" $ runHlintSession " " $ do
97
+ doc <- openDoc " CppCond .hs" " haskell"
97
98
testHlintDiagnostics doc
98
99
99
- , testCase " hlint diagnostics works with CPP via -XCPP argument and flag via #include header (#554) " $ runHlintSession " cpp" $ do
100
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
100
+ , testCase " [#554] hlint diagnostics works with CPP via -XCPP argument and flag via #include header" $ runHlintSession " cpp" $ do
101
+ doc <- openDoc " CppHeader .hs" " haskell"
101
102
testHlintDiagnostics doc
102
103
103
- , testCase " apply-refact works with -XLambdaCase argument (#590) " $ runHlintSession " lambdacase" $ do
104
- testRefactor " ApplyRefact1 .hs" " Redundant bracket"
104
+ , testCase " [#590] apply-refact works with -XLambdaCase argument" $ runHlintSession " lambdacase" $ do
105
+ testRefactor " LambdaCase .hs" " Redundant bracket"
105
106
expectedLambdaCase
106
107
107
- , testCase " apply-refact works with -XTypeApplications argument (#1242) " $ runHlintSession " typeapps" $ do
108
- testRefactor " ApplyRefact1 .hs" " Redundant bracket"
108
+ , testCase " [#1242] apply-refact works with -XTypeApplications argument" $ runHlintSession " typeapps" $ do
109
+ testRefactor " TypeApplication .hs" " Redundant bracket"
109
110
expectedTypeApp
110
111
111
112
, testCase " apply hints works with LambdaCase via language pragma" $ runHlintSession " " $ do
112
- testRefactor " ApplyRefact1 .hs" " Redundant bracket"
113
+ testRefactor " LambdaCase .hs" " Redundant bracket"
113
114
(" {-# LANGUAGE LambdaCase #-}" : expectedLambdaCase)
114
115
115
116
, expectFailBecause " apply-refact doesn't work with cpp" $
116
117
testCase " apply hints works with CPP via -XCPP argument" $ runHlintSession " cpp" $ do
117
- testRefactor " ApplyRefact3 .hs" " Redundant bracket"
118
+ testRefactor " CppCond .hs" " Redundant bracket"
118
119
expectedCPP
119
120
120
121
, expectFailBecause " apply-refact doesn't work with cpp" $
121
122
testCase " apply hints works with CPP via language pragma" $ runHlintSession " " $ do
122
- testRefactor " ApplyRefact3 .hs" " Redundant bracket"
123
+ testRefactor " CppCond .hs" " Redundant bracket"
123
124
(" {-# LANGUAGE CPP #-}" : expectedCPP)
124
125
125
126
, testCase " hlint diagnostics ignore hints honouring .hlint.yaml" $ runHlintSession " ignore" $ do
126
- doc <- openDoc " ApplyRefact .hs" " haskell"
127
+ doc <- openDoc " CamelCase .hs" " haskell"
127
128
expectNoMoreDiagnostics 3 doc " hlint"
128
129
129
130
, testCase " hlint diagnostics ignore hints honouring ANN annotations" $ runHlintSession " " $ do
130
- doc <- openDoc " ApplyRefact4 .hs" " haskell"
131
+ doc <- openDoc " IgnoreAnn .hs" " haskell"
131
132
expectNoMoreDiagnostics 3 doc " hlint"
132
133
133
- , knownBrokenForGhcVersions [ GHC810 , GHC90 ] " hlint plugin doesn't honour HLINT annotations (#838) " $
134
+ , knownBrokenForHlintOnRawGhc " [#838] hlint plugin doesn't honour HLINT annotations" $
134
135
testCase " hlint diagnostics ignore hints honouring HLINT annotations" $ runHlintSession " " $ do
135
- doc <- openDoc " ApplyRefact5 .hs" " haskell"
136
+ doc <- openDoc " IgnoreAnnHlint .hs" " haskell"
136
137
expectNoMoreDiagnostics 3 doc " hlint"
137
138
138
139
, testCase " apply-refact preserve regular comments" $ runHlintSession " " $ do
139
- testRefactor " ApplyRefact6.hs" " Redundant bracket" expectedComments
140
+ testRefactor " Comments.hs" " Redundant bracket" expectedComments
141
+
142
+ , testCase " [#2290] apply all hints works with a trailing comment" $ runHlintSession " " $ do
143
+ testRefactor " TwoHintsAndComment.hs" " Apply all hints" expectedComments2
140
144
141
145
, testCase " applyAll is shown only when there is at least one diagnostic in range" $ runHlintSession " " $ do
142
- doc <- openDoc " ApplyRefact8 .hs" " haskell"
146
+ doc <- openDoc " TwoHints .hs" " haskell"
143
147
_ <- waitForDiagnosticsFromSource doc " hlint"
144
148
145
149
firstLine <- map fromAction <$> getCodeActions doc (mkRange 0 0 0 0 )
@@ -153,6 +157,30 @@ suggestionsTests =
153
157
liftIO $ hasApplyAll secondLine @? " Missing apply all code action"
154
158
liftIO $ not (hasApplyAll thirdLine) @? " Unexpected apply all code action"
155
159
liftIO $ hasApplyAll multiLine @? " Missing apply all code action"
160
+
161
+ , knownBrokenForHlintOnRawGhc " [#2042] maybe hlint is ignoring pragmas" $
162
+ testCase " hlint should warn about unused extensions" $ runHlintSession " unusedext" $ do
163
+ doc <- openDoc " UnusedExtension.hs" " haskell"
164
+ diags@ (unusedExt: _) <- waitForDiagnosticsFromSource doc " hlint"
165
+
166
+ liftIO $ do
167
+ length diags @?= 1
168
+ unusedExt ^. L. code @?= Just (InR " refact:Unused LANGUAGE pragma" )
169
+
170
+ , knownBrokenForHlintOnGhcLib " [#1279] hlint uses a fixed set of extensions" $
171
+ testCase " hlint should not activate extensions like PatternSynonyms" $ runHlintSession " " $ do
172
+ doc <- openDoc " PatternKeyword.hs" " haskell"
173
+
174
+ waitForAllProgressDone
175
+ -- hlint will report a parse error if PatternSynonyms is enabled
176
+ expectNoMoreDiagnostics 3 doc " hlint"
177
+ , knownBrokenForHlintOnRawGhc " [#2280] maybe hlint is ignoring pragmas" $
178
+ testCase " hlint should not warn about redundant irrefutable pattern with LANGUAGE Strict" $ runHlintSession " " $ do
179
+ doc <- openDoc " StrictData.hs" " haskell"
180
+
181
+ waitForAllProgressDone
182
+
183
+ expectNoMoreDiagnostics 3 doc " hlint"
156
184
]
157
185
where
158
186
testRefactor file caTitle expected = do
@@ -168,26 +196,29 @@ suggestionsTests =
168
196
contents <- skipManyTill anyMessage $ getDocumentEdit doc
169
197
liftIO $ contents @?= T. unlines expected
170
198
171
- expectedLambdaCase = [ " module ApplyRefact1 where" , " "
199
+ expectedLambdaCase = [ " module LambdaCase where" , " "
172
200
, " f = \\ case \" true\" -> True"
173
201
, " _ -> False"
174
202
]
175
- expectedCPP = [ " module ApplyRefact3 where" , " "
203
+ expectedCPP = [ " module CppCond where" , " "
176
204
, " #ifdef FLAG"
177
205
, " f = 1"
178
206
, " #else"
179
207
, " g = 2"
180
208
, " #endif" , " "
181
209
]
182
210
expectedComments = [ " -- comment before header"
183
- , " module ApplyRefact6 where" , " "
211
+ , " module Comments where" , " "
184
212
, " {-# standalone annotation #-}" , " "
185
213
, " -- standalone comment" , " "
186
214
, " -- | haddock comment"
187
215
, " f = {- inline comment -}{- inline comment inside refactored code -} 1 -- ending comment" , " "
188
216
, " -- final comment"
189
217
]
190
- expectedTypeApp = [ " module ApplyRefact1 where" , " "
218
+ expectedComments2 = [ " module TwoHintsAndComment where"
219
+ , " biggest = foldr1 max -- the line above will show two hlint hints, \" eta reduce\" and \" use maximum\" "
220
+ ]
221
+ expectedTypeApp = [ " module TypeApplication where" , " "
191
222
, " a = id @Int 1"
192
223
]
193
224
@@ -198,7 +229,7 @@ configTests = testGroup "hlint plugin config" [
198
229
let config = def { hlintOn = True }
199
230
sendConfigurationChanged (toJSON config)
200
231
201
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
232
+ doc <- openDoc " Base .hs" " haskell"
202
233
testHlintDiagnostics doc
203
234
204
235
let config' = def { hlintOn = False }
@@ -212,7 +243,7 @@ configTests = testGroup "hlint plugin config" [
212
243
let config = def { hlintOn = True }
213
244
sendConfigurationChanged (toJSON config)
214
245
215
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
246
+ doc <- openDoc " Base .hs" " haskell"
216
247
testHlintDiagnostics doc
217
248
218
249
let config' = pluginGlobalOn config " hlint" False
@@ -226,7 +257,7 @@ configTests = testGroup "hlint plugin config" [
226
257
let config = def { hlintOn = True }
227
258
sendConfigurationChanged (toJSON config)
228
259
229
- doc <- openDoc " ApplyRefact2 .hs" " haskell"
260
+ doc <- openDoc " Base .hs" " haskell"
230
261
testHlintDiagnostics doc
231
262
232
263
let config' = hlintConfigWithFlags [" --ignore=Redundant id" , " --hint=test-hlint-config.yaml" ]
@@ -240,7 +271,7 @@ configTests = testGroup "hlint plugin config" [
240
271
let config = def { hlintOn = True }
241
272
sendConfigurationChanged (toJSON config)
242
273
243
- doc <- openDoc " ApplyRefact7 .hs" " haskell"
274
+ doc <- openDoc " Generalise .hs" " haskell"
244
275
245
276
expectNoMoreDiagnostics 3 doc " hlint"
246
277
@@ -285,3 +316,16 @@ hlintConfigWithFlags flags =
285
316
where
286
317
unObject (Object obj) = obj
287
318
unObject _ = undefined
319
+
320
+ -- We have two main code paths in the plugin depending on how hlint interacts with ghc:
321
+ -- * One when hlint uses ghc-lib (all ghc versions but the last version supported by hlint)
322
+ -- * Another one when hlint uses directly ghc (only one version, which not have to be the last version supported by ghcide)
323
+ -- As we always are using ghc through ghcide the code to get the ghc parsed AST differs
324
+ -- So the issues and bugs usually only affects to one code path or the other.
325
+ -- Although a given hlint version supports one direct ghc, we could use several versions of hlint
326
+ -- each one supporting a different ghc version. It should be a temporary situation though.
327
+ knownBrokenForHlintOnGhcLib :: String -> TestTree -> TestTree
328
+ knownBrokenForHlintOnGhcLib = knownBrokenForGhcVersions [GHC88 , GHC86 ]
329
+
330
+ knownBrokenForHlintOnRawGhc :: String -> TestTree -> TestTree
331
+ knownBrokenForHlintOnRawGhc = knownBrokenForGhcVersions [GHC810 , GHC90 ]
0 commit comments