91194d4c

Created Started Cancelled

#1701, add a "Redundant module qualifier" hint

Implements #1701, on top of the `require-type-applications` branch (#1637), so review that one first.

Type occurrences like `Map.Map`, `Set.Set` or `Text.Text` stutter: the qualifier's last component repeats the type name. A module may be imported twice, so the qualified import can stay and a second import brings just the type into scope unqualified:

```haskell
import Data.Map (Map)
import Data.Map qualified as Map
```

The hint says exactly that in a note, naming the module the qualifier resolves to via `possModules`:

```
Foo.hs:5:15-21: Suggestion: Redundant module qualifier
Found:
  Map.Map
Perhaps:
  Map
Note: requires importing Data.Map (Map)
```

When the qualifier is ambiguous (two modules aliased the same), it falls back to "requires importing Map unqualified". The note deliberately does not say whether the new import joins the qualified one or replaces it: that depends on whether the qualifier is used elsewhere in the module, and getting it wrong leaves an unused import.

### Scope

Fires on any type occurrence of the shape `<X>.<X>`, so both `Map.Map` and `Data.Map.Map`, in signatures, `data`/`newtype` declarations, type synonyms, instance heads and expression type annotations. Value-level occurrences are untouched.

Severity is `Suggestion` (on by default), since whether the extra import is worth it is a matter of taste.

### What it finds in HLint itself

31 occurrences across 8 files, which I have deliberately **not** changed in this PR — happy to add a follow-up commit applying them if you want it. CI is unaffected, since the `ndmitchell/neil` step lints with a released HLint. The breakdown:

| File | Count | Type |
| --- | --- | --- |
| `src/Idea.hs` | 10 | `GHC.Utils.Outputable.Outputable` |
| `src/Hint/Restrict.hs` | 10 | `Map.Map` |
| `src/Hint/Extensions.hs` | 5 | `Map.Map`, `Set.Set` |
| `src/Hint/Duplicate.hs` | 2 | `Map.Map` |
| `src/GHC/All.hs` | 1 | `GHC.Types.Fixity.Fixity` |
| `src/GHC/Util/ApiAnnotation.hs` | 1 | `Set.Set` |
| `src/Hint/Naming.hs` | 1 | `Set.Set` |
| `src/Hint/Smell.hs` | 1 | `Map.Map` |

The `src/Idea.hs` ones are worth a look: `GHC.Utils.Outputable` is already imported unqualified there, so those 10 need no new import at all.

### No refactoring

Dropping the qualifier only compiles once the type is in scope unqualified, which HLint cannot arrange, so the hint offers no `Refactoring` rather than letting `--refactor` produce code that does not build.

### Testing

`hlint --test` passes. The `<TEST>` block covers positives, the `Data.Map.Map` form, negatives (`Map.Key`, `Data.Map.Strict.Map`, `M.Map` under a non-stuttering alias, value-level `Map.Map`, the import declaration itself), and asserts both the severity and the note text. The note test carries a real import so it exercises the scope lookup rather than the no-import path.

`hints.md` regenerated.

https://claude.ai/code/session_01JbL9Ex7jZ7ANs2HMeSuWgd
PR #2