weeder: Detect dead code

[ bsd3, development, library, program, unclassified ] [ Propose Tags ]

Find declarations.


[Skip to Readme]
Versions [faq] 0.1, 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7, 0.1.8, 0.1.9, 0.1.10, 0.1.11, 0.1.12, 0.1.13, 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9, 2.0.0, 2.0.1, 2.1.0
Change log CHANGELOG.md
Dependencies algebraic-graphs (>=0.4 && <0.6), base (>=4.13.0.0 && <4.14 || >=4.14.0.0 && <4.15), bytestring (>=0.10.9.0 && <0.11), containers (>=0.6.2.1 && <0.7), dhall (>=1.30.0 && <1.31 || >=1.31.0 && <1.32 || >=1.32.0 && <1.33 || >=1.33.0 && <1.34), directory (>=1.3.3.2 && <1.4), filepath (>=1.4.2.1 && <1.5), generic-lens (>=1.1.0.0 && <1.2 || >=1.2.0.0 && <1.3 || >=2.0.0.0 && <2.1), ghc (>=8.8.1 && <8.9 || ==8.10.*), lens (>=4.18.1 && <4.20), mtl (>=2.2.2 && <2.3), optparse-applicative (>=0.14.3.0 && <0.15 || >=0.15.1.0 && <0.16), regex-tdfa (>=1.2.0.0 && <1.3 || >=1.3.1.0 && <1.4), text (>=1.2.3.0 && <1.3), transformers (>=0.5.6.2 && <0.6), weeder [details]
License BSD-3-Clause
Copyright Neil Mitchell 2017-2020, Oliver Charles 2020
Author Ollie Charles <ollie@ocharles.org.uk>
Maintainer Ollie Charles <ollie@ocharles.org.uk>
Category Development
Home page https://github.com/ocharles/weeder#readme
Bug tracker https://github.com/ocharles/weeder/issues
Uploaded by OliverCharles at 2020-06-30T14:02:33Z
Distributions LTSHaskell:1.0.8, NixOS:2.0.1, Stackage:1.0.8
Executables weeder
Downloads 11225 total (704 in the last 30 days)
Rating 2.5 (votes: 5) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs not available [build log]
All reported builds failed as of 2020-06-30 [all 3 reports]

Modules

  • Weeder
    • Weeder.Config
    • Weeder.Main

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for weeder-2.1.0

[back to package description]

Weeder

Weeder is an application to perform whole-program dead-code analysis. Dead code is code that is written, but never reachable from any other code. Over the lifetime of a project, this happens as code is added and removed, and leftover code is never cleaned up. While GHC has warnings to detect dead code is a single module, these warnings don't extend across module boundaries - this is where Weeder comes in.

Weeder uses HIE files produced by GHC - these files can be thought of as source code that has been enhanced by GHC, adding full symbol resolution and type information. Weeder builds a dependency graph from these files to understand how code interacts. Once all analysis is done, Weeder performs a traversal of this graph from a set of roots (e.g., your main function), and determines which code is reachable and which code is dead.

Using Weeder

Preparing Your Code for Weeder

To use Weeder, you will need to generate .hie files from your source code.

Cabal

If you use Cabal, this is easily done by adding one line to your cabal.project.local file:

package *
  ghc-options: -fwrite-ide-info

Once this has been added, perform a full rebuild of your project:

cabal clean
cabal build all

Stack

If you use stack, add the following to your stack.yaml:

ghc-options:
  "$locals": -fwrite-ide-info

and rebuild:

stack clean
stack build

Calling Weeder

To call Weeder, you first need to provide a configuration file, weeder.dhall. Weeder uses Dhall as its configuration format, and configuration files have the type:

{ roots : List Text, type-class-roots : Bool }

roots is a list of regular expressions of symbols that are considered as alive. If you're building an executable, the pattern ^Main.main$ is a good starting point - specifying that main is a root. Weeder currently doesn't add all exported functions a roots automatically but in many cases main from a test suite could be a good workaround for that

type-class-roots configures whether or not Weeder should consider anything in a type class instance as a root. Weeder is currently unable to add dependency edges into type class instances, and without this flag may produce false positives. It's recommended to initially set this to True:

{ roots = [ "^Main.main$" ], type-class-roots = True }

Now invoke the weeder executable, and - if your project has weeds - you will see something like the following:

$ weeder

src/Dhall/TH.hs:187:1: error: toDeclaration is unused

     185 ┃     -> HaskellType (Expr s a)
     186 ┃     -> Q Dec
     187 ┃ toDeclaration haskellTypes MultipleConstructors{..} = do
     188 ┃     case code of
     189 ┃         Union kts -> do

    Delete this definition or add ‘Dhall.TH.toDeclaration’ as a root to fix this error.


src/Dhall/TH.hs:106:1: error: toNestedHaskellType is unused

     104 ┃     -- ^ Dhall expression to convert to a simple Haskell type
     105 ┃     -> Q Type
     106 ┃ toNestedHaskellType haskellTypes = loop
     107 ┃   where
     108 ┃     loop dhallType = case dhallType of

    Delete this definition or add ‘Dhall.TH.toNestedHaskellType’ as a root to fix this error.

(Please note these warnings are just for demonstration and not necessarily weeds in the Dhall project).

Tips

  • You may want to add ^Paths_.* to the roots in weeder.dhall to ignore the Paths_packageName module automatically generated by Cabal.

Limitations

Weeder currently has a few limitations:

Type Class Instances

Weeder is not currently able to analyse whether a type class instance is used. For this reason, Weeder adds all symbols referenced to from a type class instance to the root set, keeping this code alive. In short, this means Weeder might not detect dead code if it's used from a type class instance which is never actually needed.

You can toggle whether Weeder consider type class instances as roots with the type-class-roots configuration option.

Template Haskell

Weeder is currently unable to parse the result of a Template Haskell splice. If some Template Haskell code refers to other source code, this dependency won't be tracked by Weeder, and thus Weeder might end up with false positives.