Skip to content

Commit 8e7855f

Browse files
committed
Fix code actions which remove constraints
1 parent 0e9dca4 commit 8e7855f

File tree

2 files changed

+50
-38
lines changed

2 files changed

+50
-38
lines changed

ghcide/src/Development/IDE/Plugin/CodeAction.hs

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ import Outputable (Outputable,
7272
showSDocUnsafe)
7373
import RdrName (GlobalRdrElt (..),
7474
lookupGlobalRdrEnv)
75-
import Safe (atMay)
7675
import SrcLoc (realSrcSpanEnd,
7776
realSrcSpanStart)
7877
import TcRnTypes (ImportAvails (..),
@@ -162,6 +161,32 @@ findSigOfDecl pred decls =
162161
any (pred . unLoc) idsSig
163162
]
164163

164+
findSigOfDecl' :: Range -> [LHsDecl p] -> Either String (Sig p)
165+
findSigOfDecl' range decls = do
166+
dec <- findDeclContainingLocE (_start range) decls
167+
case dec of
168+
L _ (SigD _ sig@TypeSig ) -> Right sig
169+
L _ (ValD _ (bind :: HsBind p)) -> findSigOfBind range bind
170+
_ -> Left "Other"
171+
172+
findSigOfBind :: Range -> HsBind p -> Either String (Sig p)
173+
findSigOfBind range bind =
174+
case bind of
175+
FunBind {} -> findSigOfLMatch (unLoc $ mg_alts (fun_matches bind))
176+
_ -> Left "Other findSigOfBind"
177+
where
178+
findSigOfLMatch :: [LMatch p (LHsExpr idR)] -> Either String (Sig p)
179+
findSigOfLMatch ls = do
180+
match <- findDeclContainingLocE (_start range) ls
181+
case unLoc (grhssLocalBinds (m_grhss (unLoc match))) of
182+
HsValBinds _ (ValBinds _ _ lsigs) ->
183+
unLoc <$> findDeclContainingLocE (_start range) lsigs
184+
_ -> Left "Other findSigOfLMatch"
185+
186+
findDeclContainingLocE :: Position -> [Located a] -> Either String (Located a)
187+
findDeclContainingLocE loc ls =
188+
maybe (Left "findDeclContainingLoc") Right $ findDeclContainingLoc loc ls
189+
165190
findInstanceHead :: (Outputable (HsType p)) => DynFlags -> String -> [LHsDecl p] -> Maybe (LHsType p)
166191
findInstanceHead df instanceHead decls =
167192
listToMaybe
@@ -173,6 +198,7 @@ findInstanceHead df instanceHead decls =
173198
findDeclContainingLoc :: Position -> [Located a] -> Maybe (Located a)
174199
findDeclContainingLoc loc = find (\(L l _) -> loc `isInsideSrcSpan` l)
175200

