From 1e7dab820db2fdb6ad3e0a81fed9ea43b771506f Mon Sep 17 00:00:00 2001 From: Curtis Chin Jen Sem Date: Sat, 21 Mar 2026 12:58:18 +0100 Subject: [PATCH 1/2] Add setting for limitting explicit import lengths --- src/Config/Type.hs | 3 ++- src/Hint/Smell.hs | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Config/Type.hs b/src/Config/Type.hs index 19adb1368..e06120fa0 100644 --- a/src/Config/Type.hs +++ b/src/Config/Type.hs @@ -166,7 +166,7 @@ data Restrict = Restrict ,restrictMessage :: Maybe String } deriving Show -data SmellType = SmellLongFunctions | SmellLongTypeLists | SmellManyArgFunctions | SmellManyImports +data SmellType = SmellLongFunctions | SmellLongTypeLists | SmellManyArgFunctions | SmellManyImports | SmellManyExplicitImports deriving (Show,Eq,Ord) getSmellType :: String -> Maybe SmellType @@ -174,6 +174,7 @@ getSmellType "long functions" = Just SmellLongFunctions getSmellType "long type lists" = Just SmellLongTypeLists getSmellType "many arg functions" = Just SmellManyArgFunctions getSmellType "many imports" = Just SmellManyImports +getSmellType "many explicit imports" = Just SmellManyExplicitImports getSmellType _ = Nothing data Setting diff --git a/src/Hint/Smell.hs b/src/Hint/Smell.hs index 780923c8c..a95d4af3b 100644 --- a/src/Hint/Smell.hs +++ b/src/Hint/Smell.hs @@ -93,17 +93,34 @@ import Language.Haskell.GhclibParserEx.GHC.Utils.Outputable smellModuleHint :: [Setting] -> ModuHint smellModuleHint settings scope m = let (L _ mod) = ghcModule m - imports = hsmodImports mod in - case Map.lookup SmellManyImports (smells settings) of + imports = hsmodImports mod + sm = smells settings in + manyImportsHint sm imports ++ + concatMap (explicitImportLengthHint sm) imports + +manyImportsHint :: Map.Map SmellType Int -> [LImportDecl GhcPs] -> [Idea] +manyImportsHint sm imports = + case Map.lookup SmellManyImports sm of Just n | length imports >= n -> let span = foldl1 combineSrcSpans $ locA . getLoc <$> imports displayImports = unlines $ f <$> imports - in [rawIdea Config.Type.Warning "Many imports" span displayImports Nothing [] [] ] + in [rawIdea Config.Type.Warning "Many imports" span displayImports Nothing [] []] where f :: LImportDecl GhcPs -> String f = trimStart . unsafePrettyPrint _ -> [] +explicitImportLengthHint :: Map.Map SmellType Int -> LImportDecl GhcPs -> [Idea] +explicitImportLengthHint sm imp@(L _ decl) = + case Map.lookup SmellManyExplicitImports sm of + Just limit -> + case ideclImportList decl of + Just (Exactly, L _ names) | length names > limit -> + [rawIdea Config.Type.Warning "Too many explicit imports" (locA $ getLoc imp) + (trimStart $ unsafePrettyPrint imp) Nothing [] []] + _ -> [] + Nothing -> [] + smellHint :: [Setting] -> DeclHint smellHint settings scope m d = sniff smellLongFunctions SmellLongFunctions ++ From cd98ab36ff620757ff9afc1594f2db1395813c92 Mon Sep 17 00:00:00 2001 From: Curtis Chin Jen Sem Date: Sat, 21 Mar 2026 12:58:32 +0100 Subject: [PATCH 2/2] Add tests on explicit import lengths hint --- data/import_explicit_limit.yaml | 3 +++ src/Hint/Smell.hs | 14 +++++++++++++ tests/import_explicit_limit.test | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 data/import_explicit_limit.yaml create mode 100644 tests/import_explicit_limit.test diff --git a/data/import_explicit_limit.yaml b/data/import_explicit_limit.yaml new file mode 100644 index 000000000..b2ee69757 --- /dev/null +++ b/data/import_explicit_limit.yaml @@ -0,0 +1,3 @@ +- smell: + type: many explicit imports + limit: 2 diff --git a/src/Hint/Smell.hs b/src/Hint/Smell.hs index a95d4af3b..36fecb61c 100644 --- a/src/Hint/Smell.hs +++ b/src/Hint/Smell.hs @@ -74,6 +74,20 @@ import A import A; import B import A + + [{smell: { type: many explicit imports, limit: 2}}] +import A (x, y, z) -- +import A (x, y) +import A +import A hiding (x, y, z) + + + +import A (x, y, z) +import A (x, y) +import A +import A hiding (x, y, z) + -} import Hint.Type(ModuHint,ModuleEx(..),DeclHint,Idea(..),rawIdea,warn) diff --git a/tests/import_explicit_limit.test b/tests/import_explicit_limit.test new file mode 100644 index 000000000..b0d449b20 --- /dev/null +++ b/tests/import_explicit_limit.test @@ -0,0 +1,35 @@ +--------------------------------------------------------------------- +RUN tests/import_explicit_limit_pos.hs --hint=data/import_explicit_limit.yaml +FILE tests/import_explicit_limit_pos.hs +import A (sort, nub, group) +import B (Map, lookup, insert) +OUTPUT +tests/import_explicit_limit_pos.hs:1:1-27: Warning: Too many explicit imports +Found: + import A ( sort, nub, group ) + +tests/import_explicit_limit_pos.hs:2:1-30: Warning: Too many explicit imports +Found: + import B ( Map, lookup, insert ) + +2 hints + +--------------------------------------------------------------------- +RUN tests/import_explicit_limit_default.hs +FILE tests/import_explicit_limit_default.hs +import A (sort, nub, group) +import B (Map, lookup, insert) +OUTPUT +No hints + +--------------------------------------------------------------------- +RUN tests/import_explicit_limit_neg.hs --hint=data/import_explicit_limit.yaml +FILE tests/import_explicit_limit_neg.hs +import A (sort, nub) +import B (sort) +import C +import D hiding (sort, nub, group) +OUTPUT +No hints + +---------------------------------------------------------------------