Skip to content

Commit e7b8eea

Browse files
committed
hlint plugin version with only diagnostics
1 parent 88f84f4 commit e7b8eea

File tree

2 files changed

+69
-42
lines changed

2 files changed

+69
-42
lines changed

haskell-language-server.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ library hls-ghc-lib
133133
, ghcide
134134
, hashable
135135
, haskell-lsp
136-
, haskell-src-exts
137136
, hlint >= 3.0
137+
, lens
138138
, regex-tdfa
139139
, shake
140140
, text
@@ -146,6 +146,8 @@ library hls-ghc-lib
146146
else
147147
build-depends:
148148
ghc-lib == 8.10.*
149+
cpp-options:
150+
-DGHC_LIB
149151

150152
ghc-options:
151153
-Wall

src/Ide/Plugin/Hlint.hs

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
{-# LANGUAGE ViewPatterns #-}
1+
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE DeriveAnyClass #-}
23
{-# LANGUAGE DeriveGeneric #-}
34
{-# LANGUAGE DuplicateRecordFields #-}
45
{-# LANGUAGE FlexibleContexts #-}
@@ -15,31 +16,21 @@ module Ide.Plugin.Hlint
1516
--, provider
1617
) where
1718

18-
-- import DA.Daml.DocTest
19-
-- import Development.IDE.Core.Service.Daml
20-
-- import qualified DA.Daml.LF.Ast as LF
21-
-- import qualified DA.Daml.LF.ScenarioServiceClient as SS
22-
-- import Control.Exception.Safe
23-
-- import Development.IDE.Core.RuleTypes.Daml
24-
-- import Development.IDE.Core.Rules
25-
-- import Development.IDE.Core.Service.Daml
26-
-- import Development.IDE.Types.Location
27-
-- import qualified DA.Daml.LF.Ast as LF
28-
-- import qualified DA.Daml.Visual as Visual
29-
-- import qualified Data.NameMap as NM
3019
import Control.DeepSeq
3120
import Control.Exception
21+
import Control.Lens ((^.))
3222
import Control.Monad
3323
import Control.Monad.Extra
3424
import Control.Monad.Trans.Maybe
3525
import qualified Data.Aeson as Aeson
36-
import Data.Aeson.Types (toJSON, fromJSON, Value(..), Result(..))
26+
import Data.Aeson.Types (ToJSON(..), FromJSON(..), Value(..), Result(..))
3727
import Data.Binary
3828
import qualified Data.ByteString as BS
3929
import Data.Either.Extra
4030
import Data.Foldable
4131
import Data.Functor
4232
import qualified Data.HashMap.Strict as Map
33+
import qualified Data.HashSet as HashSet
4334
import Data.Hashable
4435
import Data.List
4536
import Data.Map.Strict (Map)
@@ -65,9 +56,10 @@ import Development.Shake
6556
import GHC
6657
import GHC.Generics
6758
import GHC.Generics (Generic)
59+
import SrcLoc
6860
import HscTypes (ModIface, ModSummary)
6961
import Ide.Types
70-
import qualified Language.Haskell.Exts.SrcLoc as HSE
62+
import Ide.Plugin
7163
import Language.Haskell.HLint
7264
import Language.Haskell.HLint as Hlint
7365
import qualified Language.Haskell.LSP.Core as LSP
@@ -82,8 +74,6 @@ import System.FilePath
8274
import System.IO.Error
8375
import Text.Regex.TDFA.Text()
8476

85-
86-
-- import "ghc-lib-parser" Module (UnitId)
8777
-- ---------------------------------------------------------------------
8878

8979
descriptor :: PluginId -> PluginDescriptor
@@ -93,7 +83,7 @@ descriptor plId = (defaultPluginDescriptor plId)
9383
-- [ PluginCommand "applyOne" "Apply a single hint" applyOneCmd
9484
-- , PluginCommand "applyAll" "Apply all hints to the file" applyAllCmd
9585
-- ]
96-
-- , pluginCodeActionProvider = Just codeActionProvider
86+
-- , pluginCodeActionProvider = Just codeActionProvider
9787
}
9888

9989
data GetHlintDiagnostics = GetHlintDiagnostics
@@ -107,37 +97,71 @@ type instance RuleResult GetHlintDiagnostics = ()
10797
rules :: Rules ()
10898
rules = do
10999
define $ \GetHlintDiagnostics file -> do
110-
pm <- use_ GetParsedModule file
111-
let anns = pm_annotations pm
112-
let modu = pm_parsed_source pm
113100
(classify, hint) <- useNoFile_ GetHlintSettings
114-
let ideas = applyHints classify hint [createModuleEx anns modu]
115-
return ([diagnostic file i | i <- ideas, ideaSeverity i /= Ignore], Just ())
101+
eModuleEx <- getModuleEx file
102+
let getIdeas moduleEx = applyHints classify hint [moduleEx]
103+
return $ (diagnostics file (fmap getIdeas eModuleEx), Just ())
104+
105+
hlintDataDir <- liftIO getExecutablePath
106+
107+
getHlintSettingsRule (HlintEnabled hlintDataDir True)
116108

117109
action $ do
118110
files <- getFilesOfInterest
119-
void $ uses GetHlintDiagnostics $ Set.toList files
111+
void $ uses GetHlintDiagnostics $ HashSet.toList files
120112

121113
where
122-
srcSpanToRange :: HSE.SrcSpan -> LSP.Range
123-
srcSpanToRange span = Range {
114+
115+
getModuleEx :: NormalizedFilePath -> Action (Either ParseError ModuleEx)
116+
getModuleEx fp = do
117+
#ifndef GHC_LIB
118+
pm <- use_ GetParsedModule fp
119+
let anns = pm_annotations pm
120+
let modu = pm_parsed_source pm
121+
return $ Right (createModuleEx anns modu)
122+
#else
123+
liftIO $ parseModuleEx defaultParseFlags (fromNormalizedFilePath fp) Nothing
124+
#endif
125+
126+
diagnostics :: NormalizedFilePath -> Either ParseError [Idea] -> [FileDiagnostic]
127+
diagnostics file (Right ideas) =
128+
[(file, ShowDiag, ideaToDiagnostic i) | i <- ideas, ideaSeverity i /= Ignore]
129+
diagnostics file (Left parseErr) =
130+
[(file, ShowDiag, parseErrorToDiagnostic parseErr)]
131+
132+
ideaToDiagnostic :: Idea -> Diagnostic
133+
ideaToDiagnostic idea =
134+
LSP.Diagnostic {
135+
_range = srcSpanToRange $ ideaSpan idea
136+
, _severity = Just LSP.DsInfo
137+
, _code = Just (LSP.StringValue $ T.pack $ ideaHint idea)
138+
, _source = Just "hlint"
139+
, _message = T.pack $ show idea
140+
, _relatedInformation = Nothing
141+
}
142+
143+
parseErrorToDiagnostic :: ParseError -> Diagnostic
144+
parseErrorToDiagnostic (Hlint.ParseError l msg contents) =
145+
LSP.Diagnostic {
146+
_range = srcSpanToRange l
147+
, _severity = Just LSP.DsInfo
148+
, _code = Just (LSP.StringValue "parser")
149+
, _source = Just "hlint"
150+
, _message = T.unlines [T.pack msg,T.pack contents]
151+
, _relatedInformation = Nothing
152+
}
153+
-- This one is defined in Development.IDE.GHC.Error but here
154+
-- the types could come from ghc-lib or ghc
155+
srcSpanToRange :: SrcSpan -> LSP.Range
156+
srcSpanToRange (RealSrcSpan span) = Range {
124157
_start = LSP.Position {
125-
_line = HSE.srcSpanStartLine span - 1
126-
, _character = HSE.srcSpanStartColumn span - 1}
158+
_line = srcSpanStartLine span - 1
159+
, _character = srcSpanStartCol span - 1}
127160
, _end = LSP.Position {
128-
_line = HSE.srcSpanEndLine span - 1
129-
, _character = HSE.srcSpanEndColumn span - 1}
161+
_line = srcSpanEndLine span - 1
162+
, _character = srcSpanEndCol span - 1}
130163
}
131-
diagnostic :: NormalizedFilePath -> Idea -> FileDiagnostic
132-
diagnostic file i =
133-
(file, ShowDiag, LSP.Diagnostic {
134-
_range = srcSpanToRange $ ideaSpan i
135-
, _severity = Just LSP.DsInfo
136-
, _code = Nothing
137-
, _source = Just "hlint"
138-
, _message = T.pack $ show i
139-
, _relatedInformation = Nothing
140-
})
164+
srcSpanToRange (UnhelpfulSpan _) = noRange
141165

142166
-- ---------------------------------------------------------------------
143167

@@ -189,7 +213,8 @@ hlintSettings hlintDataDir enableOverrides = do
189213
foldMapM f = foldlM (\acc a -> do w <- f a; return $! mappend acc w) mempty
190214

191215
-- ---------------------------------------------------------------------
192-
-- ---------------------------------------------------------------------
216+
217+
193218
-- ---------------------------------------------------------------------
194219
{-
195220
{-# LANGUAGE CPP #-}

0 commit comments

Comments
 (0)