module Agda.Syntax.Scope.UnusedImports
( lookedupName
, lookedupModule
, registerModuleOpening
, warnUnusedImports
) where
import Prelude hiding (null, (||))
import Data.IntMap.Strict (IntMap)
import Data.IntMap.Strict qualified as IntMap
import Data.List (partition, sortOn)
import Data.Map qualified as Map
import Data.Set qualified as Set
import Agda.Interaction.Options (optQualifiedInstances)
import Agda.Interaction.Options.Warnings (WarningName (UnusedImports_, UnusedImportsAll_))
import Agda.Syntax.Abstract.Name
( WhyInScope(Defined, Opened, Applied),
AbstractName, anameName, anameLineage,
AbstractModule, amodName, amodLineage )
import Agda.Syntax.Abstract.Name qualified as A
import Agda.Syntax.Common
( IsInstanceDef(isInstanceDef), KwRange
, ImportDirective'(using, impRenaming, publicOpen)
, ImportedName'(ImportedName, ImportedModule), fromImportedName, Renaming'(renTo), Using'(Using, UseEverything)
)
import Agda.Syntax.Common.Pretty (prettyShow, Pretty (pretty))
import Agda.Syntax.Concrete qualified as C
import Agda.Syntax.Position ( HasRange(getRange), SetRange(setRange) )
import Agda.Syntax.Position qualified as P
import Agda.Syntax.Scope.Base as A
import Agda.Syntax.Scope.State ( ScopeM, withCurrentModule )
import Agda.TypeChecking.Monad.Base
import Agda.TypeChecking.Monad.Debug ( MonadDebug, reportSLn, __IMPOSSIBLE_VERBOSE__ )
import Agda.TypeChecking.Monad.State ( getScope )
import Agda.TypeChecking.Monad.Trace (setCurrentRange)
import Agda.TypeChecking.Warnings (warning)
import Agda.Utils.Boolean ( (||) )
import Agda.Utils.Function ( applyUnless )
import Agda.Utils.Lens ( (<&>), Lens' )
import Agda.Utils.List ( partitionMaybe, hasElem )
import Agda.Utils.List1 ( pattern (:|), List1 )
import Agda.Utils.List1 qualified as List1
import Agda.Utils.List2 ( List2(..) )
import Agda.Utils.List2 qualified as List2
import Agda.Utils.Maybe ( fromMaybe, isJust, mapMaybe, whenNothing )
import Agda.Utils.Monad ( forM_, when, unless, whenM )
import Agda.Utils.Null ( Null(null) )
import Agda.Utils.Impossible
lookedupName ::
C.QName
-> ResolvedName
-> ScopeM ()
lookedupName :: QName -> ResolvedName -> ScopeM ()
lookedupName QName
x = \case
DefinedName Access
_access AbstractName
y Suffix
_suffix -> AbstractName -> ScopeM ()
unamb AbstractName
y ScopeM () -> ScopeM () -> ScopeM ()
forall a b. TCMT IO a -> TCMT IO b -> TCMT IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> QName -> [AbstractName] -> ScopeM ()
forall a. InScope a => QName -> [a] -> ScopeM ()
lookedupQualifier QName
x [AbstractName
y]
FieldName NonEmpty AbstractName
ys -> NonEmpty AbstractName -> ScopeM ()
add NonEmpty AbstractName
ys
ConstructorName Set1 Induction
_ind NonEmpty AbstractName
ys -> NonEmpty AbstractName -> ScopeM ()
add NonEmpty AbstractName
ys
PatternSynResName NonEmpty AbstractName
ys -> NonEmpty AbstractName -> ScopeM ()
add NonEmpty AbstractName
ys
VarName{} -> () -> ScopeM ()
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
UnknownName{} -> () -> ScopeM ()
forall a. a -> TCMT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
where
add :: NonEmpty AbstractName -> ScopeM ()
add NonEmpty AbstractName
ys = do
case NonEmpty AbstractName
ys of
AbstractName
y :| [] -> AbstractName -> ScopeM ()
unamb AbstractName
y
AbstractName
y1 :| AbstractName
y2 : [AbstractName]
ys -> List2 AbstractName -> ScopeM ()
amb (List2 AbstractName -> ScopeM ())
-> List2 AbstractName -> ScopeM ()
forall a b. (a -> b) -> a -> b
$ AbstractName
-> AbstractName -> [AbstractName] -> List2 AbstractName
forall a. a -> a -> [a] -> List2 a
List2 AbstractName
y1 AbstractName
y2 [AbstractName]
ys
QName -> [AbstractName] -> ScopeM ()
forall a. InScope a => QName -> [a] -> ScopeM ()
lookedupQualifier QName
x ([AbstractName] -> ScopeM ()) -> [AbstractName] -> ScopeM ()
forall a b. (a -> b) -> a -> b
$ NonEmpty AbstractName -> [Item (NonEmpty AbstractName)]
forall l. IsList l => l -> [Item l]
List1.toList NonEmpty AbstractName
ys
unamb :: AbstractName -> ScopeM ()
unamb = Lens' TCState [AbstractName]
-> ([AbstractName] -> [AbstractName]) -> ScopeM ()
forall (m :: * -> *) a.
MonadTCState m =>
Lens' TCState a -> (a -> a) -> m ()
modifyTCLens ([AbstractName] -> f [AbstractName]) -> TCState -> f TCState
Lens' TCState [AbstractName]
stUnambiguousLookups (([AbstractName] -> [AbstractName]) -> ScopeM ())
-> (AbstractName -> [AbstractName] -> [AbstractName])
-> AbstractName
-> ScopeM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (:)
amb :: List2 AbstractName -> ScopeM ()
amb List2 AbstractName
xs = case QName -> Maybe Int
forall a. HasRange a => a -> Maybe Int
rangeToPosPos QName
x of
Maybe Int
Nothing -> () -> ScopeM ()
forall a. a -> TCMT IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just Int
i -> Lens' TCState (IntMap (List2 AbstractName))
-> (IntMap (List2 AbstractName) -> IntMap (List2 AbstractName))
-> ScopeM ()
forall (m :: * -> *) a.
MonadTCState m =>
Lens' TCState a -> (a -> a) -> m ()
modifyTCLens (IntMap (List2 AbstractName) -> f (IntMap (List2 AbstractName)))
-> TCState -> f TCState
Lens' TCState (IntMap (List2 AbstractName))
stAmbiguousLookups ((IntMap (List2 AbstractName) -> IntMap (List2 AbstractName))
-> ScopeM ())
-> (IntMap (List2 AbstractName) -> IntMap (List2 AbstractName))
-> ScopeM ()
forall a b. (a -> b) -> a -> b
$ Int
-> List2 AbstractName
-> IntMap (List2 AbstractName)
-> IntMap (List2 AbstractName)
forall a. Int -> a -> IntMap a -> IntMap a
IntMap.insert Int
i List2 AbstractName
xs
lookedupModule ::
C.QName
-> AbstractModule
-> ScopeM ()
lookedupModule :: QName -> AbstractModule -> ScopeM ()
lookedupModule QName
x AbstractModule
m = do
Lens' TCState [AbstractModule]
-> ([AbstractModule] -> [AbstractModule]) -> ScopeM ()
forall (m :: * -> *) a.
MonadTCState m =>
Lens' TCState a -> (a -> a) -> m ()
modifyTCLens ([AbstractModule] -> f [AbstractModule]) -> TCState -> f TCState
Lens' TCState [AbstractModule]
stModuleLookups (AbstractModule
m AbstractModule -> [AbstractModule] -> [AbstractModule]
forall a. a -> [a] -> [a]
:)
QName -> [AbstractModule] -> ScopeM ()
forall a. InScope a => QName -> [a] -> ScopeM ()
lookedupQualifier QName
x [AbstractModule
m]
lookedupQualifier :: InScope a => C.QName -> [a] -> ScopeM ()
lookedupQualifier :: forall a. InScope a => QName -> [a] -> ScopeM ()
lookedupQualifier QName
x [a]
ys = case QName
x of
C.QName{} -> () -> ScopeM ()
forall a. a -> TCMT IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
C.Qual{} -> TCMT IO Bool -> ScopeM () -> ScopeM ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM TCMT IO Bool
unusedImportsEnabled do
ms <- QName -> [a] -> ScopeInfo -> [AbstractModule]
forall a.
InScope a =>
QName -> [a] -> ScopeInfo -> [AbstractModule]
scopeLookupQualifier QName
x [a]
ys (ScopeInfo -> [AbstractModule])
-> TCMT IO ScopeInfo -> TCMT IO [AbstractModule]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TCMT IO ScopeInfo
forall (m :: * -> *). ReadTCState m => m ScopeInfo
getScope
modifyTCLens stModuleLookups (ms ++)
unusedImportsEnabled :: ScopeM Bool
unusedImportsEnabled :: TCMT IO Bool
unusedImportsEnabled = (WarningName
UnusedImports_ WarningName -> Set WarningName -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member`) (Set WarningName -> Bool)
-> TCMT IO (Set WarningName) -> TCMT IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lens' TCState (Set WarningName) -> TCMT IO (Set WarningName)
forall (m :: * -> *) a. ReadTCState m => Lens' TCState a -> m a
useTC (Set WarningName -> f (Set WarningName)) -> TCState -> f TCState
Lens' TCState (Set WarningName)
stWarningSet
rangeToPosPos :: HasRange a => a -> Maybe Int
rangeToPosPos :: forall a. HasRange a => a -> Maybe Int
rangeToPosPos = (Position' () -> Int) -> Maybe (Position' ()) -> Maybe Int
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int) -> (Position' () -> Word32) -> Position' () -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Position' () -> Word32
forall a. Position' a -> Word32
P.posPos) (Maybe (Position' ()) -> Maybe Int)
-> (a -> Maybe (Position' ())) -> a -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Range' SrcFile -> Maybe (Position' ())
forall a. Range' a -> Maybe (Position' ())
P.rStart' (Range' SrcFile -> Maybe (Position' ()))
-> (a -> Range' SrcFile) -> a -> Maybe (Position' ())
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Range' SrcFile
forall a. HasRange a => a -> Range' SrcFile
getRange
registerModuleOpening ::
KwRange
-> A.ModuleName
-> C.QName
-> C.ImportDirective
-> Scope
-> ScopeM ()
registerModuleOpening :: KwRange
-> ModuleName -> QName -> ImportDirective -> Scope -> ScopeM ()
registerModuleOpening KwRange
kwr ModuleName
currentModule QName
x ImportDirective
dir (Scope ModuleName
m0 [ModuleName]
_parents ScopeNameSpaces
ns Map QName ModuleName
imports Maybe DataOrRecordModule
_dataOrRec) = do
Bool -> ScopeM () -> ScopeM ()
forall b (m :: * -> *). (IsBool b, Monad m) => b -> m () -> m ()
unless (Map QName ModuleName -> Bool
forall a. Null a => a -> Bool
null Map QName ModuleName
imports) ScopeM ()
forall a. HasCallStack => a
__IMPOSSIBLE__
doWarn <- TCMT IO Bool
unusedImportsEnabled
reportSLn "warning.unusedImports" 20 $ unlines
[ "openedModule: " <> prettyShow doWarn
, "x = " <> prettyShow x
]
when doWarn $ whenNothing (publicOpen dir) do
let
m = Range' SrcFile -> ModuleName -> ModuleName
forall a. SetRange a => Range' SrcFile -> a -> a
setRange (QName -> Range' SrcFile
forall a. HasRange a => a -> Range' SrcFile
getRange QName
x) ModuleName
m0
names :: NamesInScope
names = [NamesInScope] -> NamesInScope
forall a. Eq a => [ThingsInScope a] -> ThingsInScope a
mergeNamesMany ([NamesInScope] -> NamesInScope) -> [NamesInScope] -> NamesInScope
forall a b. (a -> b) -> a -> b
$ ((NameSpaceId, NameSpace) -> NamesInScope)
-> ScopeNameSpaces -> [NamesInScope]
forall a b. (a -> b) -> [a] -> [b]
map (NameSpace -> NamesInScope
nsNames (NameSpace -> NamesInScope)
-> ((NameSpaceId, NameSpace) -> NameSpace)
-> (NameSpaceId, NameSpace)
-> NamesInScope
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NameSpaceId, NameSpace) -> NameSpace
forall a b. (a, b) -> b
snd) ScopeNameSpaces
ns
modules :: ModulesInScope
modules = [ModulesInScope] -> ModulesInScope
forall a. Eq a => [ThingsInScope a] -> ThingsInScope a
mergeNamesMany ([ModulesInScope] -> ModulesInScope)
-> [ModulesInScope] -> ModulesInScope
forall a b. (a -> b) -> a -> b
$ ((NameSpaceId, NameSpace) -> ModulesInScope)
-> ScopeNameSpaces -> [ModulesInScope]
forall a b. (a -> b) -> [a] -> [b]
map (NameSpace -> ModulesInScope
nsModules (NameSpace -> ModulesInScope)
-> ((NameSpaceId, NameSpace) -> NameSpace)
-> (NameSpaceId, NameSpace)
-> ModulesInScope
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NameSpaceId, NameSpace) -> NameSpace
forall a b. (a, b) -> b
snd) ScopeNameSpaces
ns
explicitModules = [Name] -> Set Name
forall a. Ord a => [a] -> Set a
Set.fromList
[ Name
y | ImportedModule Name
y <- [ImportedName' Name Name]
usingList [ImportedName' Name Name]
-> [ImportedName' Name Name] -> [ImportedName' Name Name]
forall a. [a] -> [a] -> [a]
++ (Renaming' Name Name -> ImportedName' Name Name)
-> [Renaming' Name Name] -> [ImportedName' Name Name]
forall a b. (a -> b) -> [a] -> [b]
map Renaming' Name Name -> ImportedName' Name Name
forall n m. Renaming' n m -> ImportedName' n m
renTo (ImportDirective -> [Renaming' Name Name]
forall n m. ImportDirective' n m -> RenamingDirective' n m
impRenaming ImportDirective
dir) ]
usingList = case ImportDirective -> Using' Name Name
forall n m. ImportDirective' n m -> Using' n m
using ImportDirective
dir of
Using' Name Name
UseEverything -> []
Using [ImportedName' Name Name]
ys -> [ImportedName' Name Name]
ys
companions = ModulesInScope -> Set Name
forall k a. Map k a -> Set k
Map.keysSet ((Name -> NonEmpty AbstractModule -> Bool)
-> ModulesInScope -> ModulesInScope
forall k a. (k -> a -> Bool) -> Map k a -> Map k a
Map.filterWithKey Name -> NonEmpty AbstractModule -> Bool
isCompanion ModulesInScope
modules)
isCompanion Name
y NonEmpty AbstractModule
zs = Name -> Set Name -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.notMember Name
y Set Name
explicitModules Bool -> Bool -> Bool
&&
(Name -> NamesInScope -> Bool
forall k a. Ord k => k -> Map k a -> Bool
Map.member Name
y NamesInScope
names Bool -> Bool -> Bool
forall a. Boolean a => a -> a -> a
|| (AbstractModule -> Bool) -> NonEmpty AbstractModule -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((ModuleName -> Set ModuleName -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set ModuleName
nameModules) (ModuleName -> Bool)
-> (AbstractModule -> ModuleName) -> AbstractModule -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AbstractModule -> ModuleName
amodName) NonEmpty AbstractModule
zs)
nameModules = [ModuleName] -> Set ModuleName
forall a. Ord a => [a] -> Set a
Set.fromList ([ModuleName] -> Set ModuleName) -> [ModuleName] -> Set ModuleName
forall a b. (a -> b) -> a -> b
$ (AbstractName -> ModuleName) -> [AbstractName] -> [ModuleName]
forall a b. (a -> b) -> [a] -> [b]
map (QName -> ModuleName
A.qnameToMName (QName -> ModuleName)
-> (AbstractName -> QName) -> AbstractName -> ModuleName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AbstractName -> QName
anameName) ([AbstractName] -> [ModuleName]) -> [AbstractName] -> [ModuleName]
forall a b. (a -> b) -> a -> b
$ (NonEmpty AbstractName -> [AbstractName])
-> [NonEmpty AbstractName] -> [AbstractName]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap NonEmpty AbstractName -> [Item (NonEmpty AbstractName)]
NonEmpty AbstractName -> [AbstractName]
forall l. IsList l => l -> [Item l]
List1.toList ([NonEmpty AbstractName] -> [AbstractName])
-> [NonEmpty AbstractName] -> [AbstractName]
forall a b. (a -> b) -> a -> b
$ NamesInScope -> [NonEmpty AbstractName]
forall k a. Map k a -> [a]
Map.elems NamesInScope
names
!k = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
forall a. HasCallStack => a
__IMPOSSIBLE__ (Maybe Int -> Int) -> Maybe Int -> Int
forall a b. (a -> b) -> a -> b
$ QName -> Maybe Int
forall a. HasRange a => a -> Maybe Int
rangeToPosPos QName
x
hasDir = Bool -> Bool
not (Using' Name Name -> Bool
forall a. Null a => a -> Bool
null (ImportDirective -> Using' Name Name
forall n m. ImportDirective' n m -> Using' n m
using ImportDirective
dir)) Bool -> Bool -> Bool
forall a. Boolean a => a -> a -> a
|| Bool -> Bool
not ([Renaming' Name Name] -> Bool
forall a. Null a => a -> Bool
null (ImportDirective -> [Renaming' Name Name]
forall n m. ImportDirective' n m -> RenamingDirective' n m
impRenaming ImportDirective
dir))
modifyTCLens stOpenedModules $
IntMap.insert k (OpenedModule kwr m currentModule hasDir names modules companions)
warnUnusedImports :: TCM ()
warnUnusedImports :: ScopeM ()
warnUnusedImports = do
warnAll <- (WarningName
UnusedImportsAll_ WarningName -> Set WarningName -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member`) (Set WarningName -> Bool)
-> TCMT IO (Set WarningName) -> TCMT IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lens' TCState (Set WarningName) -> TCMT IO (Set WarningName)
forall (m :: * -> *) a. ReadTCState m => Lens' TCState a -> m a
useTC (Set WarningName -> f (Set WarningName)) -> TCState -> f TCState
Lens' TCState (Set WarningName)
stWarningSet
st <- useTC stUnusedImportsState
disambiguatedNames <- useTC stDisambiguatedNames
qualifiedInstances <- optQualifiedInstances <$> pragmaOptions
reportSLn "warning.unusedImports" 60 $ "ambiguousLookups: " <> prettyShow (ambiguousLookups st)
reportSLn "warning.unusedImports" 60 $ "unambiguousLookups: " <> prettyShow (unambiguousLookups st)
reportSLn "warning.unusedImports" 60 $ "moduleLookups: " <> prettyShow (moduleLookups st)
let
addAmbLookup (Int
i :: Int) (List2 AbstractName
ys :: List2 AbstractName) = do
case Int -> IntMap DisambiguatedName -> Maybe DisambiguatedName
forall a. Int -> IntMap a -> Maybe a
IntMap.lookup Int
i IntMap DisambiguatedName
disambiguatedNames of
Just (DisambiguatedName NameKind
_k QName
x) -> ((AbstractName -> Bool) -> [AbstractName] -> [AbstractName]
forall a. (a -> Bool) -> [a] -> [a]
filter ((QName
x QName -> QName -> Bool
forall a. Eq a => a -> a -> Bool
==) (QName -> Bool) -> (AbstractName -> QName) -> AbstractName -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AbstractName -> QName
anameName) (List2 AbstractName -> [Item (List2 AbstractName)]
forall l. IsList l => l -> [Item l]
List2.toList List2 AbstractName
ys) [AbstractName] -> [AbstractName] -> [AbstractName]
forall a. [a] -> [a] -> [a]
++)
Maybe DisambiguatedName
Nothing -> (List2 AbstractName -> [Item (List2 AbstractName)]
forall l. IsList l => l -> [Item l]
List2.toList List2 AbstractName
ys [AbstractName] -> [AbstractName] -> [AbstractName]
forall a. [a] -> [a] -> [a]
++)
allLookups :: [AbstractName]
allLookups = (Int -> List2 AbstractName -> [AbstractName] -> [AbstractName])
-> [AbstractName] -> IntMap (List2 AbstractName) -> [AbstractName]
forall a b. (Int -> a -> b -> b) -> b -> IntMap a -> b
IntMap.foldrWithKey Int -> List2 AbstractName -> [AbstractName] -> [AbstractName]
addAmbLookup (UnusedImportsState -> [AbstractName]
unambiguousLookups UnusedImportsState
st) (UnusedImportsState -> IntMap (List2 AbstractName)
ambiguousLookups UnusedImportsState
st)
lookups :: [Imported AbstractName]
(unknowns, lookups) = partitionMaybe toImported allLookups
moduleLookups' :: [Imported AbstractModule]
moduleLookups' = (AbstractModule -> Maybe (Imported AbstractModule))
-> [AbstractModule] -> [Imported AbstractModule]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe AbstractModule -> Maybe (Imported AbstractModule)
forall a. Lineage a => a -> Maybe (Imported a)
toImported ([AbstractModule] -> [Imported AbstractModule])
-> [AbstractModule] -> [Imported AbstractModule]
forall a b. (a -> b) -> a -> b
$ UnusedImportsState -> [AbstractModule]
moduleLookups UnusedImportsState
st
isInst, isUsedName :: Imported AbstractName -> Bool
isInst = Maybe KwRange -> Bool
forall a. Maybe a -> Bool
isJust (Maybe KwRange -> Bool)
-> (Imported AbstractName -> Maybe KwRange)
-> Imported AbstractName
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AbstractName -> Maybe KwRange
forall a. IsInstanceDef a => a -> Maybe KwRange
isInstanceDef (AbstractName -> Maybe KwRange)
-> (Imported AbstractName -> AbstractName)
-> Imported AbstractName
-> Maybe KwRange
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Imported AbstractName -> AbstractName
forall a. Imported a -> a
iThing
isUsedName = Bool
-> ((Imported AbstractName -> Bool)
-> Imported AbstractName -> Bool)
-> (Imported AbstractName -> Bool)
-> Imported AbstractName
-> Bool
forall b a. IsBool b => b -> (a -> a) -> a -> a
applyUnless Bool
qualifiedInstances (Imported AbstractName -> Bool
isInst (Imported AbstractName -> Bool)
-> (Imported AbstractName -> Bool) -> Imported AbstractName -> Bool
forall a. Boolean a => a -> a -> a
||) ((Imported AbstractName -> Bool) -> Imported AbstractName -> Bool)
-> (Imported AbstractName -> Bool) -> Imported AbstractName -> Bool
forall a b. (a -> b) -> a -> b
$ [Imported AbstractName] -> Imported AbstractName -> Bool
forall a. Ord a => [a] -> a -> Bool
hasElem [Imported AbstractName]
lookups
isUsedModule :: Imported AbstractModule -> Bool
isUsedModule = [Imported AbstractModule] -> Imported AbstractModule -> Bool
forall a. Ord a => [a] -> a -> Bool
hasElem [Imported AbstractModule]
moduleLookups'
reportSLn "warning.unusedImports" 60 $ "allLookups: " <> prettyShow allLookups
reportSLn "warning.unusedImports" 60 $ "lookups: " <> prettyShow lookups
reportSLn "warning.unusedImports" 60 $ "unknowns: " <> prettyShow unknowns
forM_ (openedModules st) \ (OpenedModule KwRange
kwr ModuleName
m ModuleName
parent Bool
hasDir NamesInScope
names ModulesInScope
modules Set Name
companions) -> do
(usedNames, unusedNames) <- (Imported AbstractName -> Bool)
-> NamesInScope -> TCMT IO ([Name], [Name])
forall a (m :: * -> *).
(Lineage a, MonadDebug m) =>
(Imported a -> Bool) -> ThingsInScope a -> m ([Name], [Name])
partitionUsed Imported AbstractName -> Bool
isUsedName NamesInScope
names
(usedModules, unusedModules) <- partitionUsed isUsedModule modules
let
used = Bool -> Bool
not ([Name] -> Bool
forall a. Null a => a -> Bool
null [Name]
usedNames Bool -> Bool -> Bool
&& [Name] -> Bool
forall a. Null a => a -> Bool
null [Name]
usedModules)
unused :: [C.ImportedName]
unused = (ImportedName' Name Name -> Name)
-> [ImportedName' Name Name] -> [ImportedName' Name Name]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn ImportedName' Name Name -> Name
forall a. ImportedName' a a -> a
fromImportedName ([ImportedName' Name Name] -> [ImportedName' Name Name])
-> [ImportedName' Name Name] -> [ImportedName' Name Name]
forall a b. (a -> b) -> a -> b
$ [[ImportedName' Name Name]] -> [ImportedName' Name Name]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
[ (Name -> ImportedName' Name Name)
-> [Name] -> [ImportedName' Name Name]
forall a b. (a -> b) -> [a] -> [b]
map Name -> ImportedName' Name Name
forall n m. n -> ImportedName' n m
ImportedName [Name]
unusedNames
, (Name -> ImportedName' Name Name)
-> [Name] -> [ImportedName' Name Name]
forall a b. (a -> b) -> [a] -> [b]
map Name -> ImportedName' Name Name
forall n m. m -> ImportedName' n m
ImportedModule ([Name] -> [ImportedName' Name Name])
-> [Name] -> [ImportedName' Name Name]
forall a b. (a -> b) -> a -> b
$ (Name -> Bool) -> [Name] -> [Name]
forall a. (a -> Bool) -> [a] -> [a]
filter (Name -> Set Name -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.notMember` Set Name
companions) [Name]
unusedModules
]
warn = Range' SrcFile -> ScopeM () -> ScopeM ()
forall (m :: * -> *) x a.
(MonadTrace m, HasRange x) =>
x -> m a -> m a
setCurrentRange ((KwRange, ModuleName) -> Range' SrcFile
forall a. HasRange a => a -> Range' SrcFile
getRange (KwRange
kwr, ModuleName
m)) (ScopeM () -> ScopeM ())
-> (Maybe (List1 (ImportedName' Name Name)) -> ScopeM ())
-> Maybe (List1 (ImportedName' Name Name))
-> ScopeM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleName -> ScopeM () -> ScopeM ()
forall (m :: * -> *) a.
(ReadTCState m, MonadTCState m) =>
ModuleName -> m a -> m a
withCurrentModule ModuleName
parent (ScopeM () -> ScopeM ())
-> (Maybe (List1 (ImportedName' Name Name)) -> ScopeM ())
-> Maybe (List1 (ImportedName' Name Name))
-> ScopeM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Warning -> ScopeM ()
forall (m :: * -> *).
(HasCallStack, MonadWarning m) =>
Warning -> m ()
warning (Warning -> ScopeM ())
-> (Maybe (List1 (ImportedName' Name Name)) -> Warning)
-> Maybe (List1 (ImportedName' Name Name))
-> ScopeM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleName -> Maybe (List1 (ImportedName' Name Name)) -> Warning
UnusedImports ModuleName
m
warnModule = Maybe (List1 (ImportedName' Name Name)) -> ScopeM ()
warn Maybe (List1 (ImportedName' Name Name))
forall a. Maybe a
Nothing
warnEach = [ImportedName' Name Name]
-> (List1 (ImportedName' Name Name) -> ScopeM ()) -> ScopeM ()
forall (m :: * -> *) a.
Applicative m =>
[a] -> (List1 a -> m ()) -> m ()
List1.unlessNull [ImportedName' Name Name]
unused ((List1 (ImportedName' Name Name) -> ScopeM ()) -> ScopeM ())
-> (List1 (ImportedName' Name Name) -> ScopeM ()) -> ScopeM ()
forall a b. (a -> b) -> a -> b
$ Maybe (List1 (ImportedName' Name Name)) -> ScopeM ()
warn (Maybe (List1 (ImportedName' Name Name)) -> ScopeM ())
-> (List1 (ImportedName' Name Name)
-> Maybe (List1 (ImportedName' Name Name)))
-> List1 (ImportedName' Name Name)
-> ScopeM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. List1 (ImportedName' Name Name)
-> Maybe (List1 (ImportedName' Name Name))
forall a. a -> Maybe a
Just
if | hasDir -> warnEach
| not used -> warnModule
| warnAll -> warnEach
| otherwise -> pure ()
partitionUsed :: forall a m. (Lineage a, MonadDebug m)
=> (Imported a -> Bool)
-> ThingsInScope a
-> m ([C.Name], [C.Name])
partitionUsed :: forall a (m :: * -> *).
(Lineage a, MonadDebug m) =>
(Imported a -> Bool) -> ThingsInScope a -> m ([Name], [Name])
partitionUsed Imported a -> Bool
isUsed ThingsInScope a
sc = do
let
imps, used, unused :: [(C.Name, List1 (Imported a))]
([(Name, NonEmpty a)]
other, [(Name, List1 (Imported a))]
imps) = ((Name, NonEmpty a) -> Maybe (Name, List1 (Imported a)))
-> [(Name, NonEmpty a)]
-> ([(Name, NonEmpty a)], [(Name, List1 (Imported a))])
forall a b. (a -> Maybe b) -> [a] -> ([a], [b])
partitionMaybe ((NonEmpty a -> Maybe (List1 (Imported a)))
-> (Name, NonEmpty a) -> Maybe (Name, List1 (Imported a))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> (Name, a) -> f (Name, b)
traverse ((NonEmpty a -> Maybe (List1 (Imported a)))
-> (Name, NonEmpty a) -> Maybe (Name, List1 (Imported a)))
-> (NonEmpty a -> Maybe (List1 (Imported a)))
-> (Name, NonEmpty a)
-> Maybe (Name, List1 (Imported a))
forall a b. (a -> b) -> a -> b
$ (a -> Maybe (Imported a))
-> NonEmpty a -> Maybe (List1 (Imported a))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NonEmpty a -> f (NonEmpty b)
traverse a -> Maybe (Imported a)
forall a. Lineage a => a -> Maybe (Imported a)
toImported) ([(Name, NonEmpty a)]
-> ([(Name, NonEmpty a)], [(Name, List1 (Imported a))]))
-> [(Name, NonEmpty a)]
-> ([(Name, NonEmpty a)], [(Name, List1 (Imported a))])
forall a b. (a -> b) -> a -> b
$ ThingsInScope a -> [(Name, NonEmpty a)]
forall k a. Map k a -> [(k, a)]
Map.toList ThingsInScope a
sc
([(Name, List1 (Imported a))]
used, [(Name, List1 (Imported a))]
unused) = ((Name, List1 (Imported a)) -> Bool)
-> [(Name, List1 (Imported a))]
-> ([(Name, List1 (Imported a))], [(Name, List1 (Imported a))])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition ((Imported a -> Bool) -> List1 (Imported a) -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Imported a -> Bool
isUsed (List1 (Imported a) -> Bool)
-> ((Name, List1 (Imported a)) -> List1 (Imported a))
-> (Name, List1 (Imported a))
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Name, List1 (Imported a)) -> List1 (Imported a)
forall a b. (a, b) -> b
snd) [(Name, List1 (Imported a))]
imps
String -> Int -> String -> m ()
forall (m :: * -> *).
MonadDebug m =>
String -> Int -> String -> m ()
reportSLn String
"warning.unusedImports" Int
60 (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$ String
"used: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [(Name, List1 (Imported a))] -> String
forall a. Pretty a => a -> String
prettyShow [(Name, List1 (Imported a))]
used
String -> Int -> String -> m ()
forall (m :: * -> *).
MonadDebug m =>
String -> Int -> String -> m ()
reportSLn String
"warning.unusedImports" Int
60 (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$ String
"unused: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [(Name, List1 (Imported a))] -> String
forall a. Pretty a => a -> String
prettyShow [(Name, List1 (Imported a))]
unused
Bool -> m () -> m ()
forall b (m :: * -> *). (IsBool b, Monad m) => b -> m () -> m ()
unless ([(Name, NonEmpty a)] -> Bool
forall a. Null a => a -> Bool
null [(Name, NonEmpty a)]
other) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ String -> m ()
forall (m :: * -> *) a.
(HasCallStack, MonadDebug m) =>
String -> m a
__IMPOSSIBLE_VERBOSE__ ([(Name, NonEmpty a)] -> String
forall a. Show a => a -> String
show [(Name, NonEmpty a)]
other)
([Name], [Name]) -> m ([Name], [Name])
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (((Name, List1 (Imported a)) -> Name)
-> [(Name, List1 (Imported a))] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map (Name, List1 (Imported a)) -> Name
forall a b. (a, b) -> a
fst [(Name, List1 (Imported a))]
used, ((Name, List1 (Imported a)) -> Name)
-> [(Name, List1 (Imported a))] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map (Name, List1 (Imported a)) -> Name
forall a b. (a, b) -> a
fst [(Name, List1 (Imported a))]
unused)
class (Ord a, Show a, Pretty a) => Lineage a where
lineage :: a -> WhyInScope
instance Lineage AbstractName where
lineage :: AbstractName -> WhyInScope
lineage = AbstractName -> WhyInScope
anameLineage
instance Lineage AbstractModule where
lineage :: AbstractModule -> WhyInScope
lineage = AbstractModule -> WhyInScope
amodLineage
data Imported a = Imported
{ forall a. Imported a -> Int
iWhere :: Int
, forall a. Imported a -> a
iThing :: a
} deriving (Imported a -> Imported a -> Bool
(Imported a -> Imported a -> Bool)
-> (Imported a -> Imported a -> Bool) -> Eq (Imported a)
forall a. Eq a => Imported a -> Imported a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => Imported a -> Imported a -> Bool
== :: Imported a -> Imported a -> Bool
$c/= :: forall a. Eq a => Imported a -> Imported a -> Bool
/= :: Imported a -> Imported a -> Bool
Eq, Eq (Imported a)
Eq (Imported a) =>
(Imported a -> Imported a -> Ordering)
-> (Imported a -> Imported a -> Bool)
-> (Imported a -> Imported a -> Bool)
-> (Imported a -> Imported a -> Bool)
-> (Imported a -> Imported a -> Bool)
-> (Imported a -> Imported a -> Imported a)
-> (Imported a -> Imported a -> Imported a)
-> Ord (Imported a)
Imported a -> Imported a -> Bool
Imported a -> Imported a -> Ordering
Imported a -> Imported a -> Imported a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (Imported a)
forall a. Ord a => Imported a -> Imported a -> Bool
forall a. Ord a => Imported a -> Imported a -> Ordering
forall a. Ord a => Imported a -> Imported a -> Imported a
$ccompare :: forall a. Ord a => Imported a -> Imported a -> Ordering
compare :: Imported a -> Imported a -> Ordering
$c< :: forall a. Ord a => Imported a -> Imported a -> Bool
< :: Imported a -> Imported a -> Bool
$c<= :: forall a. Ord a => Imported a -> Imported a -> Bool
<= :: Imported a -> Imported a -> Bool
$c> :: forall a. Ord a => Imported a -> Imported a -> Bool
> :: Imported a -> Imported a -> Bool
$c>= :: forall a. Ord a => Imported a -> Imported a -> Bool
>= :: Imported a -> Imported a -> Bool
$cmax :: forall a. Ord a => Imported a -> Imported a -> Imported a
max :: Imported a -> Imported a -> Imported a
$cmin :: forall a. Ord a => Imported a -> Imported a -> Imported a
min :: Imported a -> Imported a -> Imported a
Ord, Int -> Imported a -> String -> String
[Imported a] -> String -> String
Imported a -> String
(Int -> Imported a -> String -> String)
-> (Imported a -> String)
-> ([Imported a] -> String -> String)
-> Show (Imported a)
forall a. Show a => Int -> Imported a -> String -> String
forall a. Show a => [Imported a] -> String -> String
forall a. Show a => Imported a -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: forall a. Show a => Int -> Imported a -> String -> String
showsPrec :: Int -> Imported a -> String -> String
$cshow :: forall a. Show a => Imported a -> String
show :: Imported a -> String
$cshowList :: forall a. Show a => [Imported a] -> String -> String
showList :: [Imported a] -> String -> String
Show)
instance Pretty a => Pretty (Imported a) where
pretty :: Imported a -> Doc
pretty (Imported Int
i a
n) = a -> Doc
forall a. Pretty a => a -> Doc
pretty a
n Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Doc
" (at position " Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Int -> Doc
forall a. Pretty a => a -> Doc
pretty Int
i Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Doc
")"
toImported :: Lineage a => a -> Maybe (Imported a)
toImported :: forall a. Lineage a => a -> Maybe (Imported a)
toImported a
x = case a -> WhyInScope
forall a. Lineage a => a -> WhyInScope
lineage a
x of
Opened QName
m WhyInScope
_ -> QName -> Maybe Int
forall a. HasRange a => a -> Maybe Int
rangeToPosPos QName
m Maybe Int -> (Int -> Imported a) -> Maybe (Imported a)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Int -> a -> Imported a
forall a. Int -> a -> Imported a
`Imported` a
x)
Applied{} -> Maybe (Imported a)
forall a. Maybe a
Nothing
Defined{} -> Maybe (Imported a)
forall a. Maybe a
Nothing
stUnambiguousLookups :: Lens' TCState [AbstractName]
stUnambiguousLookups :: Lens' TCState [AbstractName]
stUnambiguousLookups = (UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState
Lens' TCState UnusedImportsState
stUnusedImportsState ((UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState)
-> (([AbstractName] -> f [AbstractName])
-> UnusedImportsState -> f UnusedImportsState)
-> ([AbstractName] -> f [AbstractName])
-> TCState
-> f TCState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([AbstractName] -> f [AbstractName])
-> UnusedImportsState -> f UnusedImportsState
Lens' UnusedImportsState [AbstractName]
lensUnambiguousLookups
stAmbiguousLookups :: Lens' TCState (IntMap (List2 AbstractName))
stAmbiguousLookups :: Lens' TCState (IntMap (List2 AbstractName))
stAmbiguousLookups = (UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState
Lens' TCState UnusedImportsState
stUnusedImportsState ((UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState)
-> ((IntMap (List2 AbstractName)
-> f (IntMap (List2 AbstractName)))
-> UnusedImportsState -> f UnusedImportsState)
-> (IntMap (List2 AbstractName) -> f (IntMap (List2 AbstractName)))
-> TCState
-> f TCState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IntMap (List2 AbstractName) -> f (IntMap (List2 AbstractName)))
-> UnusedImportsState -> f UnusedImportsState
Lens' UnusedImportsState (IntMap (List2 AbstractName))
lensAmbiguousLookups
stModuleLookups :: Lens' TCState [AbstractModule]
stModuleLookups :: Lens' TCState [AbstractModule]
stModuleLookups = (UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState
Lens' TCState UnusedImportsState
stUnusedImportsState ((UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState)
-> (([AbstractModule] -> f [AbstractModule])
-> UnusedImportsState -> f UnusedImportsState)
-> ([AbstractModule] -> f [AbstractModule])
-> TCState
-> f TCState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([AbstractModule] -> f [AbstractModule])
-> UnusedImportsState -> f UnusedImportsState
Lens' UnusedImportsState [AbstractModule]
lensModuleLookups
stOpenedModules :: Lens' TCState (IntMap OpenedModule)
stOpenedModules :: Lens' TCState (IntMap OpenedModule)
stOpenedModules = (UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState
Lens' TCState UnusedImportsState
stUnusedImportsState ((UnusedImportsState -> f UnusedImportsState)
-> TCState -> f TCState)
-> ((IntMap OpenedModule -> f (IntMap OpenedModule))
-> UnusedImportsState -> f UnusedImportsState)
-> (IntMap OpenedModule -> f (IntMap OpenedModule))
-> TCState
-> f TCState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IntMap OpenedModule -> f (IntMap OpenedModule))
-> UnusedImportsState -> f UnusedImportsState
Lens' UnusedImportsState (IntMap OpenedModule)
lensOpenedModules