-
- unused_imports :: [GlobalRdrElt]
- unused_imports = filter unused_imp defined_but_not_used
- unused_imp (GRE {gre_prov = Imported imp_specs})
- = not (all (module_unused . importSpecModule) imp_specs)
- && or [exp | ImpSpec { is_item = ImpSome { is_explicit = exp } } <- imp_specs]
- -- Don't complain about unused imports if we've already said the
- -- entire import is unused
- unused_imp other = False
-
- -- To figure out the minimal set of imports, start with the things
- -- that are in scope (i.e. in gbl_env). Then just combine them
- -- into a bunch of avails, so they are properly grouped
- --
- -- BUG WARNING: this does not deal properly with qualified imports!
- minimal_imports :: FiniteMap ModuleName AvailEnv
- minimal_imports0 = foldr add_expall emptyFM expall_mods
- minimal_imports1 = foldr add_name minimal_imports0 defined_and_used
- minimal_imports = foldr add_inst_mod minimal_imports1 direct_import_mods
- -- The last line makes sure that we retain all direct imports
- -- even if we import nothing explicitly.
- -- It's not necessarily redundant to import such modules. Consider
- -- module This
- -- import M ()
- --
- -- The import M() is not *necessarily* redundant, even if
- -- we suck in no instance decls from M (e.g. it contains
- -- no instance decls, or This contains no code). It may be
- -- that we import M solely to ensure that M's orphan instance
- -- decls (or those in its imports) are visible to people who
- -- import This. Sigh.
- -- There's really no good way to detect this, so the error message
- -- in RnEnv.warnUnusedModules is weakened instead
-
- -- We've carefully preserved the provenance so that we can
- -- construct minimal imports that import the name by (one of)
- -- the same route(s) as the programmer originally did.
- add_name (GRE {gre_name = n, gre_prov = Imported imp_specs}) acc
- = addToFM_C plusAvailEnv acc (importSpecModule (head imp_specs))
- (unitAvailEnv (mk_avail n (nameParent_maybe n)))
- add_name other acc
- = acc
-
- -- Modules mentioned as 'module M' in the export list
- expall_mods = case export_decls of
- Nothing -> []
- Just es -> [m | L _ (IEModuleContents m) <- es]
-
- -- This is really bogus. The idea is that if we see 'module M' in
- -- the export list we must retain the import decls that drive it
- -- If we aren't careful we might see
- -- module A( module M ) where
- -- import M
- -- import N
- -- and suppose that N exports everything that M does. Then we
- -- must not drop the import of M even though N brings it all into
- -- scope.
- --
- -- BUG WARNING: 'module M' exports aside, what if M.x is mentioned?!
- --
- -- The reason that add_expall is bogus is that it doesn't take
- -- qualified imports into account. But it's an improvement.
- add_expall mod acc = addToFM_C plusAvailEnv acc mod emptyAvailEnv
-
- -- n is the name of the thing, p is the name of its parent
- mk_avail n (Just p) = AvailTC p [p,n]
- mk_avail n Nothing | isTcOcc (nameOccName n) = AvailTC n [n]
- | otherwise = Avail n
-
- add_inst_mod (mod,_,_) acc
- | mod_name `elemFM` acc = acc -- We import something already
- | otherwise = addToFM acc mod_name emptyAvailEnv
- where
- mod_name = moduleName mod
- -- Add an empty collection of imports for a module
- -- from which we have sucked only instance decls
-
- imports = tcg_imports gbl_env
-
- direct_import_mods :: [(Module, Bool, SrcSpan)]
- -- See the type of the imp_mods for this triple
- direct_import_mods = moduleEnvElts (imp_mods imports)
-
- -- unused_imp_mods are the directly-imported modules
- -- that are not mentioned in minimal_imports1
- -- [Note: not 'minimal_imports', because that includes directly-imported
- -- modules even if we use nothing from them; see notes above]
- --
- -- BUG WARNING: does not deal correctly with multiple imports of the same module
- -- becuase direct_import_mods has only one entry per module
- unused_imp_mods = [(mod_name,loc) | (mod,no_imp,loc) <- direct_import_mods,
- let mod_name = moduleName mod,
- not (mod_name `elemFM` minimal_imports1),
- mod /= pRELUDE,
- not no_imp]
- -- The not no_imp part is not to complain about
- -- import M (), which is an idiom for importing
- -- instance declarations
-
- module_unused :: ModuleName -> Bool
- module_unused mod = any (((==) mod) . fst) unused_imp_mods
-
----------------------
-warnDuplicateImports :: [GlobalRdrElt] -> RnM ()
--- Given the GREs for names that are used, figure out which imports
--- could be omitted without changing the top-level environment.
+\end{code}
+
+%*********************************************************
+%* *
+\subsection{Unused imports}
+%* *
+%*********************************************************
+
+This code finds which import declarations are unused. The
+specification and implementation notes are here:
+ http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/UnusedImports
+
+\begin{code}
+type ImportDeclUsage
+ = ( LImportDecl Name -- The import declaration
+ , [AvailInfo] -- What *is* used (normalised)
+ , [Name] ) -- What is imported but *not* used
+\end{code}
+
+\begin{code}
+warnUnusedImportDecls :: TcGblEnv -> RnM ()
+warnUnusedImportDecls gbl_env
+ = do { uses <- readMutVar (tcg_used_rdrnames gbl_env)
+ ; let imports = filter explicit_import (tcg_rn_imports gbl_env)
+ rdr_env = tcg_rdr_env gbl_env
+
+ ; let usage :: [ImportDeclUsage]
+ usage = findImportUsage imports rdr_env (Set.elems uses)
+
+ ; ifDOptM Opt_WarnUnusedImports $
+ mapM_ warnUnusedImport usage
+
+ ; ifDOptM Opt_D_dump_minimal_imports $
+ printMinimalImports usage }
+ where
+ explicit_import (L loc _) = isGoodSrcSpan loc
+ -- Filter out the implicit Prelude import
+ -- which we do not want to bleat about
+\end{code}
+
+\begin{code}
+findImportUsage :: [LImportDecl Name]
+ -> GlobalRdrEnv
+ -> [RdrName]
+ -> [ImportDeclUsage]
+
+type ImportMap = Map SrcLoc [AvailInfo]
+-- The intermediate data struture records, for each import
+-- declaration, what stuff brought into scope by that
+-- declaration is actually used in the module.