201+
176202
-- Single:
177203
-- This binding for ‘mod’ shadows the existing binding
178204
-- imported from ‘Prelude’ at haskell-language-server/ghcide/src/Development/IDE/Plugin/CodeAction.hs:10:8-40
@@ -1020,10 +1046,6 @@ suggestImplicitParameter (L _ HsModule {hsmodDecls}) Diagnostic {_message, _rang
10201046
findTypeSignatureName :: T.Text -> Maybe T.Text
10211047
findTypeSignatureName t = matchRegexUnifySpaces t "([^ ]+) :: " <&> head
10221048

1023-
findTypeSignatureLine :: T.Text -> T.Text -> Int
1024-
findTypeSignatureLine contents typeSignatureName =
1025-
T.splitOn (typeSignatureName <> " :: ") contents & head & T.lines & length
1026-
10271049
-- | Suggests a constraint for a type signature with any number of existing constraints.
10281050
suggestFunctionConstraint :: DynFlags -> ParsedSource -> Diagnostic -> T.Text -> [(T.Text, Rewrite)]
10291051

@@ -1062,31 +1084,26 @@ suggestFunctionConstraint df (L _ HsModule {hsmodDecls}) Diagnostic {..} missing
10621084
<> "` to the context of the type signature for `" <> typeSignatureName <> "`"
10631085

10641086
-- | Suggests the removal of a redundant constraint for a type signature.
1065-
removeRedundantConstraints :: Maybe T.Text -> Diagnostic -> [(T.Text, TextEdit)]
1066-
removeRedundantConstraints mContents Diagnostic{..}
1087+
removeRedundantConstraints :: DynFlags -> ParsedSource -> Diagnostic -> [(T.Text, Rewrite)]
1088+
removeRedundantConstraints df (L _ HsModule {hsmodDecls}) Diagnostic{..}
10671089
-- • Redundant constraint: Eq a
10681090
-- • In the type signature for:
10691091
-- foo :: forall a. Eq a => a -> a
10701092
-- • Redundant constraints: (Monoid a, Show a)
10711093
-- • In the type signature for:
10721094
-- foo :: forall a. (Num a, Monoid a, Eq a, Show a) => a -> Bool
1073-
| Just contents <- mContents
10741095
-- Account for both "Redundant constraint" and "Redundant constraints".
1075-
, True <- "Redundant constraint" `T.isInfixOf` _message
1096+
| "Redundant constraint" `T.isInfixOf` _message
10761097
, Just typeSignatureName <- findTypeSignatureName _message
1098+
, Right (TypeSig _ _ HsWC{hswc_body = HsIB {hsib_body = sig}})
1099+
<- findSigOfDecl' _range hsmodDecls
10771100
, Just redundantConstraintList <- findRedundantConstraints _message
1078-
, Just constraints <- findConstraints contents typeSignatureName
1079-
= let constraintList = parseConstraints constraints
1080-
newConstraints = buildNewConstraints constraintList redundantConstraintList
1081-
typeSignatureLine = findTypeSignatureLine contents typeSignatureName
1082-
typeSignatureFirstChar = T.length $ typeSignatureName <> " :: "
1083-
startOfConstraint = Position typeSignatureLine typeSignatureFirstChar
1084-
endOfConstraint = Position typeSignatureLine $
1085-
typeSignatureFirstChar + T.length (constraints <> " => ")
1086-
range = Range startOfConstraint endOfConstraint
1087-
in [(actionTitle redundantConstraintList typeSignatureName, TextEdit range newConstraints)]
1101+
, rewrite <- removeConstraint (pred df redundantConstraintList) sig
1102+
= [(actionTitle redundantConstraintList typeSignatureName, rewrite)]
10881103
| otherwise = []
10891104
where
1105+
pred df list a = showSDoc df (ppr a) `elem` (T.unpack <$> list)
1106+
10901107
parseConstraints :: T.Text -> [T.Text]
10911108
parseConstraints t = t
10921109
& (T.strip >>> stripConstraintsParens >>> T.splitOn ",")
@@ -1106,32 +1123,13 @@ removeRedundantConstraints mContents Diagnostic{..}
11061123
& (`matchRegexUnifySpaces` "Redundant constraints?: (.+)")
11071124
<&> (head >>> parseConstraints)
11081125

1109-
-- If the type signature is not formatted as expected (arbitrary number of spaces,
1110-
-- line feeds...), just fail.
1111-
findConstraints :: T.Text -> T.Text -> Maybe T.Text
1112-
findConstraints contents typeSignatureName = do
1113-
constraints <- contents
1114-
& T.splitOn (typeSignatureName <> " :: ")
1115-
& (`atMay` 1)
1116-
>>= (T.splitOn " => " >>> (`atMay` 0))
1117-
guard $ not $ "\n" `T.isInfixOf` constraints || T.strip constraints /= constraints
1118-
return constraints
1119-
11201126
formatConstraints :: [T.Text] -> T.Text
11211127
formatConstraints [] = ""
11221128
formatConstraints [constraint] = constraint
11231129
formatConstraints constraintList = constraintList
11241130
& T.intercalate ", "
11251131
& \cs -> "(" <> cs <> ")"
11261132

1127-
formatConstraintsWithArrow :: [T.Text] -> T.Text
1128-
formatConstraintsWithArrow [] = ""
1129-
formatConstraintsWithArrow cs = cs & formatConstraints & (<> " => ")
1130-
1131-
buildNewConstraints :: [T.Text] -> [T.Text] -> T.Text
1132-
buildNewConstraints constraintList redundantConstraintList =
1133-
formatConstraintsWithArrow $ constraintList \\ redundantConstraintList
1134-
11351133
actionTitle :: [T.Text] -> T.Text -> T.Text
11361134
actionTitle constraintList typeSignatureName =
11371135
"Remove redundant constraint" <> (if length constraintList == 1 then "" else "s") <> " `"

ghcide/src/Development/IDE/Plugin/CodeAction/ExactPrint.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Development.IDE.Plugin.CodeAction.ExactPrint (
1111

1212
-- * Utilities
1313
appendConstraint,
14+
removeConstraint,
1415
extendImport,
1516
hideSymbol,
1617
liftParseAST,
@@ -118,6 +119,19 @@ fixParens openDP closeDP ctxt@(L _ elems) = do
118119
dropHsParTy (L _ (HsParTy _ ty)) = ty
119120
dropHsParTy other = other
120121

122+
removeConstraint ::
123+
-- | Predicate: Which contect to drop.
124+
(LHsType GhcPs -> Bool) ->
125+
LHsType GhcPs ->
126+
Rewrite
127+
removeConstraint pred = go
128+
where
129+
go (L l it@HsQualTy{hst_ctxt = L l' ctxt}) = Rewrite l $ \_ -> do
130+
return $ L l $ it{hst_ctxt = L l' $ filter (not . pred) ctxt}
131+
go (L _ (HsParTy _ ty)) = go ty
132+
go (L _ HsForAllTy{hst_body}) = go hst_body
133+
go (L l other) = Rewrite l $ \_ -> return $ L l other
134+
121135
-- | Append a constraint at the end of a type context.
122136
-- If no context is present, a new one will be created.
123137
appendConstraint ::

0 commit comments

Comments
 (0)