@@ -64,6 +64,7 @@ import Bag (isEmptyBag)
64
64
import qualified Data.HashSet as Set
65
65
import Control.Concurrent.Extra (threadDelay , readVar )
66
66
import Development.IDE.GHC.Util (printRdrName )
67
+ import Ide.PluginUtils (subRange )
67
68
68
69
plugin :: Plugin c
69
70
plugin = codeActionPluginWithRules rules codeAction <> Plugin mempty setHandlersCodeLens
@@ -107,8 +108,9 @@ codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diag
107
108
[ mkCA title [x] edit
108
109
| x <- xs, (title, tedit) <- suggestAction exportsMap ideOptions parsedModule text x
109
110
, let edit = WorkspaceEdit (Just $ Map. singleton uri $ List tedit) Nothing
110
- ] <> caRemoveRedundantImports parsedModule text diag xs uri
111
-
111
+ ] <> caRemoveInvalidExports parsedModule text diag xs uri
112
+ <> caRemoveRedundantImports parsedModule text diag xs uri
113
+
112
114
actions' =
113
115
[mkCA title [x] edit
114
116
| x <- xs
@@ -243,8 +245,8 @@ suggestRemoveRedundantImport ParsedModule{pm_parsed_source = L _ HsModule{hsmod
243
245
| Just [_, bindings] <- matchRegexUnifySpaces _message " The( qualified)? import of ‘([^’]*)’ from module [^ ]* is redundant"
244
246
, Just (L _ impDecl) <- find (\ (L l _) -> srcSpanToRange l == Just _range ) hsmodImports
245
247
, Just c <- contents
246
- , ranges <- map (rangesForBinding impDecl . T. unpack) (T. splitOn " , " bindings)
247
- , ranges' <- extendAllToIncludeCommaIfPossible (indexedByPosition $ T. unpack c) (concat ranges)
248
+ , ranges <- map (rangesForBindingImport impDecl . T. unpack) (T. splitOn " , " bindings)
249
+ , ranges' <- extendAllToIncludeCommaIfPossible False (indexedByPosition $ T. unpack c) (concat ranges)
248
250
, not (null ranges')
249
251
= [( " Remove " <> bindings <> " from import" , [ TextEdit r " " | r <- ranges' ] )]
250
252
@@ -280,6 +282,69 @@ caRemoveRedundantImports m contents digs ctxDigs uri
280
282
_edit = Just WorkspaceEdit {.. }
281
283
_command = Nothing
282
284
285
+ caRemoveInvalidExports :: Maybe ParsedModule -> Maybe T. Text -> [Diagnostic ] -> [Diagnostic ] -> Uri -> [CAResult ]
286
+ caRemoveInvalidExports m contents digs ctxDigs uri
287
+ | Just pm <- m,
288
+ Just txt <- contents,
289
+ txt' <- indexedByPosition $ T. unpack txt,
290
+ r <- mapMaybe (groupDiag pm) digs,
291
+ r' <- map (\ (t,d,rs) -> (t,d,extend txt' rs)) r,
292
+ caRemoveCtx <- mapMaybe removeSingle r',
293
+ allRanges <- nubOrd $ [ range | (_,_,ranges) <- r, range <- ranges],
294
+ allRanges' <- extend txt' allRanges,
295
+ Just caRemoveAll <- removeAll allRanges',
296
+ ctxEdits <- [ x | x@ (_, d, _) <- r, d `elem` ctxDigs],
297
+ not $ null ctxEdits
298
+ = caRemoveCtx ++ [caRemoveAll]
299
+ | otherwise = []
300
+ where
301
+ extend txt ranges = extendAllToIncludeCommaIfPossible True txt ranges
302
+
303
+ groupDiag pm dig
304
+ | Just (title, ranges) <- suggestRemoveRedundantExport pm dig
305
+ = Just (title, dig, ranges)
306
+ | otherwise = Nothing
307
+
308
+ removeSingle (_, _, [] ) = Nothing
309
+ removeSingle (title, diagnostic, ranges) = Just $ CACodeAction CodeAction {.. } where
310
+ tedit = concatMap (\ r -> [TextEdit r " " ]) $ nubOrd ranges
311
+ _changes = Just $ Map. singleton uri $ List tedit
312
+ _title = title
313
+ _kind = Just CodeActionQuickFix
314
+ _diagnostics = Just $ List [diagnostic]
315
+ _documentChanges = Nothing
316
+ _edit = Just WorkspaceEdit {.. }
317
+ _command = Nothing
318
+ removeAll [] = Nothing
319
+ removeAll ranges = Just $ CACodeAction CodeAction {.. } where
320
+ tedit = concatMap (\ r -> [TextEdit r " " ]) ranges
321
+ _changes = Just $ Map. singleton uri $ List tedit
322
+ _title = " Remove all redundant exports"
323
+ _kind = Just CodeActionQuickFix
324
+ _diagnostics = Nothing
325
+ _documentChanges = Nothing
326
+ _edit = Just WorkspaceEdit {.. }
327
+ _command = Nothing
328
+
329
+ suggestRemoveRedundantExport :: ParsedModule -> Diagnostic -> Maybe (T. Text , [Range ])
330
+ suggestRemoveRedundantExport ParsedModule {pm_parsed_source = L _ HsModule {.. }} Diagnostic {.. }
331
+ | msg <- unifySpaces _message
332
+ , Just export <- hsmodExports
333
+ , Just exportRange <- getLocatedRange export
334
+ , exports <- unLoc export
335
+ , Just (removeFromExport, ! ranges) <- fmap (getRanges exports . notInScope) (extractNotInScopeName msg)
336
+ <|> (,[_range]) <$> matchExportItem msg
337
+ <|> (,[_range]) <$> matchDupExport msg
338
+ , subRange _range exportRange
339
+ = Just (" Remove ‘" <> removeFromExport <> " ’ from export" , ranges)
340
+ where
341
+ matchExportItem msg = regexSingleMatch msg " The export item ‘([^’]+)’"
342
+ matchDupExport msg = regexSingleMatch msg " Duplicate ‘([^’]+)’ in export list"
343
+ getRanges exports txt = case smallerRangesForBindingExport exports (T. unpack txt) of
344
+ [] -> (txt, [_range])
345
+ ranges -> (txt, ranges)
346
+ suggestRemoveRedundantExport _ _ = Nothing
347
+
283
348
suggestDeleteUnusedBinding :: ParsedModule -> Maybe T. Text -> Diagnostic -> [(T. Text , [TextEdit ])]
284
349
suggestDeleteUnusedBinding
285
350
ParsedModule {pm_parsed_source = L _ HsModule {hsmodDecls}}
@@ -396,6 +461,9 @@ suggestDeleteUnusedBinding
396
461
data ExportsAs = ExportName | ExportPattern | ExportAll
397
462
deriving (Eq )
398
463
464
+ getLocatedRange :: Located a -> Maybe Range
465
+ getLocatedRange = srcSpanToRange . getLoc
466
+
399
467
suggestExportUnusedTopBinding :: Maybe T. Text -> ParsedModule -> Diagnostic -> [(T. Text , [TextEdit ])]
400
468
suggestExportUnusedTopBinding srcOpt ParsedModule {pm_parsed_source = L _ HsModule {.. }} Diagnostic {.. }
401
469
-- Foo.hs:4:1: warning: [-Wunused-top-binds] Defined but not used: ‘f’
@@ -436,9 +504,6 @@ suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModul
436
504
| T. head x `elem` opLetter = (if needsTypeKeyword then " type " else " " ) <> " (" <> x <> " )"
437
505
| otherwise = x
438
506
439
- getLocatedRange :: Located a -> Maybe Range
440
- getLocatedRange = srcSpanToRange . getLoc
441
-
442
507
matchWithDiagnostic :: Range -> Located (IdP GhcPs ) -> Bool
443
508
matchWithDiagnostic Range {_start= l,_end= r} x =
444
509
let loc = fmap _start . getLocatedRange $ x
@@ -795,7 +860,10 @@ suggestInstanceConstraint df (L _ HsModule {hsmodDecls}) Diagnostic {..} missing
795
860
= Nothing
796
861
797
862
readPositionNumber :: T. Text -> Int
798
- readPositionNumber = T. unpack >>> read
863
+ readPositionNumber = T. unpack
864
+
865
+
866
+ read
799
867
800
868
actionTitle :: T. Text -> T. Text
801
869
actionTitle constraint = " Add `" <> constraint
@@ -1089,17 +1157,30 @@ textInRange (Range (Position startRow startCol) (Position endRow endCol)) text =
1089
1157
linesBeginningWithStartLine = drop startRow (T. splitOn " \n " text)
1090
1158
1091
1159
-- | Returns the ranges for a binding in an import declaration
1092
- rangesForBinding :: ImportDecl GhcPs -> String -> [Range ]
1093
- rangesForBinding ImportDecl {ideclHiding = Just (False , L _ lies)} b =
1160
+ rangesForBindingImport :: ImportDecl GhcPs -> String -> [Range ]
1161
+ rangesForBindingImport ImportDecl {ideclHiding = Just (False , L _ lies)} b =
1094
1162
concatMap (mapMaybe srcSpanToRange . rangesForBinding' b') lies
1095
1163
where
1096
- b' = wrapOperatorInParens (unqualify b)
1164
+ b' = modifyBinding b
1165
+ rangesForBindingImport _ _ = []
1097
1166
1167
+ modifyBinding :: String -> String
1168
+ modifyBinding = wrapOperatorInParens . unqualify
1169
+ where
1098
1170
wrapOperatorInParens x = if isAlpha (head x) then x else " (" <> x <> " )"
1099
-
1100
1171
unqualify x = snd $ breakOnEnd " ." x
1101
1172
1102
- rangesForBinding _ _ = []
1173
+ smallerRangesForBindingExport :: [LIE GhcPs ] -> String -> [Range ]
1174
+ smallerRangesForBindingExport lies b =
1175
+ concatMap (mapMaybe srcSpanToRange . ranges') lies
1176
+ where
1177
+ b' = modifyBinding b
1178
+ ranges' (L _ (IEThingWith _ thing _ inners labels))
1179
+ | showSDocUnsafe (ppr thing) == b' = []
1180
+ | otherwise =
1181
+ [ l' | L l' x <- inners, showSDocUnsafe (ppr x) == b'] ++
1182
+ [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b']
1183
+ ranges' _ = []
1103
1184
1104
1185
rangesForBinding' :: String -> LIE GhcPs -> [SrcSpan ]
1105
1186
rangesForBinding' b (L l x@ IEVar {}) | showSDocUnsafe (ppr x) == b = [l]
0 commit comments