@@ -4,176 +4,78 @@
5-- | Manipulations on import lists.
5-- | Manipulations on import lists.
6module Ormolu.Imports
6module Ormolu.Imports
7− ( normalizeImports,
7+ ( sortImports,
11import Data.Bifunctor
11import Data.Bifunctor
12import Data.Char (isAlphaNum)
12import Data.Char (isAlphaNum)
13import Data.Function (on)
13import Data.Function (on)
14+import Data.Generics (gcompare)
14−import Data.List (foldl', nubBy, sortBy, sortOn)
15+import Data.List (nubBy, sortBy)
15−import Data.Map.Strict (Map)
16−import qualified Data.Map.Strict as M
17−import FastString (FastString)
18import GHC hiding (GhcPs, IE)
16import GHC hiding (GhcPs, IE)
19import GHC.Hs.Extension
17import GHC.Hs.Extension
20import GHC.Hs.ImpExp (IE (..))
18import GHC.Hs.ImpExp (IE (..))
21import Ormolu.Utils (notImplemented, showOutputable)
19import Ormolu.Utils (notImplemented, showOutputable)
23−-- | Sort and normalize imports.
21+-- | Sort imports by module name. This also sorts explicit import lists for
24−normalizeImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
23+sortImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
25−normalizeImports =
24+sortImports = sortBy compareIdecl . fmap (fmap sortImportLists)
28− . M.fromListWith combineImports
29− . fmap (\x -> (importId x, g x))
31− g (L l ImportDecl {..}) =
26+ sortImportLists :: ImportDecl GhcPs -> ImportDecl GhcPs
32− L
27+ sortImportLists = \case
33− l
28+ ImportDecl {..} ->
34 ImportDecl
29 ImportDecl
35− { ideclHiding = second (fmap normalizeLies) <$> ideclHiding,
30+ { ideclHiding = second (fmap sortLies) <$> ideclHiding,
38− g _ = notImplemented "XImportDecl"
33+ XImportDecl x -> noExtCon x
40−-- | Combine two import declarations. It should be assumed that 'ImportId's
44− LImportDecl GhcPs ->
35+-- | Compare two @'LImportDecl' 'GhcPs'@ things.
45− LImportDecl GhcPs
36+compareIdecl :: LImportDecl GhcPs -> LImportDecl GhcPs -> Ordering
46−combineImports (L lx ImportDecl {..}) (L _ y) =
37+compareIdecl (L _ m0) (L _ m1) =
47− L
38+ case (isPrelude n0, isPrelude n1) of
48− lx
39+ (False, False) -> n0 `compare` n1
49− ImportDecl
40+ (True, False) -> GT
50− { ideclHiding = case (ideclHiding, GHC.ideclHiding y) of
41+ (False, True) -> LT
51− (Just (hiding, L l' xs), Just (_, L _ ys)) ->
42+ (True, True) -> m0 `gcompare` m1
52− Just (hiding, (L l' (normalizeLies (xs ++ ys))))
56−combineImports _ _ = notImplemented "XImportDecl"
58−-- | Import id, a collection of all things that justify having a separate
59−-- import entry. This is used for merging of imports. If two imports have
60−-- the same 'ImportId' they can be merged.
61−data ImportId = ImportId
62− { importIsPrelude :: Bool,
63− importIdName :: ModuleName,
64− importPkgQual :: Maybe FastString,
65− importSource :: Bool,
67− importQualified :: Bool,
68− importImplicit :: Bool,
69− importAs :: Maybe ModuleName,
70− importHiding :: Maybe Bool
74−-- | Obtain an 'ImportId' for a given import.
75−importId :: LImportDecl GhcPs -> ImportId
76−importId (L _ ImportDecl {..}) =
78− { importIsPrelude = isPrelude,
79− importIdName = moduleName,
80− importPkgQual = sl_fs <$> ideclPkgQual,
81− importSource = ideclSource,
82− importSafe = ideclSafe,
83− importQualified = case ideclQualified of
85− QualifiedPost -> True
86− NotQualified -> False,
87− importImplicit = ideclImplicit,
88− importAs = unLoc <$> ideclAs,
89− importHiding = fst <$> ideclHiding
44+ n0 = unLoc (ideclName m0)
45+ n1 = unLoc (ideclName m1)
92− isPrelude = moduleNameString moduleName == "Prelude"
46+ isPrelude = (== "Prelude") . moduleNameString
93− moduleName = unLoc ideclName
94−importId _ = notImplemented "XImportDecl"
96−-- | Normalize a collection of import\/export items.
48+-- | Sort located import or export, dropping duplicates.
97−normalizeLies :: [LIE GhcPs] -> [LIE GhcPs]
49+sortLies :: [LIE GhcPs] -> [LIE GhcPs]
98−normalizeLies = sortOn (getIewn . unLoc) . M.elems . foldl' combine M.empty
50+sortLies =
99− where
51+ nubBy (\x y -> compareLIE x y == EQ)
100− combine ::
52+ . sortBy compareLIE
101− Map IEWrappedNameOrd (LIE GhcPs) ->
53+ . fmap (fmap sortThings)
103− Map IEWrappedNameOrd (LIE GhcPs)
104− combine m (L new_l new) =
105− let wname = getIewn new
107− nubBy (\x y -> compareLIewn x y == EQ) . sortBy compareLIewn
109− Nothing -> Just . L new_l $
111− IEThingWith NoExtField n wildcard g flbl ->
112− IEThingWith NoExtField n wildcard (normalizeWNames g) flbl
116− IEVar NoExtField n -> IEVar NoExtField n
117− IEThingAbs NoExtField _ -> new
118− IEThingAll NoExtField n -> IEThingAll NoExtField n
119− IEThingWith NoExtField n wildcard g flbl ->
121− IEVar NoExtField _ ->
122− error "Ormolu.Imports broken presupposition"
123− IEThingAbs NoExtField _ ->
124− IEThingWith NoExtField n wildcard g flbl
125− IEThingAll NoExtField n' ->
126− IEThingAll NoExtField n'
127− IEThingWith NoExtField n' wildcard' g' flbl' ->
128− let combinedWildcard =
129− case (wildcard, wildcard') of
130− (IEWildcard _, _) -> IEWildcard 0
131− (_, IEWildcard _) -> IEWildcard 0
137− (normalizeWNames (g <> g'))
139− IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
140− IEGroup NoExtField _ _ -> notImplemented "IEGroup"
141− IEDoc NoExtField _ -> notImplemented "IEDoc"
142− IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
144− IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
145− IEGroup NoExtField _ _ -> notImplemented "IEGroup"
146− IEDoc NoExtField _ -> notImplemented "IEDoc"
147− IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
150− in M.alter alter wname m
152−-- | A wrapper for @'IEWrappedName' 'RdrName'@ that allows us to define an
55+-- | Sort imports\/exports inside of 'IEThingWith'.
153−-- 'Ord' instance for it.
56+sortThings :: IE GhcPs -> IE GhcPs
154−newtype IEWrappedNameOrd = IEWrappedNameOrd (IEWrappedName RdrName)
57+sortThings = \case
155− deriving (Eq)
58+ IEThingWith NoExtField x w xs fl ->
59+ IEThingWith NoExtField x w (sortBy (compareIewn `on` unLoc) xs) fl
157−instance Ord IEWrappedNameOrd where
62+-- | Compare a pair of located imports or exports.
158− compare (IEWrappedNameOrd x) (IEWrappedNameOrd y) = compareIewn x y
63+compareLIE :: LIE GhcPs -> LIE GhcPs -> Ordering
64+compareLIE = compareIewn `on` getIewn . unLoc
160-- | Project @'IEWrappedName' 'RdrName'@ from @'IE' 'GhcPs'@.
66-- | Project @'IEWrappedName' 'RdrName'@ from @'IE' 'GhcPs'@.
161−getIewn :: IE GhcPs -> IEWrappedNameOrd
67+getIewn :: IE GhcPs -> IEWrappedName RdrName
162getIewn = \case
68getIewn = \case
163− IEVar NoExtField x -> IEWrappedNameOrd (unLoc x)
69+ IEVar NoExtField x -> unLoc x
164− IEThingAbs NoExtField x -> IEWrappedNameOrd (unLoc x)
70+ IEThingAbs NoExtField x -> unLoc x
165− IEThingAll NoExtField x -> IEWrappedNameOrd (unLoc x)
71+ IEThingAll NoExtField x -> unLoc x
166− IEThingWith NoExtField x _ _ _ -> IEWrappedNameOrd (unLoc x)
72+ IEThingWith NoExtField x _ _ _ -> unLoc x
167 IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
73 IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
168 IEGroup NoExtField _ _ -> notImplemented "IEGroup"
74 IEGroup NoExtField _ _ -> notImplemented "IEGroup"
169 IEDoc NoExtField _ -> notImplemented "IEDoc"
75 IEDoc NoExtField _ -> notImplemented "IEDoc"
170 IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
76 IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
171 XIE x -> noExtCon x
77 XIE x -> noExtCon x
173−-- | Like 'compareIewn' for located wrapped names.
174−compareLIewn :: LIEWrappedName RdrName -> LIEWrappedName RdrName -> Ordering
175−compareLIewn = compareIewn `on` unLoc
177-- | Compare two @'IEWrapppedName' 'RdrName'@ things.
79-- | Compare two @'IEWrapppedName' 'RdrName'@ things.
178compareIewn :: IEWrappedName RdrName -> IEWrappedName RdrName -> Ordering
80compareIewn :: IEWrappedName RdrName -> IEWrappedName RdrName -> Ordering
179compareIewn (IEName x) (IEName y) = unLoc x `compareRdrName` unLoc y
81compareIewn (IEName x) (IEName y) = unLoc x `compareRdrName` unLoc y