@@ -164,88 +164,97 @@ checkPragmas modu flags exts mps =
164
164
data QualifiedPostOrPre = QualifiedPostOrPre deriving Eq
165
165
166
166
checkImports :: String -> [LImportDecl GhcPs ] -> (Bool , Map. Map String RestrictItem ) -> [Idea ]
167
- checkImports modu lImportDecls (def, mp) = mapMaybe getImportHint lImportDecls
167
+ checkImports modu lImportDecls (def, mp) = concatMap getImportHint lImportDecls
168
168
where
169
- getImportHint :: LImportDecl GhcPs -> Maybe Idea
169
+ getImportHint :: LImportDecl GhcPs -> [ Idea ]
170
170
getImportHint i@ (L _ ImportDecl {.. }) = do
171
- let RestrictItem {.. } = getRestrictItem def ideclName mp
172
- either (Just . ideaMessage riMessage) (const Nothing ) $ do
173
- unless (within modu " " riWithin) $
174
- Left $ ideaNoTo $ warn " Avoid restricted module" (reLoc i) (reLoc i) []
175
-
176
- let importedIdents = Set. fromList $
177
- case first (== EverythingBut ) <$> ideclImportList of
178
- Just (False , lxs) -> concatMap (importListToIdents . unLoc) (unLoc lxs)
179
- _ -> []
180
- invalidIdents = case riRestrictIdents of
181
- NoRestrictIdents -> Set. empty
182
- ForbidIdents badIdents -> importedIdents `Set.intersection` Set. fromList badIdents
183
- OnlyIdents onlyIdents -> importedIdents `Set.difference` Set. fromList onlyIdents
184
- unless (Set. null invalidIdents) $
185
- Left $ ideaNoTo $ warn " Avoid restricted identifiers" (reLoc i) (reLoc i) []
186
-
187
- let qualAllowed = case (riAs, ideclAs) of
188
- ([] , _) -> True
189
- (_, Nothing ) -> maybe True not $ getAlt riAsRequired
190
- (_, Just (L _ modName)) -> moduleNameString modName `elem` riAs
191
- unless qualAllowed $ do
192
- let i' = noLoc $ (unLoc i){ ideclAs = noLocA . mkModuleName <$> listToMaybe riAs }
193
- Left $ warn " Avoid restricted alias" (reLoc i) i' []
194
-
195
- let (expectedQual, expectedHiding) =
196
- case fromMaybe ImportStyleUnrestricted $ getAlt riImportStyle of
197
- ImportStyleUnrestricted
198
- | NotQualified <- ideclQualified -> (Nothing , Nothing )
199
- | otherwise -> (Just $ second (<> " or unqualified" ) expectedQualStyle, Nothing )
200
- ImportStyleQualified -> (Just expectedQualStyle, Nothing )
201
- ImportStyleExplicitOrQualified
202
- | Just (False , _) <- first (== EverythingBut ) <$> ideclImportList -> (Nothing , Nothing )
203
- | otherwise ->
204
- ( Just $ second (<> " or with an explicit import list" ) expectedQualStyle
205
- , Nothing )
206
- ImportStyleExplicit
207
- | Just (False , _) <- first (== EverythingBut ) <$> ideclImportList -> (Nothing , Nothing )
208
- | otherwise ->
209
- ( Just (Right NotQualified , " unqualified" )
210
- , Just $ Just (Exactly , noLocA [] ) )
211
- ImportStyleUnqualified -> (Just (Right NotQualified , " unqualified" ), Nothing )
212
- expectedQualStyle =
213
- case fromMaybe QualifiedStyleUnrestricted $ getAlt riQualifiedStyle of
214
- QualifiedStyleUnrestricted -> (Left QualifiedPostOrPre , " qualified" )
215
- QualifiedStylePost -> (Right QualifiedPost , " post-qualified" )
216
- QualifiedStylePre -> (Right QualifiedPre , " pre-qualified" )
217
- -- unless expectedQual is Nothing, it holds the Idea (hint) to ultimately emit,
218
- -- except in these cases when the rule's requirements are fulfilled in-source:
219
- qualIdea
220
- -- the rule demands a particular importStyle, and the decl obeys exactly
221
- | Just (Right ideclQualified) == (fst <$> expectedQual) = Nothing
222
- -- the rule demands a QualifiedPostOrPre import, and the decl does either
223
- | Just (Left QualifiedPostOrPre ) == (fst <$> expectedQual)
224
- && ideclQualified `elem` [QualifiedPost , QualifiedPre ] = Nothing
225
- -- otherwise, expectedQual gets converted into a warning below (or is Nothing)
226
- | otherwise = expectedQual
227
- whenJust qualIdea $ \ (qual, hint) -> do
228
- -- convert non-Nothing qualIdea into hlint's refactoring Idea
229
- let i' = noLoc $ (unLoc i){ ideclQualified = fromRight QualifiedPre qual
230
- , ideclImportList = fromMaybe ideclImportList expectedHiding }
231
- msg = moduleNameString (unLoc ideclName) <> " should be imported " <> hint
232
- Left $ warn msg (reLoc i) i' []
233
-
234
- getRestrictItem :: Bool -> LocatedA ModuleName -> Map. Map String RestrictItem -> RestrictItem
235
- getRestrictItem def ideclName =
236
- fromMaybe (RestrictItem mempty mempty mempty mempty [(" " ," " ) | def] NoRestrictIdents Nothing )
237
- . lookupRestrictItem ideclName
238
-
239
- lookupRestrictItem :: LocatedA ModuleName -> Map. Map String RestrictItem -> Maybe RestrictItem
171
+ let restrictItems = getRestrictItem def ideclName mp
172
+ flip mapMaybe restrictItems $ \ RestrictItem {.. } ->
173
+ either (Just . ideaMessage riMessage) (const Nothing ) $ do
174
+ unless (within modu " " riWithin) $
175
+ Left $ ideaNoTo $ warn " Avoid restricted module" (reLoc i) (reLoc i) []
176
+
177
+ let importedIdents = Set. fromList $
178
+ case first (== EverythingBut ) <$> ideclImportList of
179
+ Just (False , lxs) -> concatMap (importListToIdents . unLoc) (unLoc lxs)
180
+ _ -> []
181
+ invalidIdents = case riRestrictIdents of
182
+ NoRestrictIdents -> Set. empty
183
+ ForbidIdents badIdents -> importedIdents `Set.intersection` Set. fromList badIdents
184
+ OnlyIdents onlyIdents -> importedIdents `Set.difference` Set. fromList onlyIdents
185
+ unless (Set. null invalidIdents) $
186
+ Left $ ideaNoTo $ warn " Avoid restricted identifiers" (reLoc i) (reLoc i) []
187
+
188
+ let qualAllowed = case (riAs, ideclAs) of
189
+ ([] , _) -> True
190
+ (_, Nothing ) -> maybe True not $ getAlt riAsRequired
191
+ (_, Just (L _ modName)) -> moduleNameString modName `elem` riAs
192
+ unless qualAllowed $ do
193
+ let i' = noLoc $ (unLoc i){ ideclAs = noLocA . mkModuleName <$> listToMaybe riAs }
194
+ Left $ warn " Avoid restricted alias" (reLoc i) i' []
195
+
196
+ let (expectedQual, expectedHiding) =
197
+ case fromMaybe ImportStyleUnrestricted $ getAlt riImportStyle of
198
+ ImportStyleUnrestricted
199
+ | NotQualified <- ideclQualified -> (Nothing , Nothing )
200
+ | otherwise -> (Just $ second (<> " or unqualified" ) expectedQualStyle, Nothing )
201
+ ImportStyleQualified -> (Just expectedQualStyle, Nothing )
202
+ ImportStyleExplicitOrQualified
203
+ | Just (False , _) <- first (== EverythingBut ) <$> ideclImportList -> (Nothing , Nothing )
204
+ | otherwise ->
205
+ ( Just $ second (<> " or with an explicit import list" ) expectedQualStyle
206
+ , Nothing )
207
+ ImportStyleExplicit
208
+ | Just (False , _) <- first (== EverythingBut ) <$> ideclImportList -> (Nothing , Nothing )
209
+ | otherwise ->
210
+ ( Just (Right NotQualified , " unqualified" )
211
+ , Just $ Just (Exactly , noLocA [] ) )
212
+ ImportStyleUnqualified -> (Just (Right NotQualified , " unqualified" ), Nothing )
213
+ expectedQualStyle =
214
+ case fromMaybe QualifiedStyleUnrestricted $ getAlt riQualifiedStyle of
215
+ QualifiedStyleUnrestricted -> (Left QualifiedPostOrPre , " qualified" )
216
+ QualifiedStylePost -> (Right QualifiedPost , " post-qualified" )
217
+ QualifiedStylePre -> (Right QualifiedPre , " pre-qualified" )
218
+ -- unless expectedQual is Nothing, it holds the Idea (hint) to ultimately emit,
219
+ -- except in these cases when the rule's requirements are fulfilled in-source:
220
+ qualIdea
221
+ -- the rule demands a particular importStyle, and the decl obeys exactly
222
+ | Just (Right ideclQualified) == (fst <$> expectedQual) = Nothing
223
+ -- the rule demands a QualifiedPostOrPre import, and the decl does either
224
+ | Just (Left QualifiedPostOrPre ) == (fst <$> expectedQual)
225
+ && ideclQualified `elem` [QualifiedPost , QualifiedPre ] = Nothing
226
+ -- otherwise, expectedQual gets converted into a warning below (or is Nothing)
227
+ | otherwise = expectedQual
228
+ whenJust qualIdea $ \ (qual, hint) -> do
229
+ -- convert non-Nothing qualIdea into hlint's refactoring Idea
230
+ let i' = noLoc $ (unLoc i){ ideclQualified = fromRight QualifiedPre qual
231
+ , ideclImportList = fromMaybe ideclImportList expectedHiding }
232
+ msg = moduleNameString (unLoc ideclName) <> " should be imported " <> hint
233
+ Left $ warn msg (reLoc i) i' []
234
+
235
+ getRestrictItem :: Bool -> LocatedA ModuleName -> Map. Map String RestrictItem -> [RestrictItem ]
236
+ getRestrictItem def ideclName mp =
237
+ case lookupRestrictItem ideclName mp of
238
+ [] ->
239
+ pure (RestrictItem mempty mempty mempty mempty [(" " ," " ) | def] NoRestrictIdents Nothing )
240
+ restricts ->
241
+ restricts
242
+
243
+ lookupRestrictItem :: LocatedA ModuleName -> Map. Map String RestrictItem -> [RestrictItem ]
240
244
lookupRestrictItem ideclName mp =
241
245
let moduleName = moduleNameString $ unLoc ideclName
242
- exact = Map. lookup moduleName mp
243
- wildcard = nonEmpty
246
+ mexact = Map. lookup moduleName mp
247
+ wildcard = catMaybes . NonEmpty. toList . sequence . nonEmpty
244
248
. fmap snd
245
249
. reverse -- the hope is less specific matches will end up last, but it's not guaranteed
246
250
. filter (liftA2 (&&) (elem ' *' ) (`wildcardMatch` moduleName) . fst )
247
251
$ Map. toList mp
248
- in exact <> sconcat (sequence wildcard)
252
+ in
253
+ case mexact of
254
+ Nothing ->
255
+ wildcard
256
+ Just exact ->
257
+ [sconcat (exact NonEmpty. :| wildcard)]
249
258
250
259
importListToIdents :: IE GhcPs -> [String ]
251
260
importListToIdents =
0 commit comments