on master help sign in
Add code actions for missing type signatures (#81)

* Add code actions for missing top-level type signatures * Turn signature tester into operator

commitbf9ee2a62b984a74755f60491cca7119e99ce647 authorJacek Generowicz <jacg@my-post-office.net> dateThu 19 Sep 2019, 19:40 (7 years ago) parent54633c9
2 files changed+44−7
src/Development/IDE/LSP/CodeAction.hs+10 test/exe/Main.hs+34−7
src/Development/IDE/LSP/CodeAction.hs+10
@@ -141,6 +141,16 @@ suggestAction contents Diagnostic{_range=_range@Range{..},..}
141141 extractFitNames = map (T.strip . head . T.splitOn " :: ")
142142 in map proposeHoleFit $ nubOrd $ findSuggestedHoleFits _message
143143
144+ | "Top-level binding with no type signature" `T.isInfixOf` _message = let
145+ filterNewlines = T.concat . T.lines
146+ unifySpaces = T.unwords . T.words
147+ signature = T.strip $ unifySpaces $ last $ T.splitOn "type signature: " $ filterNewlines _message
148+ startOfLine = Position (_line _start) 0
149+ beforeLine = Range startOfLine startOfLine
150+ title = "add signature: " <> signature
151+ action = TextEdit beforeLine $ signature <> "\n"
152+ in [(title, [action])]
153+
144154suggestAction _ _ = []
145155
146156topOfHoleFitsMarker :: T.Text
test/exe/Main.hs+34−7
@@ -272,6 +272,7 @@ codeActionTests = testGroup "code actions"
272272 , removeImportTests
273273 , importRenameActionTests
274274 , fillTypedHoleTests
275+ , addSigActionTests
275276 ]
276277
277278renameActionTests :: TestTree
@@ -515,7 +516,7 @@ fillTypedHoleTests = let
515516 check :: T.Text -> T.Text -> T.Text -> T.Text -> T.Text -> T.Text -> T.Text -> TestTree
516517 check actionTitle
517518 oldA oldB oldC
518− newA newB newC = testSession (T.unpack actionTitle) $ do
519+ newA newB newC = testSession (T.unpack actionTitle) $ do
519520 let originalCode = sourceCode oldA oldB oldC
520521 let expectedCode = sourceCode newA newB newC
521522 doc <- openDoc' "Testing.hs" "haskell" originalCode
@@ -525,12 +526,6 @@ fillTypedHoleTests = let
525526 executeCodeAction chosenAction
526527 modifiedCode <- documentContents doc
527528 liftIO $ expectedCode @=? modifiedCode
528−
529− pickActionWithTitle title actions = head
530− [ action
531− | CACodeAction action@CodeAction{ _title = actionTitle } <- actions
532− , title == actionTitle ]
533−
534529 in
535530 testGroup "fill typed holes"
536531 [ check "replace hole `_` with show"
@@ -562,6 +557,33 @@ fillTypedHoleTests = let
562557#endif
563558 ]
564559
560+addSigActionTests :: TestTree
561+addSigActionTests = let
562+ head = T.unlines [ "{-# OPTIONS_GHC -Wmissing-signatures #-}"
563+ , "module Sigs where"]
564+ before def = T.unlines [head, def]
565+ after def sig = T.unlines [head, sig, def]
566+
567+ def >:: sig = testSession (T.unpack def) $ do
568+ let originalCode = before def
569+ let expectedCode = after def sig
570+ doc <- openDoc' "Sigs.hs" "haskell" originalCode
571+ _ <- waitForDiagnostics
572+ actionsOrCommands <- getCodeActions doc (Range (Position 3 1) (Position 3 maxBound))
573+ let chosenAction = pickActionWithTitle ("add signature: " <> sig) actionsOrCommands
574+ executeCodeAction chosenAction
575+ modifiedCode <- documentContents doc
576+ liftIO $ expectedCode @=? modifiedCode
577+ in
578+ testGroup "add signature"
579+ [ "abc = True" >:: "abc :: Bool"
580+ , "foo a b = a + b" >:: "foo :: Num a => a -> a -> a"
581+ , "bar a b = show $ a + b" >:: "bar :: (Show a, Num a) => a -> a -> String"
582+ , "(!!!) a b = a > b" >:: "(!!!) :: Ord a => a -> a -> Bool"
583+ , "a >>>> b = a + b" >:: "(>>>>) :: Num a => a -> a -> a"
584+ , "a `haha` b = a b" >:: "haha :: (t1 -> t2) -> t1 -> t2"
585+ ]
586+
565587----------------------------------------------------------------------
566588-- Utils
567589
@@ -577,6 +599,11 @@ testSession name =
577599 -- Experimentally, 0.5s seems to be long enough to wait for any final diagnostics to appear.
578600 ( >> expectNoMoreDiagnostics 0.5)
579601
602+pickActionWithTitle :: T.Text -> [CAResult] -> CodeAction
603+pickActionWithTitle title actions = head
604+ [ action
605+ | CACodeAction action@CodeAction{ _title = actionTitle } <- actions
606+ , title == actionTitle ]
580607
581608run :: Session a -> IO a
582609run s = withTempDir $ \dir -> do