    -- |
    -- Module      :  Distribution.PackageDescription.Check.Target
    -- Copyright   :  Lennart Kolmodin 2008, Francesco Ariis 2023
    -- License     :  BSD3
    --
    -- Maintainer  :  cabal-devel@haskell.org
    -- Portability :  portable
    --
    -- Fully-realised target (library, executable, …) checking functions.
    module Distribution.PackageDescription.Check.Target
      ( checkLibrary
      , checkForeignLib
      , checkExecutable
      , checkTestSuite
      , checkBenchmark
      ) where

    import Distribution.Compat.Prelude
    import Prelude ()

    import Distribution.CabalSpecVersion
    import Distribution.Compat.Lens
    import Distribution.Compiler
    import Distribution.ModuleName (ModuleName)
    import Distribution.Package
    import Distribution.PackageDescription
    import Distribution.PackageDescription.Check.Common
    import Distribution.PackageDescription.Check.Monad
    import Distribution.PackageDescription.Check.Paths
    import Distribution.Pretty (prettyShow)
    import Distribution.Simple.BuildPaths
      ( autogenPackageInfoModuleName
      , autogenPathsModuleName
      )
    import Distribution.Simple.Utils hiding (findPackageDesc, notice)
    import Distribution.Types.PackageName.Magic
    import Distribution.Utils.Path
    import Distribution.Version
    import Language.Haskell.Extension
    import System.FilePath (takeExtension)

    import Control.Monad

    import qualified Distribution.Types.BuildInfo.Lens as L

    checkLibrary
      :: Monad m
      => Bool -- Is this a sublibrary?
      -> [AssocDep] -- “Inherited” dependencies for PVP checks.
      -> Library
      -> CheckM m ()
    checkLibrary :: forall (m :: * -> *).
    Monad m =>
    Bool -> [AssocDep] -> Library -> CheckM m ()
    checkLibrary
      Bool
    isSub
      [AssocDep]
    ads
      lib :: Library
    lib@( Library
              LibraryName
    libName_
              [ModuleName]
    _exposedModules_
              [ModuleReexport]
    reexportedModules_
              [ModuleName]
    signatures_
              Bool
    _libExposed_
              LibraryVisibility
    _libVisibility_
              BuildInfo
    libBuildInfo_
            ) = do
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          (LibraryName
    libName_ LibraryName -> LibraryName -> Bool
    forall a. Eq a => a -> a -> Bool
    == LibraryName
    LMainLibName Bool -> Bool -> Bool
    && Bool
    isSub)
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    UnnamedInternal)
        -- TODO: bogus if a required-signature was passed through.
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ([ModuleName] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (Library -> [ModuleName]
    explicitLibModules Library
    lib) Bool -> Bool -> Bool
    && [ModuleReexport] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [ModuleReexport]
    reexportedModules_)
          (CheckExplanation -> PackageCheck
    PackageDistSuspiciousWarn (LibraryName -> CheckExplanation
    NoModulesExposed LibraryName
    libName_))
        -- TODO parse-caught check, can safely remove.
        CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
          CabalSpecVersion
    CabalSpecV2_0
          (Bool -> Bool
    not (Bool -> Bool) -> ([ModuleName] -> Bool) -> [ModuleName] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ModuleName] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([ModuleName] -> Bool) -> [ModuleName] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [ModuleName]
    signatures_)
          (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    SignaturesCabal2)
        -- autogen/includes checks.
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ( Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
              (ModuleName -> Bool) -> [ModuleName] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all
                ((ModuleName -> [ModuleName] -> Bool)
    -> [ModuleName] -> ModuleName -> Bool
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ModuleName -> [ModuleName] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem (Library -> [ModuleName]
    explicitLibModules Library
    lib))
                (Library -> [ModuleName]
    libModulesAutogen Library
    lib)
          )
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    AutogenNotExposed)
        -- check that all autogen-includes appear on includes or
        -- install-includes.
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ( Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
              (FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all
                ((FilePath -> [FilePath] -> Bool) -> [FilePath] -> FilePath -> Bool
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem (Library -> [FilePath]
    forall a. HasBuildInfo a => a -> [FilePath]
    allExplicitIncludes Library
    lib))
                (Getting [FilePath] Library [FilePath] -> Library -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] Library [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' Library [FilePath]
    L.autogenIncludes Library
    lib)
          )
          (PackageCheck -> CheckM m ()) -> PackageCheck -> CheckM m ()
    forall a b. (a -> b) -> a -> b
    $ (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    AutogenIncludesNotIncluded)

        -- § Build infos.
        CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    checkBuildInfo
          (LibraryName -> CEType
    CETLibrary LibraryName
    libName_)
          (Library -> [ModuleName]
    explicitLibModules Library
    lib)
          [AssocDep]
    ads
          BuildInfo
    libBuildInfo_

        -- Feature checks.
        -- check use of reexported-modules sections
        CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
          CabalSpecVersion
    CabalSpecV1_22
          (Bool -> Bool
    not (Bool -> Bool)
    -> ([ModuleReexport] -> Bool) -> [ModuleReexport] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ModuleReexport] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([ModuleReexport] -> Bool) -> [ModuleReexport] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [ModuleReexport]
    reexportedModules_)
          (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    CVReexported)
        where
          allExplicitIncludes :: L.HasBuildInfo a => a -> [FilePath]
          allExplicitIncludes :: forall a. HasBuildInfo a => a -> [FilePath]
    allExplicitIncludes a
    x =
            Getting [FilePath] a [FilePath] -> a -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] a [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' a [FilePath]
    L.includes a
    x
              [FilePath] -> [FilePath] -> [FilePath]
    forall a. [a] -> [a] -> [a]
    ++ Getting [FilePath] a [FilePath] -> a -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] a [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' a [FilePath]
    L.installIncludes a
    x

    checkForeignLib :: Monad m => ForeignLib -> CheckM m ()
    checkForeignLib :: forall (m :: * -> *). Monad m => ForeignLib -> CheckM m ()
    checkForeignLib
      ( ForeignLib
          UnqualComponentName
    foreignLibName_
          ForeignLibType
    _foreignLibType_
          [ForeignLibOption]
    _foreignLibOptions_
          BuildInfo
    foreignLibBuildInfo_
          Maybe LibVersionInfo
    _foreignLibVersionInfo_
          Maybe Version
    _foreignLibVersionLinux_
          [FilePath]
    _foreignLibModDefFile_
        ) = do
        CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    checkBuildInfo
          (UnqualComponentName -> CEType
    CETForeignLibrary UnqualComponentName
    foreignLibName_)
          []
          []
          BuildInfo
    foreignLibBuildInfo_

    checkExecutable
      :: Monad m
      => [AssocDep] -- “Inherited” dependencies for PVP checks.
      -> Executable
      -> CheckM m ()
    checkExecutable :: forall (m :: * -> *).
    Monad m =>
    [AssocDep] -> Executable -> CheckM m ()
    checkExecutable
      [AssocDep]
    ads
      exe :: Executable
    exe@( Executable
              UnqualComponentName
    exeName_
              FilePath
    modulePath_
              ExecutableScope
    _exeScope_
              BuildInfo
    buildInfo_
            ) = do
        -- Target type/name (exe).
        let cet :: CEType
    cet = UnqualComponentName -> CEType
    CETExecutable UnqualComponentName
    exeName_

        -- § Exe specific checks
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          (FilePath -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null FilePath
    modulePath_)
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible (UnqualComponentName -> CheckExplanation
    NoMainIs UnqualComponentName
    exeName_))
        -- This check does not apply to scripts.
        pid <- (CheckCtx m -> PackageIdentifier) -> CheckM m PackageIdentifier
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM (PNames -> PackageIdentifier
    pnPackageId (PNames -> PackageIdentifier)
    -> (CheckCtx m -> PNames) -> CheckCtx m -> PackageIdentifier
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CheckCtx m -> PNames
    forall (m :: * -> *). CheckCtx m -> PNames
    ccNames)
        checkP
          ( pid /= fakePackageId
              && not (null modulePath_)
              && not (fileExtensionSupportedLanguage $ modulePath_)
          )
          (PackageBuildImpossible NoHsLhsMain)

        -- § Features check
        checkSpecVer
          CabalSpecV1_18
          ( fileExtensionSupportedLanguage modulePath_
              && takeExtension modulePath_ `notElem` [".hs", ".lhs"]
          )
          (PackageDistInexcusable MainCCabal1_18)

        -- Alas exeModules ad exeModulesAutogen (exported from
        -- Distribution.Types.Executable) take `Executable` as a parameter.
        checkP
          (not $ all (flip elem (exeModules exe)) (exeModulesAutogen exe))
          (PackageBuildImpossible $ AutogenNoOther cet)
        checkP
          ( not $
              all
                (flip elem (view L.includes exe))
                (view L.autogenIncludes exe)
          )
          (PackageBuildImpossible AutogenIncludesNotIncludedExe)

        -- § Build info checks.
        checkBuildInfo cet [] ads buildInfo_

    checkTestSuite
      :: Monad m
      => [AssocDep] -- “Inherited” dependencies for PVP checks.
      -> TestSuite
      -> CheckM m ()
    checkTestSuite :: forall (m :: * -> *).
    Monad m =>
    [AssocDep] -> TestSuite -> CheckM m ()
    checkTestSuite
      [AssocDep]
    ads
      ts :: TestSuite
    ts@( TestSuite
            UnqualComponentName
    testName_
            TestSuiteInterface
    testInterface_
            BuildInfo
    testBuildInfo_
            [FilePath]
    _testCodeGenerators_
          ) = do
        -- Target type/name (test).
        let cet :: CEType
    cet = UnqualComponentName -> CEType
    CETTest UnqualComponentName
    testName_

        -- § TS specific checks.
        -- TODO caught by the parser, can remove safely
        case TestSuiteInterface
    testInterface_ of
          TestSuiteUnsupported tt :: TestType
    tt@(TestTypeUnknown FilePath
    _ Version
    _) ->
            PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ TestType -> CheckExplanation
    TestsuiteTypeNotKnown TestType
    tt)
          TestSuiteUnsupported TestType
    tt ->
            PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ TestType -> CheckExplanation
    TestsuiteNotSupported TestType
    tt)
          TestSuiteInterface
    _ -> () -> CheckM m ()
    forall a. a -> CheckM m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          Bool
    mainIsWrongExt
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    NoHsLhsMain)
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ( Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
              (ModuleName -> Bool) -> [ModuleName] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all
                ((ModuleName -> [ModuleName] -> Bool)
    -> [ModuleName] -> ModuleName -> Bool
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ModuleName -> [ModuleName] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem (TestSuite -> [ModuleName]
    testModules TestSuite
    ts))
                (TestSuite -> [ModuleName]
    testModulesAutogen TestSuite
    ts)
          )
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ CEType -> CheckExplanation
    AutogenNoOther CEType
    cet)
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ( Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
              (FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all
                ((FilePath -> [FilePath] -> Bool) -> [FilePath] -> FilePath -> Bool
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem (Getting [FilePath] TestSuite [FilePath] -> TestSuite -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] TestSuite [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' TestSuite [FilePath]
    L.includes TestSuite
    ts))
                (Getting [FilePath] TestSuite [FilePath] -> TestSuite -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] TestSuite [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' TestSuite [FilePath]
    L.autogenIncludes TestSuite
    ts)
          )
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    AutogenIncludesNotIncludedExe)

        -- § Feature checks.
        CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
          CabalSpecVersion
    CabalSpecV1_18
          (Bool
    mainIsNotHsExt Bool -> Bool -> Bool
    && Bool -> Bool
    not Bool
    mainIsWrongExt)
          (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    MainCCabal1_18)

        -- § Build info checks.
        CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    checkBuildInfo CEType
    cet [] [AssocDep]
    ads BuildInfo
    testBuildInfo_
        where
          mainIsWrongExt :: Bool
    mainIsWrongExt =
            case TestSuiteInterface
    testInterface_ of
              TestSuiteExeV10 Version
    _ FilePath
    f -> Bool -> Bool
    not (FilePath -> Bool
    fileExtensionSupportedLanguage FilePath
    f)
              TestSuiteInterface
    _ -> Bool
    False

          mainIsNotHsExt :: Bool
    mainIsNotHsExt =
            case TestSuiteInterface
    testInterface_ of
              TestSuiteExeV10 Version
    _ FilePath
    f -> FilePath -> FilePath
    takeExtension FilePath
    f FilePath -> [FilePath] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [FilePath
    ".hs", FilePath
    ".lhs"]
              TestSuiteInterface
    _ -> Bool
    False

    checkBenchmark
      :: Monad m
      => [AssocDep] -- “Inherited” dependencies for PVP checks.
      -> Benchmark
      -> CheckM m ()
    checkBenchmark :: forall (m :: * -> *).
    Monad m =>
    [AssocDep] -> Benchmark -> CheckM m ()
    checkBenchmark
      [AssocDep]
    ads
      bm :: Benchmark
    bm@( Benchmark
            UnqualComponentName
    benchmarkName_
            BenchmarkInterface
    benchmarkInterface_
            BuildInfo
    benchmarkBuildInfo_
          ) = do
        -- Target type/name (benchmark).
        let cet :: CEType
    cet = UnqualComponentName -> CEType
    CETBenchmark UnqualComponentName
    benchmarkName_

        -- § Interface & bm specific tests.
        case BenchmarkInterface
    benchmarkInterface_ of
          BenchmarkUnsupported tt :: BenchmarkType
    tt@(BenchmarkTypeUnknown FilePath
    _ Version
    _) ->
            PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ BenchmarkType -> CheckExplanation
    BenchmarkTypeNotKnown BenchmarkType
    tt)
          BenchmarkUnsupported BenchmarkType
    tt ->
            PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ BenchmarkType -> CheckExplanation
    BenchmarkNotSupported BenchmarkType
    tt)
          BenchmarkInterface
    _ -> () -> CheckM m ()
    forall a. a -> CheckM m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          Bool
    mainIsWrongExt
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    NoHsLhsMainBench)

        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ( Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
              (ModuleName -> Bool) -> [ModuleName] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all
                ((ModuleName -> [ModuleName] -> Bool)
    -> [ModuleName] -> ModuleName -> Bool
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ModuleName -> [ModuleName] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem (Benchmark -> [ModuleName]
    benchmarkModules Benchmark
    bm))
                (Benchmark -> [ModuleName]
    benchmarkModulesAutogen Benchmark
    bm)
          )
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ CEType -> CheckExplanation
    AutogenNoOther CEType
    cet)

        Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
          ( Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
              (FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all
                ((FilePath -> [FilePath] -> Bool) -> [FilePath] -> FilePath -> Bool
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem (Getting [FilePath] Benchmark [FilePath] -> Benchmark -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] Benchmark [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' Benchmark [FilePath]
    L.includes Benchmark
    bm))
                (Getting [FilePath] Benchmark [FilePath] -> Benchmark -> [FilePath]
    forall a s. Getting a s a -> s -> a
    view Getting [FilePath] Benchmark [FilePath]
    forall a. HasBuildInfo a => Lens' a [FilePath]
    Lens' Benchmark [FilePath]
    L.autogenIncludes Benchmark
    bm)
          )
          (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    AutogenIncludesNotIncludedExe)

        -- § BuildInfo checks.
        CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    checkBuildInfo CEType
    cet [] [AssocDep]
    ads BuildInfo
    benchmarkBuildInfo_
        where
          -- Cannot abstract with similar function in checkTestSuite,
          -- they are different.
          mainIsWrongExt :: Bool
    mainIsWrongExt =
            case BenchmarkInterface
    benchmarkInterface_ of
              BenchmarkExeV10 Version
    _ FilePath
    f -> FilePath -> FilePath
    takeExtension FilePath
    f FilePath -> [FilePath] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [FilePath
    ".hs", FilePath
    ".lhs"]
              BenchmarkInterface
    _ -> Bool
    False

    -- ------------------------------------------------------------
    -- Build info
    -- ------------------------------------------------------------

    -- Check a great deal of things in buildInfo.
    -- With 'checkBuildInfo' we cannot follow the usual “pattern match
    -- everything” method, for the number of BuildInfo fields (almost 50)
    -- but more importantly because accessing options, etc. is done
    -- with functions from 'Distribution.Types.BuildInfo' (e.g. 'hcOptions').
    -- Duplicating the effort here means risk of diverging definitions for
    -- little gain (most likely if a field is added to BI, the relevant
    -- function will be tweaked in Distribution.Types.BuildInfo too).
    checkBuildInfo
      :: Monad m
      => CEType -- Name and type of the target.
      -> [ModuleName] -- Additional module names which cannot be
      -- extracted from BuildInfo (mainly: exposed
      -- library modules).
      -> [AssocDep] -- Inherited “internal” (main lib, named
      -- internal libs) dependencies.
      -> BuildInfo
      -> CheckM m ()
    checkBuildInfo :: forall (m :: * -> *).
    Monad m =>
    CEType -> [ModuleName] -> [AssocDep] -> BuildInfo -> CheckM m ()
    checkBuildInfo CEType
    cet [ModuleName]
    ams [AssocDep]
    ads BuildInfo
    bi = do
      -- For the sake of clarity, we split che checks in various
      -- (top level) functions, even if we are not actually going
      -- deeper in the traversal.

      BITarget -> BuildInfo -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    BITarget -> BuildInfo -> CheckM m ()
    checkBuildInfoOptions (CEType -> BITarget
    cet2bit CEType
    cet) BuildInfo
    bi
      BuildInfo -> CheckM m ()
    forall (m :: * -> *). Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoPathsContent BuildInfo
    bi
      BuildInfo -> CheckM m ()
    forall (m :: * -> *). Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoPathsWellFormedness BuildInfo
    bi

      sv <- (CheckCtx m -> CabalSpecVersion) -> CheckM m CabalSpecVersion
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM CheckCtx m -> CabalSpecVersion
    forall (m :: * -> *). CheckCtx m -> CabalSpecVersion
    ccSpecVersion
      checkBuildInfoFeatures bi sv

      checkAutogenModules ams bi

      -- PVP: we check for base and all other deps.
      (ids, rds) <-
        partitionDeps
          ads
          [mkUnqualComponentName "base"]
          (mergeDependencies $ targetBuildDepends bi)
      let ick = PackageCheck -> b -> PackageCheck
    forall a b. a -> b -> a
    const (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    BaseNoUpperBounds)
          rck = CheckExplanation -> PackageCheck
    PackageDistSuspiciousWarn (CheckExplanation -> PackageCheck)
    -> ([FilePath] -> CheckExplanation) -> [FilePath] -> PackageCheck
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CEType -> [FilePath] -> CheckExplanation
    MissingUpperBounds CEType
    cet
      checkPVP ick ids
      unless
        (isInternalTarget cet)
        (checkPVPs rck rds)

      -- Custom fields well-formedness (ASCII).
      mapM_ checkCustomField (customFieldsBI bi)

      -- Content.
      mapM_ (checkLocalPathExist "extra-lib-dirs") (extraLibDirs bi)
      mapM_
        (checkLocalPathExist "extra-lib-dirs-static")
        (extraLibDirsStatic bi)
      mapM_
        (checkLocalPathExist "extra-framework-dirs")
        (extraFrameworkDirs bi)
      mapM_ (checkLocalPathExist "include-dirs") (includeDirs bi)
      mapM_
        (checkLocalPathExist "hs-source-dirs" . getSymbolicPath)
        (hsSourceDirs bi)

    -- Well formedness of BI contents (no `Haskell2015`, no deprecated
    -- extensions etc).
    checkBuildInfoPathsContent :: Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoPathsContent :: forall (m :: * -> *). Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoPathsContent BuildInfo
    bi = do
      (Language -> CheckM m ()) -> [Language] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Language -> CheckM m ()
    forall (m :: * -> *). Monad m => Language -> CheckM m ()
    checkLang (BuildInfo -> [Language]
    allLanguages BuildInfo
    bi)
      (Extension -> CheckM m ()) -> [Extension] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Extension -> CheckM m ()
    forall (m :: * -> *). Monad m => Extension -> CheckM m ()
    checkExt (BuildInfo -> [Extension]
    allExtensions BuildInfo
    bi)
      (Dependency -> CheckM m ()) -> [Dependency] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Dependency -> CheckM m ()
    forall (m :: * -> *). Monad m => Dependency -> CheckM m ()
    checkIntDep (BuildInfo -> [Dependency]
    targetBuildDepends BuildInfo
    bi)
      df <- (CheckCtx m -> LegacyExeDependency -> Maybe ExeDependency)
    -> CheckM m (LegacyExeDependency -> Maybe ExeDependency)
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM CheckCtx m -> LegacyExeDependency -> Maybe ExeDependency
    forall (m :: * -> *).
    CheckCtx m -> LegacyExeDependency -> Maybe ExeDependency
    ccDesugar
      -- This way we can use the same function for legacy&non exedeps.
      let ds = BuildInfo -> [ExeDependency]
    buildToolDepends BuildInfo
    bi [ExeDependency] -> [ExeDependency] -> [ExeDependency]
    forall a. [a] -> [a] -> [a]
    ++ [Maybe ExeDependency] -> [ExeDependency]
    forall a. [Maybe a] -> [a]
    catMaybes ((LegacyExeDependency -> Maybe ExeDependency)
    -> [LegacyExeDependency] -> [Maybe ExeDependency]
    forall a b. (a -> b) -> [a] -> [b]
    map LegacyExeDependency -> Maybe ExeDependency
    df ([LegacyExeDependency] -> [Maybe ExeDependency])
    -> [LegacyExeDependency] -> [Maybe ExeDependency]
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [LegacyExeDependency]
    buildTools BuildInfo
    bi)
      mapM_ checkBTDep ds
      where
        checkLang :: Monad m => Language -> CheckM m ()
        checkLang :: forall (m :: * -> *). Monad m => Language -> CheckM m ()
    checkLang (UnknownLanguage FilePath
    n) =
          PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning ([FilePath] -> CheckExplanation
    UnknownLanguages [FilePath
    n]))
        checkLang Language
    _ = () -> CheckM m ()
    forall a. a -> CheckM m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

        checkExt :: Monad m => Extension -> CheckM m ()
        checkExt :: forall (m :: * -> *). Monad m => Extension -> CheckM m ()
    checkExt (UnknownExtension FilePath
    n)
          | FilePath
    n FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` (Language -> FilePath) -> [Language] -> [FilePath]
    forall a b. (a -> b) -> [a] -> [b]
    map Language -> FilePath
    forall a. Pretty a => a -> FilePath
    prettyShow [Language]
    knownLanguages =
              PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning ([FilePath] -> CheckExplanation
    LanguagesAsExtension [FilePath
    n]))
          | Bool
    otherwise =
              PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning ([FilePath] -> CheckExplanation
    UnknownExtensions [FilePath
    n]))
        checkExt Extension
    n = do
          let dss :: [(Extension, Maybe Extension)]
    dss = ((Extension, Maybe Extension) -> Bool)
    -> [(Extension, Maybe Extension)] -> [(Extension, Maybe Extension)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (\(Extension
    a, Maybe Extension
    _) -> Extension
    a Extension -> Extension -> Bool
    forall a. Eq a => a -> a -> Bool
    == Extension
    n) [(Extension, Maybe Extension)]
    deprecatedExtensions
          Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
            (Bool -> Bool
    not (Bool -> Bool)
    -> ([(Extension, Maybe Extension)] -> Bool)
    -> [(Extension, Maybe Extension)]
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(Extension, Maybe Extension)] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([(Extension, Maybe Extension)] -> Bool)
    -> [(Extension, Maybe Extension)] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [(Extension, Maybe Extension)]
    dss)
            (CheckExplanation -> PackageCheck
    PackageDistSuspicious (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ [(Extension, Maybe Extension)] -> CheckExplanation
    DeprecatedExtensions [(Extension, Maybe Extension)]
    dss)

        checkIntDep :: Monad m => Dependency -> CheckM m ()
        checkIntDep :: forall (m :: * -> *). Monad m => Dependency -> CheckM m ()
    checkIntDep d :: Dependency
    d@(Dependency PackageName
    name VersionRange
    vrange NonEmptySet LibraryName
    _) = do
          mpn <-
            (CheckCtx m -> UnqualComponentName) -> CheckM m UnqualComponentName
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM
              ( PackageName -> UnqualComponentName
    packageNameToUnqualComponentName
                  (PackageName -> UnqualComponentName)
    -> (CheckCtx m -> PackageName) -> CheckCtx m -> UnqualComponentName
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PackageIdentifier -> PackageName
    pkgName
                  (PackageIdentifier -> PackageName)
    -> (CheckCtx m -> PackageIdentifier) -> CheckCtx m -> PackageName
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PNames -> PackageIdentifier
    pnPackageId
                  (PNames -> PackageIdentifier)
    -> (CheckCtx m -> PNames) -> CheckCtx m -> PackageIdentifier
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CheckCtx m -> PNames
    forall (m :: * -> *). CheckCtx m -> PNames
    ccNames
              )
          lns <- asksCM (pnSubLibs . ccNames)
          pVer <- asksCM (pkgVersion . pnPackageId . ccNames)
          let allLibNs = UnqualComponentName
    mpn UnqualComponentName
    -> [UnqualComponentName] -> [UnqualComponentName]
    forall a. a -> [a] -> [a]
    : [UnqualComponentName]
    lns
          when
            ( mpn == packageNameToUnqualComponentName name
                -- Make sure it is not a library with the
                -- same name from another package.
                && packageNameToUnqualComponentName name `elem` allLibNs
            )
            ( checkP
                (not $ pVer `withinRange` vrange)
                (PackageBuildImpossible $ ImpossibleInternalDep [d])
            )

        checkBTDep :: Monad m => ExeDependency -> CheckM m ()
        checkBTDep :: forall (m :: * -> *). Monad m => ExeDependency -> CheckM m ()
    checkBTDep ed :: ExeDependency
    ed@(ExeDependency PackageName
    n UnqualComponentName
    name VersionRange
    vrange) = do
          exns <- (CheckCtx m -> [UnqualComponentName])
    -> CheckM m [UnqualComponentName]
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM (PNames -> [UnqualComponentName]
    pnExecs (PNames -> [UnqualComponentName])
    -> (CheckCtx m -> PNames) -> CheckCtx m -> [UnqualComponentName]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CheckCtx m -> PNames
    forall (m :: * -> *). CheckCtx m -> PNames
    ccNames)
          pVer <- asksCM (pkgVersion . pnPackageId . ccNames)
          pNam <- asksCM (pkgName . pnPackageId . ccNames)
          checkP
            ( n == pNam
                && name `notElem` exns -- internal
                -- not present
            )
            (PackageBuildImpossible $ MissingInternalExe [ed])
          when
            (name `elem` exns)
            ( checkP
                (not $ pVer `withinRange` vrange)
                (PackageBuildImpossible $ ImpossibleInternalExe [ed])
            )

    -- Paths well-formedness check for BuildInfo.
    checkBuildInfoPathsWellFormedness :: Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoPathsWellFormedness :: forall (m :: * -> *). Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoPathsWellFormedness BuildInfo
    bi = do
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "asm-sources" PathKind
    PathKindFile) (BuildInfo -> [FilePath]
    asmSources BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "cmm-sources" PathKind
    PathKindFile) (BuildInfo -> [FilePath]
    cmmSources BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "c-sources" PathKind
    PathKindFile) (BuildInfo -> [FilePath]
    cSources BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "cxx-sources" PathKind
    PathKindFile) (BuildInfo -> [FilePath]
    cxxSources BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "js-sources" PathKind
    PathKindFile) (BuildInfo -> [FilePath]
    jsSources BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
        (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "install-includes" PathKind
    PathKindFile)
        (BuildInfo -> [FilePath]
    installIncludes BuildInfo
    bi)
      (SymbolicPath PackageDir SourceDir -> CheckM m ())
    -> [SymbolicPath PackageDir SourceDir] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
        (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    False FilePath
    "hs-source-dirs" PathKind
    PathKindDirectory (FilePath -> CheckM m ())
    -> (SymbolicPath PackageDir SourceDir -> FilePath)
    -> SymbolicPath PackageDir SourceDir
    -> CheckM m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SymbolicPath PackageDir SourceDir -> FilePath
    forall from to. SymbolicPath from to -> FilePath
    getSymbolicPath)
        (BuildInfo -> [SymbolicPath PackageDir SourceDir]
    hsSourceDirs BuildInfo
    bi)
      -- Possibly absolute paths.
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    True FilePath
    "includes" PathKind
    PathKindFile) (BuildInfo -> [FilePath]
    includes BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
        (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    True FilePath
    "include-dirs" PathKind
    PathKindDirectory)
        (BuildInfo -> [FilePath]
    includeDirs BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
        (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    True FilePath
    "extra-lib-dirs" PathKind
    PathKindDirectory)
        (BuildInfo -> [FilePath]
    extraLibDirs BuildInfo
    bi)
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
        (Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> FilePath -> PathKind -> FilePath -> CheckM m ()
    checkPath Bool
    True FilePath
    "extra-lib-dirs-static" PathKind
    PathKindDirectory)
        (BuildInfo -> [FilePath]
    extraLibDirsStatic BuildInfo
    bi)
      ((CompilerFlavor, [FilePath]) -> CheckM m ())
    -> [(CompilerFlavor, [FilePath])] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (CompilerFlavor, [FilePath]) -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    (CompilerFlavor, [FilePath]) -> CheckM m ()
    checkOptionPath (PerCompilerFlavor [FilePath] -> [(CompilerFlavor, [FilePath])]
    forall v. PerCompilerFlavor v -> [(CompilerFlavor, v)]
    perCompilerFlavorToList (PerCompilerFlavor [FilePath] -> [(CompilerFlavor, [FilePath])])
    -> PerCompilerFlavor [FilePath] -> [(CompilerFlavor, [FilePath])]
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> PerCompilerFlavor [FilePath]
    options BuildInfo
    bi)
      where
        checkOptionPath
          :: Monad m
          => (CompilerFlavor, [FilePath])
          -> CheckM m ()
        checkOptionPath :: forall (m :: * -> *).
    Monad m =>
    (CompilerFlavor, [FilePath]) -> CheckM m ()
    checkOptionPath (CompilerFlavor
    GHC, [FilePath]
    paths) =
          (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
            ( \FilePath
    path ->
                Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
                  (FilePath -> Bool
    isInsideDist FilePath
    path)
                  (CheckExplanation -> PackageCheck
    PackageDistInexcusable (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ Maybe FilePath -> FilePath -> CheckExplanation
    DistPoint Maybe FilePath
    forall a. Maybe a
    Nothing FilePath
    path)
            )
            [FilePath]
    paths
        checkOptionPath (CompilerFlavor, [FilePath])
    _ = () -> CheckM m ()
    forall a. a -> CheckM m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    -- Checks for features that can be present in BuildInfo only with certain
    -- CabalSpecVersion.
    checkBuildInfoFeatures
      :: Monad m
      => BuildInfo
      -> CabalSpecVersion
      -> CheckM m ()
    checkBuildInfoFeatures :: forall (m :: * -> *).
    Monad m =>
    BuildInfo -> CabalSpecVersion -> CheckM m ()
    checkBuildInfoFeatures BuildInfo
    bi CabalSpecVersion
    sv = do
      -- Default language can be used only w/ spec ≥ 1.10
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV1_10
        (Maybe Language -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe Language -> Bool) -> Maybe Language -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> Maybe Language
    defaultLanguage BuildInfo
    bi)
        (CheckExplanation -> PackageCheck
    PackageBuildWarning CheckExplanation
    CVDefaultLanguage)
      -- CheckSpecVer sv.
      CheckM m ()
    forall (m :: * -> *). Monad m => CheckM m ()
    checkDefaultLanguage
      -- Check use of 'extra-framework-dirs' field.
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV1_24
        (Bool -> Bool
    not (Bool -> Bool) -> ([FilePath] -> Bool) -> [FilePath] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [FilePath] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([FilePath] -> Bool) -> [FilePath] -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [FilePath]
    extraFrameworkDirs BuildInfo
    bi)
        (CheckExplanation -> PackageCheck
    PackageDistSuspiciousWarn CheckExplanation
    CVExtraFrameworkDirs)
      -- Check use of default-extensions field don't need to do the
      -- equivalent check for other-extensions.
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV1_10
        (Bool -> Bool
    not (Bool -> Bool) -> ([Extension] -> Bool) -> [Extension] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Extension] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([Extension] -> Bool) -> [Extension] -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [Extension]
    defaultExtensions BuildInfo
    bi)
        (CheckExplanation -> PackageCheck
    PackageBuildWarning CheckExplanation
    CVDefaultExtensions)
      -- Check use of extensions field
      Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
        (CabalSpecVersion
    sv CabalSpecVersion -> CabalSpecVersion -> Bool
    forall a. Ord a => a -> a -> Bool
    >= CabalSpecVersion
    CabalSpecV1_10 Bool -> Bool -> Bool
    && (Bool -> Bool
    not (Bool -> Bool) -> ([Extension] -> Bool) -> [Extension] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Extension] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([Extension] -> Bool) -> [Extension] -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [Extension]
    oldExtensions BuildInfo
    bi))
        (CheckExplanation -> PackageCheck
    PackageBuildWarning CheckExplanation
    CVExtensionsDeprecated)

      -- asm-sources, cmm-sources and friends only w/ spec ≥ 1.10
      [FilePath] -> CheckM m ()
    forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCVSources (BuildInfo -> [FilePath]
    asmSources BuildInfo
    bi)
      [FilePath] -> CheckM m ()
    forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCVSources (BuildInfo -> [FilePath]
    cmmSources BuildInfo
    bi)
      [FilePath] -> CheckM m ()
    forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCVSources (BuildInfo -> [FilePath]
    extraBundledLibs BuildInfo
    bi)
      [FilePath] -> CheckM m ()
    forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCVSources (BuildInfo -> [FilePath]
    extraLibFlavours BuildInfo
    bi)

      -- extra-dynamic-library-flavours requires ≥ 3.0
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV3_0
        (Bool -> Bool
    not (Bool -> Bool) -> ([FilePath] -> Bool) -> [FilePath] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [FilePath] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([FilePath] -> Bool) -> [FilePath] -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [FilePath]
    extraDynLibFlavours BuildInfo
    bi)
        (CheckExplanation -> PackageCheck
    PackageDistInexcusable (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ [[FilePath]] -> CheckExplanation
    CVExtraDynamic [BuildInfo -> [FilePath]
    extraDynLibFlavours BuildInfo
    bi])
      -- virtual-modules requires ≥ 2.2
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer CabalSpecVersion
    CabalSpecV2_2 (Bool -> Bool
    not (Bool -> Bool) -> ([ModuleName] -> Bool) -> [ModuleName] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ModuleName] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([ModuleName] -> Bool) -> [ModuleName] -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [ModuleName]
    virtualModules BuildInfo
    bi) (PackageCheck -> CheckM m ()) -> PackageCheck -> CheckM m ()
    forall a b. (a -> b) -> a -> b
    $
        (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    CVVirtualModules)
      -- Check use of thinning and renaming.
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV2_0
        (Bool -> Bool
    not (Bool -> Bool) -> ([Mixin] -> Bool) -> [Mixin] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Mixin] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([Mixin] -> Bool) -> [Mixin] -> Bool
    forall a b. (a -> b) -> a -> b
    $ BuildInfo -> [Mixin]
    mixins BuildInfo
    bi)
        (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    CVMixins)

      BuildInfo -> CheckM m ()
    forall (m :: * -> *). Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoExtensions BuildInfo
    bi
      where
        checkCVSources :: Monad m => [FilePath] -> CheckM m ()
        checkCVSources :: forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCVSources [FilePath]
    cvs =
          CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
            CabalSpecVersion
    CabalSpecV3_0
            (Bool -> Bool
    not (Bool -> Bool) -> ([FilePath] -> Bool) -> [FilePath] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [FilePath] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([FilePath] -> Bool) -> [FilePath] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [FilePath]
    cvs)
            (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    CVSources)

        checkDefaultLanguage :: Monad m => CheckM m ()
        checkDefaultLanguage :: forall (m :: * -> *). Monad m => CheckM m ()
    checkDefaultLanguage = do
          -- < 1.10 has no `default-language` field.
          Bool -> CheckM m () -> CheckM m ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when
            (CabalSpecVersion
    sv CabalSpecVersion -> CabalSpecVersion -> Bool
    forall a. Ord a => a -> a -> Bool
    >= CabalSpecVersion
    CabalSpecV1_10 Bool -> Bool -> Bool
    && Maybe Language -> Bool
    forall a. Maybe a -> Bool
    isNothing (BuildInfo -> Maybe Language
    defaultLanguage BuildInfo
    bi))
            -- < 3.4 mandatory, after just a suggestion.
            ( if CabalSpecVersion
    sv CabalSpecVersion -> CabalSpecVersion -> Bool
    forall a. Ord a => a -> a -> Bool
    < CabalSpecVersion
    CabalSpecV3_4
                then PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageBuildWarning CheckExplanation
    CVDefaultLanguageComponent)
                else PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (CheckExplanation -> PackageCheck
    PackageDistInexcusable CheckExplanation
    CVDefaultLanguageComponentSoft)
            )

    -- Tests for extensions usage which can break Cabal < 1.4.
    checkBuildInfoExtensions :: Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoExtensions :: forall (m :: * -> *). Monad m => BuildInfo -> CheckM m ()
    checkBuildInfoExtensions BuildInfo
    bi = do
      let exts :: [Extension]
    exts = BuildInfo -> [Extension]
    allExtensions BuildInfo
    bi
          extCabal1_2 :: [Extension]
    extCabal1_2 = [Extension] -> [Extension]
    forall a. Eq a => [a] -> [a]
    nub ([Extension] -> [Extension]) -> [Extension] -> [Extension]
    forall a b. (a -> b) -> a -> b
    $ (Extension -> Bool) -> [Extension] -> [Extension]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Extension -> [Extension] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Extension]
    compatExtensionsExtra) [Extension]
    exts
          extCabal1_4 :: [Extension]
    extCabal1_4 = [Extension] -> [Extension]
    forall a. Eq a => [a] -> [a]
    nub ([Extension] -> [Extension]) -> [Extension] -> [Extension]
    forall a b. (a -> b) -> a -> b
    $ (Extension -> Bool) -> [Extension] -> [Extension]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Extension -> [Extension] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [Extension]
    compatExtensions) [Extension]
    exts
      -- As of Cabal-1.4 we can add new extensions without worrying
      -- about breaking old versions of cabal.
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV1_2
        (Bool -> Bool
    not (Bool -> Bool) -> ([Extension] -> Bool) -> [Extension] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Extension] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([Extension] -> Bool) -> [Extension] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [Extension]
    extCabal1_2)
        ( CheckExplanation -> PackageCheck
    PackageDistInexcusable (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $
            CabalSpecVersion -> [Extension] -> CheckExplanation
    CVExtensions CabalSpecVersion
    CabalSpecV1_2 [Extension]
    extCabal1_2
        )
      CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
        CabalSpecVersion
    CabalSpecV1_4
        (Bool -> Bool
    not (Bool -> Bool) -> ([Extension] -> Bool) -> [Extension] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Extension] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([Extension] -> Bool) -> [Extension] -> Bool
    forall a b. (a -> b) -> a -> b
    $ [Extension]
    extCabal1_4)
        ( CheckExplanation -> PackageCheck
    PackageDistInexcusable (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $
            CabalSpecVersion -> [Extension] -> CheckExplanation
    CVExtensions CabalSpecVersion
    CabalSpecV1_4 [Extension]
    extCabal1_4
        )
      where
        -- The known extensions in Cabal-1.2.3
        compatExtensions :: [Extension]
        compatExtensions :: [Extension]
    compatExtensions =
          (KnownExtension -> Extension) -> [KnownExtension] -> [Extension]
    forall a b. (a -> b) -> [a] -> [b]
    map
            KnownExtension -> Extension
    EnableExtension
            [ KnownExtension
    OverlappingInstances
            , KnownExtension
    UndecidableInstances
            , KnownExtension
    IncoherentInstances
            , KnownExtension
    RecursiveDo
            , KnownExtension
    ParallelListComp
            , KnownExtension
    MultiParamTypeClasses
            , KnownExtension
    FunctionalDependencies
            , KnownExtension
    Rank2Types
            , KnownExtension
    RankNTypes
            , KnownExtension
    PolymorphicComponents
            , KnownExtension
    ExistentialQuantification
            , KnownExtension
    ScopedTypeVariables
            , KnownExtension
    ImplicitParams
            , KnownExtension
    FlexibleContexts
            , KnownExtension
    FlexibleInstances
            , KnownExtension
    EmptyDataDecls
            , KnownExtension
    CPP
            , KnownExtension
    BangPatterns
            , KnownExtension
    TypeSynonymInstances
            , KnownExtension
    TemplateHaskell
            , KnownExtension
    ForeignFunctionInterface
            , KnownExtension
    Arrows
            , KnownExtension
    Generics
            , KnownExtension
    NamedFieldPuns
            , KnownExtension
    PatternGuards
            , KnownExtension
    GeneralizedNewtypeDeriving
            , KnownExtension
    ExtensibleRecords
            , KnownExtension
    RestrictedTypeSynonyms
            , KnownExtension
    HereDocuments
            ]
            [Extension] -> [Extension] -> [Extension]
    forall a. [a] -> [a] -> [a]
    ++ (KnownExtension -> Extension) -> [KnownExtension] -> [Extension]
    forall a b. (a -> b) -> [a] -> [b]
    map
              KnownExtension -> Extension
    DisableExtension
              [KnownExtension
    MonomorphismRestriction, KnownExtension
    ImplicitPrelude]
            [Extension] -> [Extension] -> [Extension]
    forall a. [a] -> [a] -> [a]
    ++ [Extension]
    compatExtensionsExtra

        -- The extra known extensions in Cabal-1.2.3 vs Cabal-1.1.6
        -- (Cabal-1.1.6 came with ghc-6.6. Cabal-1.2 came with ghc-6.8)
        compatExtensionsExtra :: [Extension]
        compatExtensionsExtra :: [Extension]
    compatExtensionsExtra =
          (KnownExtension -> Extension) -> [KnownExtension] -> [Extension]
    forall a b. (a -> b) -> [a] -> [b]
    map
            KnownExtension -> Extension
    EnableExtension
            [ KnownExtension
    KindSignatures
            , KnownExtension
    MagicHash
            , KnownExtension
    TypeFamilies
            , KnownExtension
    StandaloneDeriving
            , KnownExtension
    UnicodeSyntax
            , KnownExtension
    PatternSignatures
            , KnownExtension
    UnliftedFFITypes
            , KnownExtension
    LiberalTypeSynonyms
            , KnownExtension
    TypeOperators
            , KnownExtension
    RecordWildCards
            , KnownExtension
    RecordPuns
            , KnownExtension
    DisambiguateRecordFields
            , KnownExtension
    OverloadedStrings
            , KnownExtension
    GADTs
            , KnownExtension
    RelaxedPolyRec
            , KnownExtension
    ExtendedDefaultRules
            , KnownExtension
    UnboxedTuples
            , KnownExtension
    DeriveDataTypeable
            , KnownExtension
    ConstrainedClassMethods
            ]
            [Extension] -> [Extension] -> [Extension]
    forall a. [a] -> [a] -> [a]
    ++ (KnownExtension -> Extension) -> [KnownExtension] -> [Extension]
    forall a b. (a -> b) -> [a] -> [b]
    map
              KnownExtension -> Extension
    DisableExtension
              [KnownExtension
    MonoPatBinds]

    -- Autogenerated modules (Paths_, PackageInfo_) checks. We could pass this
    -- function something more specific than the whole BuildInfo, but it would be
    -- a tuple of [ModuleName] lists, error prone.
    checkAutogenModules
      :: Monad m
      => [ModuleName] -- Additional modules not present
      -- in BuildInfo (e.g. exposed library
      -- modules).
      -> BuildInfo
      -> CheckM m ()
    checkAutogenModules :: forall (m :: * -> *).
    Monad m =>
    [ModuleName] -> BuildInfo -> CheckM m ()
    checkAutogenModules [ModuleName]
    ams BuildInfo
    bi = do
      pkgId <- (CheckCtx m -> PackageIdentifier) -> CheckM m PackageIdentifier
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM (PNames -> PackageIdentifier
    pnPackageId (PNames -> PackageIdentifier)
    -> (CheckCtx m -> PNames) -> CheckCtx m -> PackageIdentifier
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CheckCtx m -> PNames
    forall (m :: * -> *). CheckCtx m -> PNames
    ccNames)
      let
        -- It is an unfortunate reality that autogenPathsModuleName
        -- and autogenPackageInfoModuleName work on PackageDescription
        -- while not needing it all, but just the `package` bit.
        minimalPD = PackageDescription
    emptyPackageDescription{package = pkgId}
        autoPathsName = PackageDescription -> ModuleName
    autogenPathsModuleName PackageDescription
    minimalPD
        autoInfoModuleName = PackageDescription -> ModuleName
    autogenPackageInfoModuleName PackageDescription
    minimalPD

      -- Autogenerated module + some default extension build failure.
      autogenCheck autoPathsName CVAutogenPaths
      rebindableClashCheck autoPathsName RebindableClashPaths

      -- Paths_* module + some default extension build failure.
      autogenCheck autoInfoModuleName CVAutogenPackageInfo
      rebindableClashCheck autoInfoModuleName RebindableClashPackageInfo

      -- PackageInfo_* module + cabal-version < 3.12
      -- See Mikolaj’s comments on #9481 on why this has to be
      -- PackageBuildImpossible and not merely PackageDistInexcusable.
      checkSpecVer
        CabalSpecV3_12
        (elem autoInfoModuleName allModsForAuto)
        (PackageBuildImpossible CVAutogenPackageInfoGuard)
      where
        allModsForAuto :: [ModuleName]
        allModsForAuto :: [ModuleName]
    allModsForAuto = [ModuleName]
    ams [ModuleName] -> [ModuleName] -> [ModuleName]
    forall a. [a] -> [a] -> [a]
    ++ BuildInfo -> [ModuleName]
    otherModules BuildInfo
    bi

        autogenCheck
          :: Monad m
          => ModuleName
          -> CheckExplanation
          -> CheckM m ()
        autogenCheck :: forall (m :: * -> *).
    Monad m =>
    ModuleName -> CheckExplanation -> CheckM m ()
    autogenCheck ModuleName
    name CheckExplanation
    warning = do
          sv <- (CheckCtx m -> CabalSpecVersion) -> CheckM m CabalSpecVersion
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM CheckCtx m -> CabalSpecVersion
    forall (m :: * -> *). CheckCtx m -> CabalSpecVersion
    ccSpecVersion
          checkP
            ( sv >= CabalSpecV2_0
                && elem name allModsForAuto
                && notElem name (autogenModules bi)
            )
            (PackageDistInexcusable warning)

        rebindableClashCheck
          :: Monad m
          => ModuleName
          -> CheckExplanation
          -> CheckM m ()
        rebindableClashCheck :: forall (m :: * -> *).
    Monad m =>
    ModuleName -> CheckExplanation -> CheckM m ()
    rebindableClashCheck ModuleName
    name CheckExplanation
    warning = do
          CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    CabalSpecVersion -> Bool -> PackageCheck -> CheckM m ()
    checkSpecVer
            CabalSpecVersion
    CabalSpecV2_2
            ( ( ModuleName
    name ModuleName -> [ModuleName] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` BuildInfo -> [ModuleName]
    otherModules BuildInfo
    bi
                  Bool -> Bool -> Bool
    || ModuleName
    name ModuleName -> [ModuleName] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` BuildInfo -> [ModuleName]
    autogenModules BuildInfo
    bi
              )
                Bool -> Bool -> Bool
    && Bool
    checkExts
            )
            (CheckExplanation -> PackageCheck
    PackageBuildImpossible CheckExplanation
    warning)

        -- Do we have some peculiar extensions active which would interfere
        -- (cabal-version <2.2) with Paths_modules?
        checkExts :: Bool
        checkExts :: Bool
    checkExts =
          let exts :: [Extension]
    exts = BuildInfo -> [Extension]
    defaultExtensions BuildInfo
    bi
           in Extension
    rebind Extension -> [Extension] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Extension]
    exts
                Bool -> Bool -> Bool
    && (Extension
    strings Extension -> [Extension] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Extension]
    exts Bool -> Bool -> Bool
    || Extension
    lists Extension -> [Extension] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Extension]
    exts)
          where
            rebind :: Extension
    rebind = KnownExtension -> Extension
    EnableExtension KnownExtension
    RebindableSyntax
            strings :: Extension
    strings = KnownExtension -> Extension
    EnableExtension KnownExtension
    OverloadedStrings
            lists :: Extension
    lists = KnownExtension -> Extension
    EnableExtension KnownExtension
    OverloadedLists

    checkLocalPathExist
      :: Monad m
      => String -- .cabal field where we found the error.
      -> FilePath
      -> CheckM m ()
    checkLocalPathExist :: forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> CheckM m ()
    checkLocalPathExist FilePath
    title FilePath
    dir =
      (CheckPackageContentOps m -> m Bool) -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    (CheckPackageContentOps m -> m Bool) -> PackageCheck -> CheckM m ()
    checkPkg
        ( \CheckPackageContentOps m
    ops -> do
            dn <- Bool -> Bool
    not (Bool -> Bool) -> m Bool -> m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CheckPackageContentOps m -> FilePath -> m Bool
    forall (m :: * -> *).
    CheckPackageContentOps m -> FilePath -> m Bool
    doesDirectoryExist CheckPackageContentOps m
    ops FilePath
    dir
            let rp = Bool -> Bool
    not (FilePath -> Bool
    isAbsoluteOnAnyPlatform FilePath
    dir)
            return (rp && dn)
        )
        (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> FilePath -> CheckExplanation
    UnknownDirectory FilePath
    title FilePath
    dir)

    -- PVP --

    -- Sometimes we read (or end up with) “straddle” deps declarations
    -- like this:
    --
    --     build-depends: base > 3, base < 4
    --
    -- `mergeDependencies` reduces that to base > 3 && < 4, _while_ maintaining
    -- dependencies order in the list (better UX).
    mergeDependencies :: [Dependency] -> [Dependency]
    mergeDependencies :: [Dependency] -> [Dependency]
    mergeDependencies [] = []
    mergeDependencies l :: [Dependency]
    l@(Dependency
    d : [Dependency]
    _) =
      let ([Dependency]
    sames, [Dependency]
    diffs) = (Dependency -> Bool)
    -> [Dependency] -> ([Dependency], [Dependency])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition ((FilePath -> FilePath -> Bool
    forall a. Eq a => a -> a -> Bool
    == Dependency -> FilePath
    depName Dependency
    d) (FilePath -> Bool)
    -> (Dependency -> FilePath) -> Dependency -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Dependency -> FilePath
    depName) [Dependency]
    l
          merged :: Dependency
    merged =
            PackageName
    -> VersionRange -> NonEmptySet LibraryName -> Dependency
    Dependency
              (Dependency -> PackageName
    depPkgName Dependency
    d)
              ( (VersionRange -> VersionRange -> VersionRange)
    -> VersionRange -> [VersionRange] -> VersionRange
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl VersionRange -> VersionRange -> VersionRange
    intersectVersionRanges VersionRange
    anyVersion ([VersionRange] -> VersionRange) -> [VersionRange] -> VersionRange
    forall a b. (a -> b) -> a -> b
    $
                  (Dependency -> VersionRange) -> [Dependency] -> [VersionRange]
    forall a b. (a -> b) -> [a] -> [b]
    map Dependency -> VersionRange
    depVerRange [Dependency]
    sames
              )
              (Dependency -> NonEmptySet LibraryName
    depLibraries Dependency
    d)
       in Dependency
    merged Dependency -> [Dependency] -> [Dependency]
    forall a. a -> [a] -> [a]
    : [Dependency] -> [Dependency]
    mergeDependencies [Dependency]
    diffs
      where
        depName :: Dependency -> String
        depName :: Dependency -> FilePath
    depName Dependency
    wd = PackageName -> FilePath
    unPackageName (PackageName -> FilePath)
    -> (Dependency -> PackageName) -> Dependency -> FilePath
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Dependency -> PackageName
    depPkgName (Dependency -> FilePath) -> Dependency -> FilePath
    forall a b. (a -> b) -> a -> b
    $ Dependency
    wd

    -- Is this an internal target? We do not perform PVP checks on those,
    -- see https://github.com/haskell/cabal/pull/8361#issuecomment-1577547091
    isInternalTarget :: CEType -> Bool
    isInternalTarget :: CEType -> Bool
    isInternalTarget (CETLibrary{}) = Bool
    False
    isInternalTarget (CETForeignLibrary{}) = Bool
    False
    isInternalTarget (CETExecutable{}) = Bool
    False
    isInternalTarget (CETTest{}) = Bool
    True
    isInternalTarget (CETBenchmark{}) = Bool
    True
    isInternalTarget (CETSetup{}) = Bool
    False

    -- ------------------------------------------------------------
    -- Options
    -- ------------------------------------------------------------

    -- Target type for option checking.
    data BITarget = BITLib | BITTestBench | BITOther
      deriving (BITarget -> BITarget -> Bool
    (BITarget -> BITarget -> Bool)
    -> (BITarget -> BITarget -> Bool) -> Eq BITarget
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: BITarget -> BITarget -> Bool
    == :: BITarget -> BITarget -> Bool
    $c/= :: BITarget -> BITarget -> Bool
    /= :: BITarget -> BITarget -> Bool
    Eq, Int -> BITarget -> FilePath -> FilePath
    [BITarget] -> FilePath -> FilePath
    BITarget -> FilePath
    (Int -> BITarget -> FilePath -> FilePath)
    -> (BITarget -> FilePath)
    -> ([BITarget] -> FilePath -> FilePath)
    -> Show BITarget
    forall a.
    (Int -> a -> FilePath -> FilePath)
    -> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
    $cshowsPrec :: Int -> BITarget -> FilePath -> FilePath
    showsPrec :: Int -> BITarget -> FilePath -> FilePath
    $cshow :: BITarget -> FilePath
    show :: BITarget -> FilePath
    $cshowList :: [BITarget] -> FilePath -> FilePath
    showList :: [BITarget] -> FilePath -> FilePath
    Show)

    cet2bit :: CEType -> BITarget
    cet2bit :: CEType -> BITarget
    cet2bit (CETLibrary{}) = BITarget
    BITLib
    cet2bit (CETForeignLibrary{}) = BITarget
    BITLib
    cet2bit (CETExecutable{}) = BITarget
    BITOther
    cet2bit (CETTest{}) = BITarget
    BITTestBench
    cet2bit (CETBenchmark{}) = BITarget
    BITTestBench
    cet2bit CEType
    CETSetup = BITarget
    BITOther

    -- General check on all options (ghc, C, C++, …) for common inaccuracies.
    checkBuildInfoOptions :: Monad m => BITarget -> BuildInfo -> CheckM m ()
    checkBuildInfoOptions :: forall (m :: * -> *).
    Monad m =>
    BITarget -> BuildInfo -> CheckM m ()
    checkBuildInfoOptions BITarget
    t BuildInfo
    bi = do
      FilePath -> BITarget -> [FilePath] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> BITarget -> [FilePath] -> CheckM m ()
    checkGHCOptions FilePath
    "ghc-options" BITarget
    t (CompilerFlavor -> BuildInfo -> [FilePath]
    hcOptions CompilerFlavor
    GHC BuildInfo
    bi)
      FilePath -> BITarget -> [FilePath] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> BITarget -> [FilePath] -> CheckM m ()
    checkGHCOptions FilePath
    "ghc-prof-options" BITarget
    t (CompilerFlavor -> BuildInfo -> [FilePath]
    hcProfOptions CompilerFlavor
    GHC BuildInfo
    bi)
      FilePath -> BITarget -> [FilePath] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> BITarget -> [FilePath] -> CheckM m ()
    checkGHCOptions FilePath
    "ghc-shared-options" BITarget
    t (CompilerFlavor -> BuildInfo -> [FilePath]
    hcSharedOptions CompilerFlavor
    GHC BuildInfo
    bi)
      let ldOpts :: [FilePath]
    ldOpts = BuildInfo -> [FilePath]
    ldOptions BuildInfo
    bi
      WarnLang -> FilePath -> [FilePath] -> [FilePath] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    WarnLang -> FilePath -> [FilePath] -> [FilePath] -> CheckM m ()
    checkCLikeOptions WarnLang
    LangC FilePath
    "cc-options" (BuildInfo -> [FilePath]
    ccOptions BuildInfo
    bi) [FilePath]
    ldOpts
      WarnLang -> FilePath -> [FilePath] -> [FilePath] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    WarnLang -> FilePath -> [FilePath] -> [FilePath] -> CheckM m ()
    checkCLikeOptions WarnLang
    LangCPlusPlus FilePath
    "cxx-options" (BuildInfo -> [FilePath]
    cxxOptions BuildInfo
    bi) [FilePath]
    ldOpts
      [FilePath] -> CheckM m ()
    forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCPPOptions (BuildInfo -> [FilePath]
    cppOptions BuildInfo
    bi)

    -- | Checks GHC options for commonly misused or non-portable flags.
    checkGHCOptions
      :: Monad m
      => CabalField -- .cabal field name where we found the error.
      -> BITarget -- Target type.
      -> [String] -- Options (alas in String form).
      -> CheckM m ()
    checkGHCOptions :: forall (m :: * -> *).
    Monad m =>
    FilePath -> BITarget -> [FilePath] -> CheckM m ()
    checkGHCOptions FilePath
    title BITarget
    t [FilePath]
    opts = do
      CheckM m ()
    checkGeneral
      case BITarget
    t of
        BITarget
    BITLib -> [CheckM m ()] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, Monad m) =>
    t (m a) -> m ()
    sequence_ [CheckM m ()
    checkLib, CheckM m ()
    checkNonTestBench]
        BITarget
    BITTestBench -> CheckM m ()
    checkTestBench
        BITarget
    BITOther -> CheckM m ()
    checkNonTestBench
      where
        checkFlags :: Monad m => [String] -> PackageCheck -> CheckM m ()
        checkFlags :: forall (m :: * -> *).
    Monad m =>
    [FilePath] -> PackageCheck -> CheckM m ()
    checkFlags [FilePath]
    fs PackageCheck
    ck = Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP ((FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [FilePath]
    fs) [FilePath]
    opts) PackageCheck
    ck

        checkFlagsP
          :: Monad m
          => (String -> Bool)
          -> (String -> PackageCheck)
          -> CheckM m ()
        checkFlagsP :: forall (m :: * -> *).
    Monad m =>
    (FilePath -> Bool) -> (FilePath -> PackageCheck) -> CheckM m ()
    checkFlagsP FilePath -> Bool
    p FilePath -> PackageCheck
    ckc =
          case (FilePath -> Bool) -> [FilePath] -> [FilePath]
    forall a. (a -> Bool) -> [a] -> [a]
    filter FilePath -> Bool
    p [FilePath]
    opts of
            [] -> () -> CheckM m ()
    forall a. a -> CheckM m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            (FilePath
    _ : [FilePath]
    _) -> PackageCheck -> CheckM m ()
    forall (m :: * -> *). Monad m => PackageCheck -> CheckM m ()
    tellP (FilePath -> PackageCheck
    ckc FilePath
    title)

        checkGeneral :: CheckM m ()
    checkGeneral = do
          [FilePath] -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    [FilePath] -> PackageCheck -> CheckM m ()
    checkFlags
            [FilePath
    "-fasm"]
            (CheckExplanation -> PackageCheck
    PackageDistInexcusable (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptFasm FilePath
    title)
          [FilePath] -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    [FilePath] -> PackageCheck -> CheckM m ()
    checkFlags
            [FilePath
    "-fhpc"]
            (CheckExplanation -> PackageCheck
    PackageDistInexcusable (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptHpc FilePath
    title)
          [FilePath] -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    [FilePath] -> PackageCheck -> CheckM m ()
    checkFlags
            [FilePath
    "-prof"]
            (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptProf FilePath
    title)
          -- Does not apply to scripts.
          -- Why do we need this? See #8963.
          pid <- (CheckCtx m -> PackageIdentifier) -> CheckM m PackageIdentifier
    forall (m :: * -> *) a. Monad m => (CheckCtx m -> a) -> CheckM m a
    asksCM (PNames -> PackageIdentifier
    pnPackageId (PNames -> PackageIdentifier)
    -> (CheckCtx m -> PNames) -> CheckCtx m -> PackageIdentifier
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CheckCtx m -> PNames
    forall (m :: * -> *). CheckCtx m -> PNames
    ccNames)
          unless (pid == fakePackageId) $
            checkFlags
              ["-o"]
              (PackageBuildWarning $ OptO title)
          checkFlags
            ["-hide-package"]
            (PackageBuildWarning $ OptHide title)
          checkFlags
            ["--make"]
            (PackageBuildWarning $ OptMake title)
          checkFlags
            ["-O", "-O1"]
            (PackageDistInexcusable $ OptOOne title)
          checkFlags
            ["-O2"]
            (PackageDistSuspiciousWarn $ OptOTwo title)
          checkFlags
            ["-split-sections"]
            (PackageBuildWarning $ OptSplitSections title)
          checkFlags
            ["-split-objs"]
            (PackageBuildWarning $ OptSplitObjs title)
          checkFlags
            ["-optl-Wl,-s", "-optl-s"]
            (PackageDistInexcusable $ OptWls title)
          checkFlags
            ["-fglasgow-exts"]
            (PackageDistSuspicious $ OptExts title)
          let ghcNoRts = [FilePath] -> [FilePath]
    rmRtsOpts [FilePath]
    opts
          checkAlternatives
            title
            "default-extensions"
            [ (flag, prettyShow extension)
            | flag <- ghcNoRts
            , Just extension <- [ghcExtension flag]
            ]
          checkAlternatives
            title
            "default-extensions"
            [ (flag, extension)
            | flag@('-' : 'X' : extension) <- ghcNoRts
            ]
          checkAlternatives
            title
            "cpp-options"
            ( [(flag, flag) | flag@('-' : 'D' : _) <- ghcNoRts]
                ++ [(flag, flag) | flag@('-' : 'U' : _) <- ghcNoRts]
            )
          checkAlternatives
            title
            "include-dirs"
            [(flag, dir) | flag@('-' : 'I' : dir) <- ghcNoRts]
          checkAlternatives
            title
            "extra-libraries"
            [(flag, lib) | flag@('-' : 'l' : lib) <- ghcNoRts]
          checkAlternatives
            title
            "extra-libraries-static"
            [(flag, lib) | flag@('-' : 'l' : lib) <- ghcNoRts]
          checkAlternatives
            title
            "extra-lib-dirs"
            [(flag, dir) | flag@('-' : 'L' : dir) <- ghcNoRts]
          checkAlternatives
            title
            "extra-lib-dirs-static"
            [(flag, dir) | flag@('-' : 'L' : dir) <- ghcNoRts]
          checkAlternatives
            title
            "frameworks"
            [ (flag, fmwk)
            | (flag@"-framework", fmwk) <-
                zip ghcNoRts (safeTail ghcNoRts)
            ]
          checkAlternatives
            title
            "extra-framework-dirs"
            [ (flag, dir)
            | (flag@"-framework-path", dir) <-
                zip ghcNoRts (safeTail ghcNoRts)
            ]
          -- Old `checkDevelopmentOnlyFlagsOptions` section
          checkFlags
            ["-Werror"]
            (PackageDistInexcusable $ WErrorUnneeded title)
          checkFlags
            ["-fdefer-type-errors"]
            (PackageDistInexcusable $ FDeferTypeErrorsUnneeded title)
          checkFlags
            [ "-fprof-auto"
            , "-fprof-auto-top"
            , "-fprof-auto-calls"
            , "-fprof-cafs"
            , "-fno-prof-count-entries"
            , "-auto-all"
            , "-auto"
            , "-caf-all"
            ]
            (PackageDistSuspicious $ ProfilingUnneeded title)
          checkFlagsP
            ( \FilePath
    opt ->
                FilePath
    "-d" FilePath -> FilePath -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` FilePath
    opt
                  Bool -> Bool -> Bool
    && FilePath
    opt FilePath -> FilePath -> Bool
    forall a. Eq a => a -> a -> Bool
    /= FilePath
    "-dynamic"
            )
            (PackageDistInexcusable . DynamicUnneeded)
          checkFlagsP
            ( \FilePath
    opt -> case FilePath
    opt of
                FilePath
    "-j" -> Bool
    True
                (Char
    '-' : Char
    'j' : Char
    d : FilePath
    _) -> Char -> Bool
    isDigit Char
    d
                FilePath
    _ -> Bool
    False
            )
            (PackageDistInexcusable . JUnneeded)

        checkLib :: CheckM m ()
    checkLib = do
          Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
            (FilePath
    "-rtsopts" FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [FilePath]
    opts)
            (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptRts FilePath
    title)
          Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
            ((FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (\FilePath
    opt -> FilePath
    "-with-rtsopts" FilePath -> FilePath -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` FilePath
    opt) [FilePath]
    opts)
            (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptWithRts FilePath
    title)

        checkTestBench :: CheckM m ()
    checkTestBench = do
          [FilePath] -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    [FilePath] -> PackageCheck -> CheckM m ()
    checkFlags
            [FilePath
    "-O0", FilePath
    "-Onot"]
            (CheckExplanation -> PackageCheck
    PackageDistSuspiciousWarn (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptONot FilePath
    title)

        checkNonTestBench :: CheckM m ()
    checkNonTestBench = do
          [FilePath] -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    [FilePath] -> PackageCheck -> CheckM m ()
    checkFlags
            [FilePath
    "-O0", FilePath
    "-Onot"]
            (CheckExplanation -> PackageCheck
    PackageDistSuspicious (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> CheckExplanation
    OptONot FilePath
    title)

        ghcExtension :: FilePath -> Maybe Extension
    ghcExtension (Char
    '-' : Char
    'f' : FilePath
    name) = case FilePath
    name of
          FilePath
    "allow-overlapping-instances" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    OverlappingInstances
          FilePath
    "no-allow-overlapping-instances" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    OverlappingInstances
          FilePath
    "th" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    TemplateHaskell
          FilePath
    "no-th" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    TemplateHaskell
          FilePath
    "ffi" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    ForeignFunctionInterface
          FilePath
    "no-ffi" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    ForeignFunctionInterface
          FilePath
    "fi" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    ForeignFunctionInterface
          FilePath
    "no-fi" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    ForeignFunctionInterface
          FilePath
    "monomorphism-restriction" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    MonomorphismRestriction
          FilePath
    "no-monomorphism-restriction" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    MonomorphismRestriction
          FilePath
    "mono-pat-binds" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    MonoPatBinds
          FilePath
    "no-mono-pat-binds" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    MonoPatBinds
          FilePath
    "allow-undecidable-instances" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    UndecidableInstances
          FilePath
    "no-allow-undecidable-instances" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    UndecidableInstances
          FilePath
    "allow-incoherent-instances" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    IncoherentInstances
          FilePath
    "no-allow-incoherent-instances" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    IncoherentInstances
          FilePath
    "arrows" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    Arrows
          FilePath
    "no-arrows" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    Arrows
          FilePath
    "generics" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    Generics
          FilePath
    "no-generics" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    Generics
          FilePath
    "implicit-prelude" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    ImplicitPrelude
          FilePath
    "no-implicit-prelude" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    ImplicitPrelude
          FilePath
    "implicit-params" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    ImplicitParams
          FilePath
    "no-implicit-params" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    ImplicitParams
          FilePath
    "bang-patterns" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    BangPatterns
          FilePath
    "no-bang-patterns" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    BangPatterns
          FilePath
    "scoped-type-variables" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    ScopedTypeVariables
          FilePath
    "no-scoped-type-variables" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    ScopedTypeVariables
          FilePath
    "extended-default-rules" -> KnownExtension -> Maybe Extension
    enable KnownExtension
    ExtendedDefaultRules
          FilePath
    "no-extended-default-rules" -> KnownExtension -> Maybe Extension
    disable KnownExtension
    ExtendedDefaultRules
          FilePath
    _ -> Maybe Extension
    forall a. Maybe a
    Nothing
        ghcExtension FilePath
    "-cpp" = KnownExtension -> Maybe Extension
    enable KnownExtension
    CPP
        ghcExtension FilePath
    _ = Maybe Extension
    forall a. Maybe a
    Nothing

        enable :: KnownExtension -> Maybe Extension
    enable KnownExtension
    e = Extension -> Maybe Extension
    forall a. a -> Maybe a
    Just (KnownExtension -> Extension
    EnableExtension KnownExtension
    e)
        disable :: KnownExtension -> Maybe Extension
    disable KnownExtension
    e = Extension -> Maybe Extension
    forall a. a -> Maybe a
    Just (KnownExtension -> Extension
    DisableExtension KnownExtension
    e)

        rmRtsOpts :: [String] -> [String]
        rmRtsOpts :: [FilePath] -> [FilePath]
    rmRtsOpts (FilePath
    "-with-rtsopts" : FilePath
    _ : [FilePath]
    xs) = [FilePath] -> [FilePath]
    rmRtsOpts [FilePath]
    xs
        rmRtsOpts (FilePath
    x : [FilePath]
    xs) = FilePath
    x FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : [FilePath] -> [FilePath]
    rmRtsOpts [FilePath]
    xs
        rmRtsOpts [] = []

    checkCLikeOptions
      :: Monad m
      => WarnLang -- Language we are warning about (C or C++).
      -> CabalField -- Field where we found the error.
      -> [String] -- Options in string form.
      -> [String] -- Link options in String form.
      -> CheckM m ()
    checkCLikeOptions :: forall (m :: * -> *).
    Monad m =>
    WarnLang -> FilePath -> [FilePath] -> [FilePath] -> CheckM m ()
    checkCLikeOptions WarnLang
    label FilePath
    prefix [FilePath]
    opts [FilePath]
    ldOpts = do
      FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives
        FilePath
    prefix
        FilePath
    "include-dirs"
        [(FilePath
    flag, FilePath
    dir) | flag :: FilePath
    flag@(Char
    '-' : Char
    'I' : FilePath
    dir) <- [FilePath]
    opts]
      FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives
        FilePath
    prefix
        FilePath
    "extra-libraries"
        [(FilePath
    flag, FilePath
    lib) | flag :: FilePath
    flag@(Char
    '-' : Char
    'l' : FilePath
    lib) <- [FilePath]
    opts]
      FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives
        FilePath
    prefix
        FilePath
    "extra-lib-dirs"
        [(FilePath
    flag, FilePath
    dir) | flag :: FilePath
    flag@(Char
    '-' : Char
    'L' : FilePath
    dir) <- [FilePath]
    opts]

      FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives
        FilePath
    "ld-options"
        FilePath
    "extra-libraries"
        [(FilePath
    flag, FilePath
    lib) | flag :: FilePath
    flag@(Char
    '-' : Char
    'l' : FilePath
    lib) <- [FilePath]
    ldOpts]
      FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives
        FilePath
    "ld-options"
        FilePath
    "extra-lib-dirs"
        [(FilePath
    flag, FilePath
    dir) | flag :: FilePath
    flag@(Char
    '-' : Char
    'L' : FilePath
    dir) <- [FilePath]
    ldOpts]

      Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
        ((FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (FilePath -> [FilePath] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [FilePath
    "-O", FilePath
    "-Os", FilePath
    "-O0", FilePath
    "-O1", FilePath
    "-O2", FilePath
    "-O3"]) [FilePath]
    opts)
        (CheckExplanation -> PackageCheck
    PackageDistSuspicious (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> WarnLang -> CheckExplanation
    COptONumber FilePath
    prefix WarnLang
    label)

    checkAlternatives
      :: Monad m
      => CabalField -- Wrong field.
      -> CabalField -- Appropriate field.
      -> [(String, String)] -- List of good and bad flags.
      -> CheckM m ()
    checkAlternatives :: forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives FilePath
    badField FilePath
    goodField [(FilePath, FilePath)]
    flags = do
      let ([FilePath]
    badFlags, [FilePath]
    _) = [(FilePath, FilePath)] -> ([FilePath], [FilePath])
    forall a b. [(a, b)] -> ([a], [b])
    unzip [(FilePath, FilePath)]
    flags
      Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
        (Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ [FilePath] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [FilePath]
    badFlags)
        (CheckExplanation -> PackageCheck
    PackageBuildWarning (CheckExplanation -> PackageCheck)
    -> CheckExplanation -> PackageCheck
    forall a b. (a -> b) -> a -> b
    $ FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckExplanation
    OptAlternatives FilePath
    badField FilePath
    goodField [(FilePath, FilePath)]
    flags)

    checkCPPOptions
      :: Monad m
      => [String] -- Options in String form.
      -> CheckM m ()
    checkCPPOptions :: forall (m :: * -> *). Monad m => [FilePath] -> CheckM m ()
    checkCPPOptions [FilePath]
    opts = do
      FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    FilePath -> FilePath -> [(FilePath, FilePath)] -> CheckM m ()
    checkAlternatives
        FilePath
    "cpp-options"
        FilePath
    "include-dirs"
        [(FilePath
    flag, FilePath
    dir) | flag :: FilePath
    flag@(Char
    '-' : Char
    'I' : FilePath
    dir) <- [FilePath]
    opts]
      (FilePath -> CheckM m ()) -> [FilePath] -> CheckM m ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_
        ( \FilePath
    opt ->
            Bool -> PackageCheck -> CheckM m ()
    forall (m :: * -> *).
    Monad m =>
    Bool -> PackageCheck -> CheckM m ()
    checkP
              (Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (FilePath -> FilePath -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` FilePath
    opt) [FilePath
    "-D", FilePath
    "-U", FilePath
    "-I"])
              (CheckExplanation -> PackageCheck
    PackageBuildWarning (FilePath -> CheckExplanation
    COptCPP FilePath
    opt))
        )
        [FilePath]
    opts