splint: HLint as a GHC source plugin.

[ development, library ] [ Propose Tags ]

Splint makes HLint 3 available as a GHC source plugin. To use it, pass -fplugin=Splint to GHC. Any options passed to Splint are passed through to HLint. For example you can use -fplugin-opt=Splint:'--ignore=Use concatMap' to ignore the "Use concatMap" suggestion.


[Skip to Readme]
Versions [faq] 1.0.0.0, 1.0.0.1, 1.0.1.0, 1.0.1.1, 1.0.1.2
Dependencies base (>=4.12.0 && <4.15), ghc (>=8.6.1 && <8.11), hlint (>=3.0 && <3.2) [details]
License ISC
Author
Maintainer Taylor Fausak
Category Development
Source repo head: git clone https://github.com/tfausak/splint
Uploaded by fozworth at 2020-05-26T14:39:36Z
Distributions NixOS:1.0.1.2
Downloads 304 total (15 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs available [build log]
Last success reported on 2020-05-26 [all 1 reports]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for splint-1.0.1.0

[back to package description]

Splint

Travis CI Hackage Stackage

Splint makes HLint 3 available as a GHC source plugin. It is similar to hlint-source-plugin by Ollie Charles, except that it doesn't have to re-parse the module in order to lint it.

To use Splint, pass -fplugin=Splint to GHC. Any ideas suggested by HLint will be reported as warnings by GHC. For example, if you define Main.hs as:

main = print . concat $ map pure [ 'a' .. 'z' ]

You would expect HLint to tell you to use concatMap. Normally you would need to both compile your module with GHC and lint it with HLint. However with Splint you can compile it and get suggestions from HLint all at once by running:

ghc -fplugin=Splint Main.hs

Among all the usual output from GHC, you should see this new warning:

Main.hs:1:8: warning:
    Use concatMap
    Perhaps: print (concatMap pure ['a' .. 'z'])
  |
1 | main = print . concat $ map pure [ 'a' .. 'z' ]
  |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

And that's all there is to it! HLint suggestions as part of your normal build process. What a time to be alive.

If you want to pass arguments through to HLint, you can use -fplugin-opt=Splint:arg. For example you can ignore the warning above with -fplugin-opt=Splint:'--ignore=Use concatMap'.

Trade offs

Running HLint as a GHC source plugin has some upsides:

  • Modules are only linted when they're compiled, so if they haven't changed they won't be linted again.

  • HLint's suggestions are reported just like GHC's warnings. They're formatted the same way and they're reported at the same time.

  • Each module is only parsed once.

  • Parsing is done by GHC instead of something like haskell-src-exts. HLint already works like this, but by using a plugin you can be sure that all of the versions and options line up correctly.

However it's also got some downsides:

  • Using Splint means adding it as a dependency to the targets you want to lint. Normally HLint is either a test dependency or just installed on the system.

    You may be able to lessen the impact of this by providing a flag to control linting. That way you can enable it locally and in CI, but not require everything downstream of you to depend on HLint.

    flag lint
      default: False
      manual: True
    library
      if flag(lint)
        build-depends: splint
        ghc-options: -fplugin=Splint
    
  • It's slower. I've found that it adds about a tenth of a second per module.

  • You can't use the automated refactorings that HLint provides.

  • Using plugins marks every module as unsafe.