-getIfaceDeclNames :: RdrNameIE -> RdrIfaceDecl
- -> RnM_IInfo s (Bag RnName, -- values
- Bag RnName, -- tycons/classes
- Bag (RnName,ExportFlag)) -- import flags
-
-getIfaceDeclNames ie (ValSig val src_loc _)
- = newImportedName False src_loc Nothing Nothing val `thenRn` \ val_name ->
- returnRn (unitBag (RnName val_name),
- emptyBag,
- unitBag (RnName val_name, ExportAll))
-
-getIfaceDeclNames ie (TypeSig tycon src_loc _)
- = newImportedName True src_loc Nothing Nothing tycon `thenRn` \ tycon_name ->
- returnRn (emptyBag,
- unitBag (RnSyn tycon_name),
- unitBag (RnSyn tycon_name, ExportAll))
-
-getIfaceDeclNames ie (NewTypeSig tycon con src_loc _)
- = newImportedName True src_loc Nothing Nothing tycon `thenRn` \ tycon_name ->
- newImportedName False src_loc (Just (nameExportFlag tycon_name))
- (Just (nameImportFlag tycon_name))
- con `thenRn` \ con_name ->
- returnRn (if imp_all (imp_flag ie) then
- unitBag (RnConstr con_name tycon_name)
- else
- emptyBag,
- unitBag (RnData tycon_name [con_name] []),
- unitBag (RnData tycon_name [con_name] [], imp_flag ie))
-
-getIfaceDeclNames ie (DataSig tycon cons fields src_loc _)
- = newImportedName True src_loc Nothing Nothing tycon `thenRn` \ tycon_name ->
- mapRn (newImportedName False src_loc (Just (nameExportFlag tycon_name))
- (Just (nameImportFlag tycon_name)))
- cons `thenRn` \ con_names ->
- mapRn (newImportedName False src_loc (Just (nameExportFlag tycon_name))
- (Just (nameImportFlag tycon_name)))
- fields `thenRn` \ field_names ->
- let
- rn_tycon = RnData tycon_name con_names field_names
- rn_constrs = [ RnConstr name tycon_name | name <- con_names ]
- rn_fields = [ RnField name tycon_name | name <- field_names ]
- in
- returnRn (if imp_all (imp_flag ie) then
- listToBag rn_constrs `unionBags` listToBag rn_fields
- else
- emptyBag,
- unitBag rn_tycon,
- unitBag (rn_tycon, imp_flag ie))
-
-getIfaceDeclNames ie (ClassSig cls ops src_loc _)
- = newImportedName True src_loc Nothing Nothing cls `thenRn` \ cls_name ->
- mapRn (newImportedName False src_loc (Just (nameExportFlag cls_name))
- (Just (nameImportFlag cls_name)))
- ops `thenRn` \ op_names ->
- returnRn (if imp_all (imp_flag ie) then
- listToBag (map (\ n -> RnClassOp n cls_name) op_names)
- else
- emptyBag,
- unitBag (RnClass cls_name op_names),
- unitBag (RnClass cls_name op_names, imp_flag ie))
-
-
-imp_all ExportAll = True
-imp_all _ = False
-
-imp_flag (IEThingAbs _) = ExportAbs
-imp_flag (IEThingAll _) = ExportAll
-imp_flag (IEThingWith _ _) = ExportAll
+reportUnusedNames :: TcGblEnv -> RnM ()
+reportUnusedNames gbl_env
+ = do { warnUnusedTopBinds unused_locals
+ ; warnUnusedModules unused_imp_mods
+ ; warnUnusedImports unused_imports
+ ; warnDuplicateImports dup_imps
+ ; printMinimalImports minimal_imports }
+ where
+ used_names, all_used_names :: NameSet
+ used_names = findUses (tcg_dus gbl_env) emptyNameSet
+ all_used_names = used_names `unionNameSets`
+ mkNameSet (mapCatMaybes nameParent_maybe (nameSetToList used_names))
+ -- A use of C implies a use of T,
+ -- if C was brought into scope by T(..) or T(C)
+
+ -- Collect the defined names from the in-scope environment
+ defined_names :: [GlobalRdrElt]
+ defined_names = globalRdrEnvElts (tcg_rdr_env gbl_env)
+
+ -- Note that defined_and_used, defined_but_not_used
+ -- are both [GRE]; that's why we need defined_and_used
+ -- rather than just all_used_names
+ defined_and_used, defined_but_not_used :: [GlobalRdrElt]
+ (defined_and_used, defined_but_not_used)
+ = partition (gre_is_used all_used_names) defined_names
+
+ -- Find the duplicate imports
+ dup_imps = filter is_dup defined_and_used
+ is_dup (GRE {gre_prov = Imported imp_spec True}) = not (isSingleton imp_spec)
+ is_dup other = False
+
+ -- Filter out the ones that are
+ -- (a) defined in this module, and
+ -- (b) not defined by a 'deriving' clause
+ -- The latter have an Internal Name, so we can filter them out easily
+ unused_locals :: [GlobalRdrElt]
+ unused_locals = filter is_unused_local defined_but_not_used
+ is_unused_local :: GlobalRdrElt -> Bool
+ is_unused_local gre = isLocalGRE gre && isExternalName (gre_name gre)
+
+ unused_imports :: [GlobalRdrElt]
+ unused_imports = filter unused_imp defined_but_not_used
+ unused_imp (GRE {gre_prov = Imported imp_specs True})
+ = not (all (module_unused . is_mod) 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
+ minimal_imports :: FiniteMap ModuleName AvailEnv
+ minimal_imports0 = emptyFM
+ 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 (is_mod (head imp_specs))
+ (unitAvailEnv (mk_avail n (nameParent_maybe n)))
+ add_name other acc
+ = acc
+
+ -- 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 m acc
+ | m `elemFM` acc = acc -- We import something already
+ | otherwise = addToFM acc m emptyAvailEnv
+ -- 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 :: [ModuleName]
+ direct_import_mods = map (moduleName . fst)
+ (moduleEnvElts (imp_mods imports))
+
+ hasEmptyImpList :: ModuleName -> Bool
+ hasEmptyImpList m =
+ case lookupModuleEnvByName (imp_mods imports) m of
+ Just (_,Just x) -> not x
+ _ -> False
+
+ -- 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]
+ unused_imp_mods = [m | m <- direct_import_mods,
+ isNothing (lookupFM minimal_imports1 m),
+ m /= pRELUDE_Name,
+ not (hasEmptyImpList m)]
+ -- hasEmptyImpList arranges not to complain about
+ -- import M (), which is an idiom for importing
+ -- instance declarations
+
+ module_unused :: ModuleName -> Bool
+ module_unused mod = mod `elem` unused_imp_mods
+
+---------------------
+warnDuplicateImports :: [GlobalRdrElt] -> RnM ()
+warnDuplicateImports gres
+ = ifOptM Opt_WarnUnusedImports (mapM_ warn gres)
+ where
+ warn (GRE { gre_name = name, gre_prov = Imported imps _ })
+ = addWarn ((quotes (ppr name) <+> ptext SLIT("is imported more than once:"))
+ $$ nest 2 (vcat (map ppr imps)))
+
+
+-- ToDo: deal with original imports with 'qualified' and 'as M' clauses
+printMinimalImports :: FiniteMap ModuleName AvailEnv -- Minimal imports
+ -> RnM ()
+printMinimalImports imps
+ = ifOptM Opt_D_dump_minimal_imports $ do {
+
+ mod_ies <- mappM to_ies (fmToList imps) ;
+ this_mod <- getModule ;
+ rdr_env <- getGlobalRdrEnv ;
+ ioToTcRn (do { h <- openFile (mkFilename this_mod) WriteMode ;
+ printForUser h (unQualInScope rdr_env)
+ (vcat (map ppr_mod_ie mod_ies)) })
+ }
+ where
+ mkFilename this_mod = moduleNameUserString (moduleName this_mod) ++ ".imports"
+ ppr_mod_ie (mod_name, ies)
+ | mod_name == pRELUDE_Name
+ = empty
+ | null ies -- Nothing except instances comes from here
+ = ptext SLIT("import") <+> ppr mod_name <> ptext SLIT("() -- Instances only")
+ | otherwise
+ = ptext SLIT("import") <+> ppr mod_name <>
+ parens (fsep (punctuate comma (map ppr ies)))
+
+ to_ies (mod, avail_env) = mappM to_ie (availEnvElts avail_env) `thenM` \ ies ->
+ returnM (mod, ies)
+
+ to_ie :: AvailInfo -> RnM (IE Name)
+ -- The main trick here is that if we're importing all the constructors
+ -- we want to say "T(..)", but if we're importing only a subset we want
+ -- to say "T(A,B,C)". So we have to find out what the module exports.
+ to_ie (Avail n) = returnM (IEVar n)
+ to_ie (AvailTC n [m]) = ASSERT( n==m )
+ returnM (IEThingAbs n)
+ to_ie (AvailTC n ns)
+ = loadSrcInterface doc n_mod False `thenM` \ iface ->
+ case [xs | (m,as) <- mi_exports iface,
+ m == n_mod,
+ AvailTC x xs <- as,
+ x == nameOccName n] of
+ [xs] | all_used xs -> returnM (IEThingAll n)
+ | otherwise -> returnM (IEThingWith n (filter (/= n) ns))
+ other -> pprTrace "to_ie" (ppr n <+> ppr n_mod <+> ppr other) $
+ returnM (IEVar n)
+ where
+ all_used avail_occs = all (`elem` map nameOccName ns) avail_occs
+ doc = text "Compute minimal imports from" <+> ppr n
+ n_mod = nameModuleName n