9e0f88e8

By: Tom Sydney Kerckhove <syd@cs-syd.eu>

Say what a path is, and add the rule that holds us to it

A FilePath is a String, so nothing about it says whether it holds a file or a
directory, whether it is absolute or relative, or whether it is a path at all.
Every function taking one documents what it accepts and then trusts its
callers.

HsNoFilePath reports the type where a module's own signatures use it. Read off
the token stream rather than the parse tree, because that is where a name the
code wrote is already told apart from the same word in a comment, in a string
literal, or in the tail of a module name: `-- a FilePath is a String` and
`"a FilePath is a String"` are each one token of their own, and a golden asserts
both stay quiet.

Each finding is scoped to the declaration it is inside, so a boundary that
genuinely wants a String is suppressed at that declaration and nowhere wider.
Converting at the edge is not reported at all: `readFile (toFilePath file)` is
correct and stays quiet.

The repository is clean under it. Twenty findings, all in the test specs, are
gone: `resourceDir` is a `Path Rel Dir`, the three copies of `rootAt` take one,
and `listDirRel` answers with directories and files already told apart, which
several listing assertions are now exact about rather than comparing sorted
strings. `hopinion-gen` no longer depends on `directory`.

The library needed no changes to pass, which is worth saying: it had no FilePath
in its own signatures already. Its one word-comparison of a directory name is
now a comparison of directories.

What is not here: the same rule over `import System.FilePath` and
`import System.Directory`. An import is not a declaration, so the comment
attachment pass has nowhere to attach a suppression above one, and a
file-scoped suppression would exempt every other finding in the file. That
wants an AttachedToImport first.