Skip to content

Commit 132abfa

Browse files
committed
hls-class-plugin: Only create placeholders unimplemented methods
1 parent e64b61e commit 132abfa

File tree

5 files changed

+88
-3
lines changed

5 files changed

+88
-3
lines changed

plugins/hls-class-plugin/src/Ide/Plugin/Class.hs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE DeriveAnyClass #-}
33
{-# LANGUAGE DeriveGeneric #-}
4+
{-# LANGUAGE LambdaCase #-}
45
{-# LANGUAGE OverloadedStrings #-}
56
{-# LANGUAGE RecordWildCards #-}
67
{-# LANGUAGE TypeFamilies #-}
@@ -17,6 +18,7 @@ import Control.Monad.Trans.Class
1718
import Control.Monad.Trans.Maybe
1819
import Data.Aeson
1920
import Data.Char
21+
import Data.Either (rights)
2022
import Data.List
2123
import qualified Data.Map.Strict as Map
2224
import Data.Maybe
@@ -40,7 +42,7 @@ import Language.LSP.Types
4042
import qualified Language.LSP.Types.Lens as J
4143

4244
#if MIN_VERSION_ghc(9,2,0)
43-
import GHC.Hs (AnnsModule(AnnsModule))
45+
import GHC.Hs (AnnsModule (AnnsModule))
4446
import GHC.Parser.Annotation
4547
#endif
4648

@@ -192,7 +194,8 @@ codeAction state plId (CodeActionParams _ _ docId _ context) = liftIO $ fmap (fr
192194
mkActions docPath diag = do
193195
ident <- findClassIdentifier docPath range
194196
cls <- findClassFromIdentifier docPath ident
195-
lift . traverse mkAction . minDefToMethodGroups . classMinimalDef $ cls
197+
implemented <- findImplementedMethods docPath range
198+
lift . traverse (mkAction . (\\ implemented)) . minDefToMethodGroups . classMinimalDef $ cls
196199
where
197200
range = diag ^. J.range
198201

@@ -212,6 +215,7 @@ codeAction state plId (CodeActionParams _ _ docId _ context) = liftIO $ fmap (fr
212215
= InR
213216
$ CodeAction title (Just CodeActionQuickFix) (Just (List [])) Nothing Nothing Nothing (Just cmd) Nothing
214217

218+
findClassIdentifier :: NormalizedFilePath -> Range -> MaybeT IO (Either ModuleName Name)
215219
findClassIdentifier docPath range = do
216220
(hieAstResult, pmap) <- MaybeT . runAction "classplugin" state $ useWithStale GetHieAst docPath
217221
case hieAstResult of
@@ -234,18 +238,38 @@ codeAction state plId (CodeActionParams _ _ docId _ context) = liftIO $ fmap (fr
234238
_ -> panic "Ide.Plugin.Class.findClassFromIdentifier"
235239
findClassFromIdentifier _ (Left _) = panic "Ide.Plugin.Class.findClassIdentifier"
236240

241+
findImplementedMethods :: NormalizedFilePath -> Range -> MaybeT IO [T.Text]
242+
findImplementedMethods docPath range = do
243+
(HAR {hieAst = hf}, pmap) <- MaybeT . runAction "classplugin" state $ useWithStale GetHieAst docPath
244+
pure
245+
$ concat
246+
$ pointCommand hf (fromJust (fromCurrentRange pmap range) ^. J.start & J.character -~ 1)
247+
$ map (T.pack . getOccString) . rights . findInstanceValBindIdentifiers
248+
249+
findInstanceValBindIdentifiers :: HieAST a -> [Identifier]
250+
findInstanceValBindIdentifiers ast
251+
| Map.null (getNodeIds ast) = concatMap findInstanceValBindIdentifiers (nodeChildren ast)
252+
| otherwise = Map.keys
253+
. Map.filter (not . Set.null)
254+
. Map.map (Set.filter isInstanceValBind . identInfo)
255+
$ getNodeIds ast
256+
237257
ghostSpan :: RealSrcSpan
238258
ghostSpan = realSrcLocSpan $ mkRealSrcLoc (fsLit "<haskell-language-sever>") 1 1
239259

240260
containRange :: Range -> SrcSpan -> Bool
241261
containRange range x = isInsideSrcSpan (range ^. J.start) x || isInsideSrcSpan (range ^. J.end) x
242262

243263
isClassNodeIdentifier :: IdentifierDetails a -> Bool
244-
isClassNodeIdentifier ident = (isNothing . identType) ident && Use `Set.member` (identInfo ident)
264+
isClassNodeIdentifier ident = (isNothing . identType) ident && Use `Set.member` identInfo ident
245265

246266
isClassMethodWarning :: T.Text -> Bool
247267
isClassMethodWarning = T.isPrefixOf "• No explicit implementation for"
248268

269+
isInstanceValBind :: ContextInfo -> Bool
270+
isInstanceValBind (ValBind InstanceBind _ _) = True
271+
isInstanceValBind _ = False
272+
249273
minDefToMethodGroups :: BooleanFormula Name -> [[T.Text]]
250274
minDefToMethodGroups = go
251275
where

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ tests = testGroup
4848
executeCodeAction _fAction
4949
, goldenWithClass "Creates a placeholder for '==' with extra lines" "T5" "" $ \(eqAction:_) -> do
5050
executeCodeAction eqAction
51+
, goldenWithClass "Creates a placeholder for only the unimplemented methods of multiple methods" "T6" "1" $ \(gAction:_) -> do
52+
executeCodeAction gAction
53+
, goldenWithClass "Creates a placeholder for other two multiple methods" "T6" "2" $ \(_:ghAction:_) -> do
54+
executeCodeAction ghAction
5155
]
5256

5357
_CACodeAction :: Prism' (Command |? CodeAction) CodeAction
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module T6 where
2+
3+
data X = X | Y
4+
5+
class Test a where
6+
f :: a -> a
7+
f = h
8+
9+
g :: a
10+
11+
h :: a -> a
12+
h = f
13+
14+
{-# MINIMAL f, g | g, h #-}
15+
16+
instance Test X where
17+
f X = X
18+
f Y = Y
19+
g = _
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module T6 where
2+
3+
data X = X | Y
4+
5+
class Test a where
6+
f :: a -> a
7+
f = h
8+
9+
g :: a
10+
11+
h :: a -> a
12+
h = f
13+
14+
{-# MINIMAL f, g | g, h #-}
15+
16+
instance Test X where
17+
f X = X
18+
f Y = Y
19+
g = _
20+
h = _
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module T6 where
2+
3+
data X = X | Y
4+
5+
class Test a where
6+
f :: a -> a
7+
f = h
8+
9+
g :: a
10+
11+
h :: a -> a
12+
h = f
13+
14+
{-# MINIMAL f, g | g, h #-}
15+
16+
instance Test X where
17+
f X = X
18+
f Y = Y

0 commit comments

Comments
 (0)