summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuras Shumovich <shumovichy@gmail.com>2019-01-20 19:49:56 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-06-11 18:39:58 -0400
commitfe7e7e4a950a77326cc16f4ade30a67d20d7cdd5 (patch)
tree49e25ca769f6a66240c5960a59a411175a7241d7
parente5d275f45677ed89df310754973a15c522dc1003 (diff)
downloadhaskell-fe7e7e4a950a77326cc16f4ade30a67d20d7cdd5.tar.gz
Warn about unused packages
Reviewers: bgamari, simonpj Reviewed By: simonpj Subscribers: hvr, simonpj, mpickering, rwbarton, carter GHC Trac Issues: #15838 Differential Revision: https://phabricator.haskell.org/D5285
-rw-r--r--compiler/main/DynFlags.hs4
-rw-r--r--compiler/main/GhcMake.hs70
-rw-r--r--docs/users_guide/8.8.1-notes.rst2
-rw-r--r--docs/users_guide/using-warnings.rst15
-rw-r--r--testsuite/tests/warnings/should_compile/UnusedPackages.hs5
-rw-r--r--testsuite/tests/warnings/should_compile/UnusedPackages.stderr6
-rw-r--r--testsuite/tests/warnings/should_compile/all.T2
7 files changed, 102 insertions, 2 deletions
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 91bf627aaa..5217fced5f 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -911,6 +911,7 @@ data WarningFlag =
| Opt_WarnSpaceAfterBang
| Opt_WarnMissingDerivingStrategies -- Since 8.8
| Opt_WarnPrepositiveQualifiedModule -- Since TBD
+ | Opt_WarnUnusedPackages -- Since 8.10
deriving (Eq, Show, Enum)
data Language = Haskell98 | Haskell2010
@@ -4110,7 +4111,8 @@ wWarningFlagsDeps = [
flagSpec "missing-space-after-bang" Opt_WarnSpaceAfterBang,
flagSpec "partial-fields" Opt_WarnPartialFields,
flagSpec "prepositive-qualified-module"
- Opt_WarnPrepositiveQualifiedModule
+ Opt_WarnPrepositiveQualifiedModule,
+ flagSpec "unused-packages" Opt_WarnUnusedPackages
]
-- | These @-\<blah\>@ flags can all be reversed with @-no-\<blah\>@
diff --git a/compiler/main/GhcMake.hs b/compiler/main/GhcMake.hs
index a748cc668b..491504d3bd 100644
--- a/compiler/main/GhcMake.hs
+++ b/compiler/main/GhcMake.hs
@@ -267,7 +267,75 @@ data LoadHowMuch
load :: GhcMonad m => LoadHowMuch -> m SuccessFlag
load how_much = do
mod_graph <- depanal [] False
- load' how_much (Just batchMsg) mod_graph
+ success <- load' how_much (Just batchMsg) mod_graph
+ warnUnusedPackages
+ pure success
+
+-- Note [Unused packages]
+--
+-- Cabal passes `--package-id` flag for each direct dependency. But GHC
+-- loads them lazily, so when compilation is done, we have a list of all
+-- actually loaded packages. All the packages, specified on command line,
+-- but never loaded, are probably unused dependencies.
+
+warnUnusedPackages :: GhcMonad m => m ()
+warnUnusedPackages = do
+ hsc_env <- getSession
+ eps <- liftIO $ hscEPS hsc_env
+
+ let dflags = hsc_dflags hsc_env
+ pit = eps_PIT eps
+
+ let loadedPackages
+ = map (getPackageDetails dflags)
+ . nub . sort
+ . map moduleUnitId
+ . moduleEnvKeys
+ $ pit
+
+ requestedArgs = mapMaybe packageArg (packageFlags dflags)
+
+ unusedArgs
+ = filter (\arg -> not $ any (matching dflags arg) loadedPackages)
+ requestedArgs
+
+ let warn = makeIntoWarning
+ (Reason Opt_WarnUnusedPackages)
+ (mkPlainErrMsg dflags noSrcSpan msg)
+ msg = hang
+ ( text "The following packages were specified "
+ <> text "via -package or -package-id flags, "
+ <> text "but were not needed for compilation: ")
+ 4
+ (sep (map pprUnusedArg unusedArgs))
+
+ when (wopt Opt_WarnUnusedPackages dflags && not (null unusedArgs)) $
+ logWarnings (listToBag [warn])
+
+ where
+ packageArg (ExposePackage _ arg _) = Just arg
+ packageArg _ = Nothing
+
+ pprUnusedArg (PackageArg str) = text str
+ pprUnusedArg (UnitIdArg uid) = ppr uid
+
+ matchingStr :: String -> PackageConfig -> Bool
+ matchingStr str p
+ = str == sourcePackageIdString p
+ || str == packageNameString p
+
+ matching :: DynFlags -> PackageArg -> PackageConfig -> Bool
+ matching _ (PackageArg str) p = matchingStr str p
+ matching dflags (UnitIdArg uid) p = uid == realUnitId dflags p
+
+ -- For wired-in packages, we have to unwire their id,
+ -- otherwise they won't match package flags
+ realUnitId :: DynFlags -> PackageConfig -> UnitId
+ realUnitId dflags
+ = unwireUnitId dflags
+ . DefiniteUnitId
+ . DefUnitId
+ . installedPackageConfigId
-- | Generalized version of 'load' which also supports a custom
-- 'Messager' (for reporting progress) and 'ModuleGraph' (generally
diff --git a/docs/users_guide/8.8.1-notes.rst b/docs/users_guide/8.8.1-notes.rst
index a781ec4181..972e4c0446 100644
--- a/docs/users_guide/8.8.1-notes.rst
+++ b/docs/users_guide/8.8.1-notes.rst
@@ -102,6 +102,8 @@ Compiler
- The :ghc-flag:`-Wcompat` warning group now includes :ghc-flag:`-Wstar-is-type`.
+- New :ghc-flag:`-Wunused-packages` warning reports unused packages.
+
- The :ghc-flag:`-fllvm-pass-vectors-in-regs` flag is now deprecated as vector
arguments are now passed in registers by default.
diff --git a/docs/users_guide/using-warnings.rst b/docs/users_guide/using-warnings.rst
index ab61da936a..dda7bb656c 100644
--- a/docs/users_guide/using-warnings.rst
+++ b/docs/users_guide/using-warnings.rst
@@ -1683,6 +1683,21 @@ of ``-W(no-)*``.
data Foo = Foo { f :: Int } | Bar
+.. ghc-flag:: -Wunused-packages
+ :shortdesc: warn when package is requested on command line, but was never loaded.
+ :type: dynamic
+ :reverse: -Wno-unused-packages
+ :category:
+
+ :since: 8.8
+
+ The option :ghc-flag:`-Wunused-packages` warns about packages, specified on
+ command line via :ghc-flag:`-package` or :ghc-flag:`-package-id`, but were not
+ loaded during compication. Usually it means that you have an unused dependency.
+
+ You may want to enable this warning on a clean build or enable :ghc-flag:`-fforce-recomp`
+ in order to get reliable results.
+
If you're feeling really paranoid, the :ghc-flag:`-dcore-lint` option is a good choice.
It turns on heavyweight intra-pass sanity-checking within GHC. (It checks GHC's
sanity, not yours.)
diff --git a/testsuite/tests/warnings/should_compile/UnusedPackages.hs b/testsuite/tests/warnings/should_compile/UnusedPackages.hs
new file mode 100644
index 0000000000..ef70dbb084
--- /dev/null
+++ b/testsuite/tests/warnings/should_compile/UnusedPackages.hs
@@ -0,0 +1,5 @@
+module Main
+where
+
+main :: IO ()
+main = return ()
diff --git a/testsuite/tests/warnings/should_compile/UnusedPackages.stderr b/testsuite/tests/warnings/should_compile/UnusedPackages.stderr
new file mode 100644
index 0000000000..7660287aa8
--- /dev/null
+++ b/testsuite/tests/warnings/should_compile/UnusedPackages.stderr
@@ -0,0 +1,6 @@
+[1 of 1] Compiling Main ( UnusedPackages.hs, UnusedPackages.o )
+Linking UnusedPackages ...
+
+<no location info>: warning: [-Wunused-packages]
+ The following packages were specified via -package or -package-id flags, but were not needed for compilation:
+ bytestring
diff --git a/testsuite/tests/warnings/should_compile/all.T b/testsuite/tests/warnings/should_compile/all.T
index fcf03443d3..55dee873ae 100644
--- a/testsuite/tests/warnings/should_compile/all.T
+++ b/testsuite/tests/warnings/should_compile/all.T
@@ -27,3 +27,5 @@ test('T16551', [extra_files(['T16551/'])], multimod_compile, ['T16551/A.hs T1655
test('StarBinder', normal, compile, [''])
test('Overflow', normal, compile, [''])
+
+test('UnusedPackages', normal, multimod_compile, ['UnusedPackages.hs', '-package=bytestring -package=base -Wunused-packages'])