{-# LANGUAGE QuasiQuotes #-} module Main (main) where import Bag import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Data.Bool import Data.Eq import Data.Foldable import Data.Function import Data.Maybe import Data.Semigroup import Data.String import GHC.Paths import HscMain import HscTypes import Module import Outputable hiding ((<>), empty) import SourceConstraints import SourceConstraints.LocalModule import System.IO import Test.Hspec import Text.Heredoc import DynFlags ( DynFlags(packageFlags) , ModRenaming(ModRenaming) , PackageArg(PackageArg) , PackageFlag(ExposePackage) , getDynFlags ) import ErrUtils ( WarnMsg , errMsgDoc , errMsgSeverity , errMsgSpan , formatErrDoc , getCaretDiagnostic ) import GHC ( GhcMonad , LoadHowMuch(LoadAllTargets) , depanal , getSession , getSessionDynFlags , guessTarget , load , runGhc , setSessionDynFlags , setTargets , succeeded ) main :: IO () main = hspec $ do expectWarnings "test/MissingDerivingStrategy.hs" [[str|Missing deriving strategy | | |7 | data Foo = Foo deriving Eq | | ^^^^^^^^^^^|]] expectWarnings "test/UnsortedIE.hs" [[str|Unsorted import/export declaration, expected: Integer | | |4 | import Prelude (tail, head, Integer, (+)) | | ^^^^|]] expectWarnings "test/UnsortedIEThingWith.hs" [[str|Unsorted import/export item with list, expected: (+) | | |3 | import GHC.Num (Num((-), (+))) | | ^^^|]] expectWarnings "test/UnsortedMultipleDeriving.hs" [[str|Unsorted deriving clauses, expected: deriving newtype Eq | | |10 | deriving stock Show | | ^^^^^^^^^^^^^^^^^^^|]] expectWarnings "test/UnsortedImportStatement.hs" [[str|Unsorted import statement, expected: import Data.Bool | | |3 | import Data.Char | | ^^^^^^^^^^^^^^^^|]] expectWarnings "test/LocalModuleExplicitImport.hs" [[str|Present import list for local module | | |3 | import Data.Word (Word32) | | ^^^^^^^^|]] where expectWarnings file messages = it ("returns expected warnings from: " <> file) $ do actual <- getWarnings file actual `shouldBe` messages getWarnings :: String -> IO [String] getWarnings file = runGhc (pure libdir) $ do setupDynFlags setupTargets parseWarnings where parseWarnings :: GhcMonad m => m [String] parseWarnings = do moduleGraph <- depanal empty True let moduleSummary = fromMaybe (panic $ "Cannot find module summary for " <> file <> " in dependency graph") (find ((== file) . msHsFilePath) $ mgModSummaries moduleGraph) env <- getSession dynFlags <- getDynFlags parsedModule <- liftIO $ hscParse env moduleSummary let localModules = [LocalModule $ mkModuleName "Data.Word"] mapM (render dynFlags) . bagToList . warnings Context{..} $ hpm_module parsedModule setupDynFlags :: GhcMonad m => m () setupDynFlags = do dynFlags <- getSessionDynFlags void . setSessionDynFlags $ dynFlags { packageFlags = [packageFlag] } where packageFlag = ExposePackage "-package base" (PackageArg "base") (ModRenaming True empty) setupTargets :: GhcMonad m => m () setupTargets = do target <- guessTarget file empty setTargets [target] result <- load LoadAllTargets unless (succeeded result) $ panic "Loading of targets failed" render :: GhcMonad m => DynFlags -> WarnMsg -> m String render dynFlags warning = do caretDiagnostic <- liftIO $ getCaretDiagnostic (errMsgSeverity warning) (errMsgSpan warning) pure $ renderWithStyle dynFlags (formatErrDoc dynFlags (errMsgDoc warning) $+$ caretDiagnostic) (defaultUserStyle dynFlags)