-
- 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
+\end{code}
+
+%*********************************************************
+%* *
+ 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)
+
+ ; ifOptM Opt_WarnUnusedImports $
+ mapM_ warnUnusedImport usage
+
+ ; ifOptM 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 = FiniteMap 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.
+ --
+ -- The SrcLoc is the location of the start
+ -- of a particular 'import' declaration
+ --
+ -- The AvailInfos are the things imported from that decl
+ -- (just a list, not normalised)
+
+findImportUsage imports rdr_env rdrs
+ = map unused_decl imports
+ where
+ import_usage :: ImportMap
+ import_usage = foldr add_rdr emptyFM rdrs
+
+ unused_decl decl@(L loc (ImportDecl { ideclHiding = imps }))
+ = (decl, nubAvails used_avails, unused_imps)