zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

README.md (16969B)


      1 # Dialyxir
      2 
      3 [![Build Status](https://travis-ci.org/jeremyjh/dialyxir.svg?branch=master)](https://travis-ci.org/jeremyjh/dialyxir)
      4 [![Module Version](https://img.shields.io/hexpm/v/dialyxir.svg)](https://hex.pm/packages/dialyxir)
      5 [![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/dialyxir/)
      6 [![Total Download](https://img.shields.io/hexpm/dt/dialyxir.svg)](https://hex.pm/packages/dialyxir)
      7 [![License](https://img.shields.io/hexpm/l/dialyxir.svg)](https://github.com/jeremyjh/dialyxir/blob/master/LICENSE)
      8 [![Last Updated](https://img.shields.io/github/last-commit/jeremyjh/dialyxir.svg)](https://github.com/jeremyjh/dialyxir/commits/master)
      9 
     10 Mix tasks to simplify use of Dialyzer in Elixir projects.
     11 
     12 ## Changes in 1.0
     13 
     14 Elixir 1.6 is required, to support the new pretty printing feature. If your
     15 project is not yet on 1.6, continue to specify 0.5 in your mix deps.
     16 
     17 Warning messages have been greatly improved, but are filtered through the legacy formatter to support your existing ignore files. You can optionally use the new Elixir [term format](#elixir-term-format) for ignore files. You may want to use the `--format short` argument in your CI pipelines. There are several formats, also there is a new `explain` feature - for details see CLI [options](#command-line-options).
     18 
     19 ## Quickstart
     20 If you are planning to use Dialyzer with an application built with the [Phoenix Framework](http://www.phoenixframework.org/), check out the [Quickstart wiki](https://github.com/jeremyjh/dialyxir/wiki/Phoenix-Dialyxir-Quickstart).
     21 
     22 ## Installation
     23 
     24 Dialyxir is available on [hex.pm](https://hex.pm/packages/dialyxir).
     25 
     26 You can either add it as a dependency in your mix.exs, or install it globally as an archive task.
     27 
     28 To add it to a mix project, just add a line like this in your deps function in mix.exs:
     29 
     30 ```elixir
     31 defp deps do
     32   [
     33     {:dialyxir, "~> 1.0", only: [:dev], runtime: false},
     34   ]
     35 end
     36 ```
     37 
     38 ```console
     39 mix do deps.get, deps.compile
     40 ```
     41 
     42 ## Usage
     43 
     44 Use dialyxir from the directory of the mix project you want to analyze; a PLT file will be created or updated if required and the project will be automatically compiled.
     45 
     46 ```console
     47 mix dialyzer
     48 ```
     49 
     50 ### Command line options
     51 
     52   * `--no-compile`          - do not compile even if needed.
     53   * `--no-check`            - do not perform (quick) check to see if PLT needs to be updated.
     54   * `--ignore-exit-status`  - display warnings but do not halt the VM or return an exit status code.
     55   *  `--format short`       - format the warnings in a compact format, suitable for ignore file using Elixir term format.
     56   *  `--format raw`         - format the warnings in format returned before Dialyzer formatting.
     57   *  `--format dialyxir`    - format the warnings in a pretty printed format.
     58   *  `--format dialyzer`    - format the warnings in the original Dialyzer format, suitable for ignore file using simple string matches.
     59   *  `--format github`      - format the warnings in the Github Actions message format.
     60   *  `--format ignore_file` - format the warnings to be suitable for adding to Elixir Format ignore file.
     61   *  `--quiet`              - suppress all informational messages.
     62 
     63 Warning flags passed to this task are passed on to `:dialyzer` - e.g.
     64 
     65 ```console
     66 mix dialyzer --unmatched_returns
     67 ```
     68 
     69 There is information available about the warnings via the explain task - e.g.
     70 
     71 ```console
     72 mix dialyzer.explain unmatched_return
     73 ```
     74 
     75 If invoked without arguments, `mix dialyzer.explain` will list all the known warnings.
     76 
     77 ## Continuous Integration
     78 
     79 To use Dialyzer in CI, you must be aware of several things:
     80 
     81 1) Building the PLT file may take a while if a project has many dependencies
     82 2) The PLT should be cached using the CI caching system
     83 3) The PLT will need to be rebuilt whenever adding a new Erlang or Elixir version to build matrix
     84 
     85 ### Travis
     86 
     87 `.travis.yml`
     88 ```markdown
     89 language: elixir
     90 
     91 elixir:
     92   - 1.8
     93 
     94 otp_release:
     95   - 21.0
     96 
     97 script:
     98   - mix dialyzer
     99 
    100 cache:
    101   directories:
    102     - priv/plts
    103 ```
    104 
    105 ### Github Actions
    106 
    107 `dialyzer.yml`
    108 ```yaml
    109 ...
    110     steps:
    111       - uses: actions/checkout@v2
    112       - name: Set up Elixir
    113         id: beam
    114         uses: erlef/setup-beam@v1
    115         with:
    116           elixir-version: "1.12.3" # Define the elixir version
    117           otp-version: "24.1" # Define the OTP version
    118 
    119       # Don't cache PLTs based on mix.lock hash, as Dialyzer can incrementally update even old ones
    120       # Cache key based on Elixir & Erlang version (also useful when running in matrix)
    121       - name: Restore PLT cache
    122         uses: actions/cache@v2
    123         id: plt_cache
    124         with:
    125           key: |
    126             ${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
    127           restore-keys: |
    128             ${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
    129           path: |
    130             priv/plts
    131 
    132       # Create PLTs if no cache was found
    133       - name: Create PLTs
    134         if: steps.plt_cache.outputs.cache-hit != 'true'
    135         run: mix dialyzer --plt
    136 
    137       - name: Run dialyzer
    138         run: mix dialyzer --format github
    139 
    140 ```
    141 
    142 `mix.exs`
    143 ```elixir
    144 def project do
    145   [
    146     ...
    147     dialyzer: [
    148       plt_file: {:no_warn, "priv/plts/dialyzer.plt"}
    149     ]
    150   ]
    151 end
    152 ```
    153 
    154 `.gitignore`
    155 ```
    156 /priv/plts/*.plt
    157 /priv/plts/*.plt.hash
    158 ```
    159 
    160 ## With Explaining Stuff
    161 
    162 [Dialyzer](http://www.erlang.org/doc/apps/dialyzer/dialyzer_chapter.html) is a static analysis tool for Erlang and other languages that compile to BEAM bytecode for the Erlang VM. It can analyze the BEAM files and provide warnings about problems in your code including type mismatches and other issues that are commonly detected by static language compilers. The analysis can be improved by inclusion of type hints (called [specs](https://hexdocs.pm/elixir/typespecs.html)) but it can be useful even without those. For more information I highly recommend the [Success Typings](http://user.it.uu.se/~kostis/Papers/succ_types.pdf) paper that describes the theory behind the tool.
    163 
    164 
    165 Usage is straightforward but you should be aware of the available configuration settings you may wish to add to your mix.exs file.
    166 
    167 ### PLT
    168 
    169 The Persistent Lookup Table (PLT) is basically a cached output of the analysis. This is important because you'd probably stab yourself in the eye with
    170 a fork if you had to wait for Dialyzer to analyze all the standard library and OTP modules you are using every time you ran it.
    171 Running the mix task `dialyzer` by default builds several PLT files:
    172 
    173   * A core Erlang file in `$MIX_HOME/dialyxir_erlang-[OTP Version].plt`
    174   * A core Elixir file in `$MIX_HOME/dialyxir_erlang-[OTP Version]_elixir-[Elixir Version].plt`
    175   * A project environment specific file in `_build/env/dialyze_erlang-[OTP Version]_elixir-[Elixir Version]_deps-dev.plt`
    176 
    177 The core files are simply copied to your project folder when you run `dialyxir` for the first time with a given version of Erlang and Elixir. By default, all
    178 the modules in the project PLT are checked against your dependencies to be sure they are up to date. If you do not want to use MIX_HOME to store your core Erlang and Elixir files, you can provide a `:plt_core_path` key with a file path. You can specify a different directory for the project PLT file with the `:plt_local_path keyword`. You can specify a different filename for the project PLT file with the `:plt_file keyword` - this is deprecated because people were using it with the old `dialyxir` to have project-specific PLTs, which are now the default. To silence the deprecation warning, specify this value as `plt_file: {:no_warn, "/myproject/mypltfile"}`.
    179 
    180 The core PLTs include a basic set of OTP applications, as well as all of the Elixir standard libraries.
    181 The apps included by default are `[:erts, :kernel, :stdlib, :crypto]`.
    182 
    183 If you don't want to include the default apps you can specify a `:plt_apps` key and list there only the apps you want in the PLT. Using this option will mean dependencies are not added automatically (see below). If you want to just add an application to the list of defaults and dependencies you can use the `:plt_add_apps` key.
    184 
    185 If you want to ignore a specific dependency, you can specify it in the `:plt_ignore_apps` key.
    186 
    187 #### Dependencies
    188 
    189 OTP application dependencies are (transitively) added to your PLT by default. The applications added are the same as you would see displayed with the command `mix app.tree`. There is also a `:plt_add_deps` option you can set to control the dependencies added. The following options are supported:
    190 
    191   * `:apps_direct` - Only Direct OTP runtime application dependencies - not the entire tree
    192   * `:app_tree` - Transitive OTP runtime application dependencies e.g. `mix app.tree` (default)
    193 
    194 
    195 The example below changes the default to include only direct OTP dependencies, adds another specific dependency, and removes a dependency from the list. This can be helpful if a large dependency tree is creating memory issues and only some of the transitive dependencies are required for analysis.
    196 
    197 ```elixir
    198 def project do
    199   [
    200     app: :my_app,
    201     version: "0.0.1",
    202     deps: deps,
    203     dialyzer: [
    204       plt_add_deps: :apps_direct,
    205       plt_add_apps: [:wx],
    206       plt_ignore_apps: [:mnesia]
    207     ]
    208   ]
    209 end
    210 ```
    211 
    212 #### Explanations
    213 
    214 Explanations are available for classes of warnings by executing `mix dialyzer.explain warning_name`. It will include a description about the type of warning, as well as a small example that would also cause that warning. Poor explanations and examples should be considered issues in this library, and pull requests are very welcome! The warning name is returned from the `--format short` and `--format dialyzer` flags. List available warnings with `mix dialyzer.explain`.
    215 
    216 #### Formats
    217 
    218 Dialyxir supports formatting the errors in several different ways:
    219 
    220   * Short - By passing `--format short`, the structs and other spec/type information will be dropped from the error message, with a minimal message. This is useful for CI environments. Includes `warning_name ` for use in explanations.
    221   * Dialyzer - By passing `--format dialyzer`, the messages will be printed in the default Dialyzer format. This format is used in [legacy string matching](#simple-string-matches) ignore files.
    222   * Raw - By passing `--format raw`, messages will be printed in their form before being pretty printed by Dialyzer or Dialyxir.
    223   * Dialyxir (default) -- By passing `--format dialyxir`, messages will be converted to Elixir style messages then pretty printed and formatted. Includes `warning_name ` for use in explanations.
    224 
    225 ### Flags
    226 
    227 Dialyzer supports a number of warning flags used to enable or disable certain kinds of analysis features. Until version 0.4, `dialyxir` used by default the additional warning flags shown in the example below. However some of these create warnings that are often more confusing than helpful, particularly to new users of Dialyzer. As of 0.4, there are no longer any flags used by default. To get the old behavior, specify them in your Mix project file. For compatibility reasons you can use either the `-Wwarning` convention of the dialyzer CLI, or (preferred) the `WarnOpts` atoms supported by the [API](http://erlang.org/doc/man/dialyzer.html#gui-1).  e.g.
    228 
    229 ```elixir
    230 def project do
    231   [
    232     app: :my_app,
    233     version: "0.0.1",
    234     deps: deps,
    235     dialyzer: [flags: ["-Wunmatched_returns", :error_handling, :race_conditions, :underspecs]]
    236   ]
    237 end
    238 ```
    239 
    240 ### Paths
    241 
    242 By default only the ebin in the `_build` directory for the current mix environment of your project is included in paths to search for BEAM files to perform analysis on. You can specify a list of locations to find BEAMS for analysis with :paths keyword.
    243 
    244 ```elixir
    245 def project do
    246   [
    247     app: :my_app,
    248     version: "0.0.1",
    249     deps: deps,
    250     dialyzer: [
    251       plt_add_apps: [:mnesia],
    252       flags: [:unmatched_returns, :error_handling, :race_conditions, :no_opaque],
    253       paths: ["_build/dev/lib/my_app/ebin", "_build/dev/lib/foo/ebin"]
    254     ]
    255   ]
    256 end
    257 ```
    258 
    259 ### Ignore Warnings
    260 #### Dialyxir defaults
    261 
    262 By default `dialyxir` has always included the `:unknown` warning option so that warnings about unknown functions are returned. This is usually a clue that the PLT is not complete and it may be best to leave it on, but it can be disabled entirely by specifying `remove_defaults: [:unknown]` in your config.
    263 
    264 A better option is to ignore the specific warnings you can't fix (maybe due to a bug upstream, or a dependency you just don't want to include in your PLT due to time/memory in building the PLT file.)
    265 
    266 #### Module attribute
    267 
    268 Dialyzer has a built-in support for ignoring warnings through a `@dialyzer` module attribute. For example:
    269 
    270 ```elixir
    271 defmodule Myapp.Repo do
    272   use Ecto.Repo, otp_app: :myapp
    273   @dialyzer {:nowarn_function, rollback: 1}
    274 end
    275 ```
    276 
    277 More details can be found in the [erlang documentation](http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files)
    278 
    279 #### Ignore file
    280 
    281 If you want to ignore well-known warnings, you can specify a file path in `:ignore_warnings`.
    282 
    283 ```elixir
    284 def project do
    285   [
    286     app: :my_app,
    287     version: "0.0.1",
    288     deps: deps,
    289     dialyzer: [ignore_warnings: "dialyzer.ignore-warnings"]
    290   ]
    291 end
    292 ```
    293 
    294 This file comes in two formats: `--format dialyzer` string matches (compatible with `<= 0.5.1` ignore files), and the [term format](#elixir-term-format).
    295 
    296 Dialyzer will look for an ignore file using the term format with the name `.dialyzer_ignore.exs` by default if you don't specify something otherwise.
    297 
    298 #### Simple String Matches
    299 
    300 Any line of dialyzer format output (partially) matching a line in `"dialyzer.ignore-warnings"` is filtered.
    301 
    302 Note that copying output in the default format will not work!  Run `mix dialyzer --format dialyzer` to produce output suitable for the ignore file.
    303 
    304 For example, in a project where `mix dialyzer --format dialyzer` outputs:
    305 
    306 ```
    307   Proceeding with analysis...
    308 config.ex:64: The call ets:insert('Elixir.MyApp.Config',{'Elixir.MyApp.Config',_}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('Elixir.MyApp.Config','Elixir.MyApp.Config') call in config.ex on line 26
    309 config.ex:79: Guard test is_binary(_@5::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
    310 config.ex:79: Guard test is_atom(_@6::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
    311  done in 0m1.32s
    312 done (warnings were emitted)
    313 ```
    314 
    315 If you wanted to ignore the last two warnings about guard tests, you could add to `dialyzer.ignore-warnings`:
    316 
    317 ```
    318 Guard test is_binary(_@5::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
    319 Guard test is_atom(_@6::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
    320 ```
    321 
    322 And then run `mix dialyzer` would output:
    323 
    324 ```
    325   Proceeding with analysis...
    326 config.ex:64: The call ets:insert('Elixir.MyApp.Config',{'Elixir.MyApp.Config',_}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('Elixir.MyApp.Config','Elixir.MyApp.Config') call in config.ex on line 26
    327  done in 0m1.32s
    328 done (warnings were emitted)
    329 ```
    330 
    331 #### Elixir Term Format
    332 
    333 Dialyxir also recognizes an Elixir format of the ignore file. If your ignore file is an `exs` file, Dialyxir will evaluate it and process its data structure. A line may be either a tuple or an arbitrary Regex
    334 applied to the *short-description* format of Dialyzer output (`mix dialyzer --format short`). The file looks like the following:
    335 
    336 ```elixir
    337 # .dialyzer_ignore.exs
    338 [
    339   # {short_description}
    340   {":0:unknown_function Function :erl_types.t_is_opaque/1/1 does not exist."},
    341   # {short_description, warning_type}
    342   {":0:unknown_function Function :erl_types.t_to_string/1 does not exist.", :unknown_function},
    343   # {short_description, warning_type, line}
    344   {":0:unknown_function Function :erl_types.t_to_string/1 does not exist.", :unknown_function, 0},
    345   # {file, warning_type, line}
    346   {"lib/dialyxir/pretty_print.ex", :no_return, 100},
    347   # {file, warning_type}
    348   {"lib/dialyxir/warning_helpers.ex", :no_return},
    349   # {file}
    350   {"lib/dialyxir/warnings/app_call.ex"},
    351   # regex
    352   ~r/my_file\.ex.*my_function.*no local return/
    353 ]
    354 ```
    355 
    356 Entries for existing warnings can be generated with `mix dialyzer --format short`. Just remember to put the output in quotes and braces to match the format above.
    357 
    358 
    359 #### List unused Filters
    360 
    361 As filters tend to become obsolete (either because a discrepancy was fixed, or because the location
    362 for which a filter is needed changes), listing unused filters might be useful. This can be done by
    363 setting the `:list_unused_filters` option to `true` in `mix.exs`. For example:
    364 
    365 ```elixir
    366 dialyzer: [
    367   ignore_warnings: "ignore_test.exs",
    368   list_unused_filters: true
    369 ]
    370 ```
    371 
    372 This option can also be set on the command line with `--list-unused-filters`. When used without
    373 `--ignore-exit-status`, this option will result in an error status code.