查看源码 dialyzer (dialyzer v5.3)
Dialyzer 是一个用于 Erlang 程序的 DIscrepancy AnaLYZer(差异分析器)。
Dialyzer 是一个静态分析工具,用于识别软件差异,例如确定的类型错误、由于编程错误而无法访问的代码,以及单个 Erlang 模块或整个代码库中不必要的测试。
Dialyzer 从调试编译的 BEAM 代码或 Erlang 源代码开始进行分析。报告差异的文件和行号,并指出差异的性质。Dialyzer 的分析基于成功类型化的概念,确保发出可靠的警告,而不会出现误报。
从命令行使用 Dialyzer
本节简要介绍从命令行运行 Dialyzer 时可用的选项。可以通过在 shell 中写入以下内容获得相同的信息
dialyzer --help
命令行版本的退出状态
0
- 分析期间未发现问题,也没有发出警告。1
- 分析期间发现问题。2
- 分析期间未发现问题,但发出了警告。
用法
dialyzer [--add_to_plt] [--apps applications] [--build_plt]
[--check_plt] [-Ddefine]* [-Dname]* [--dump_callgraph file]
[--error_location flag] [files_or_dirs] [--fullpath]
[--get_warnings] [--help] [-I include_dir]*
[--incremental] [--metrics_file] [--no_check_plt] [--no_indentation]
[--no_spec] [-o outfile] [--output_plt file] [-pa dir]* [--plt plt]
[--plt_info] [--plts plt*] [--quiet] [-r dirs] [--raw]
[--remove_from_plt] [--shell] [--src] [--statistics] [--verbose]
[--version] [--warning_apps applications] [-Wwarn]*
注意
* 表示该选项可能出现多次。
命令行版本的选项
--add_to_plt
- PLT 扩展为还包括使用-c
和-r
指定的文件。使用--plt
指定从哪个 PLT 开始,使用--output_plt
指定 PLT 的存储位置。请注意,如果 PLT 中已包含的文件依赖于新文件,则会重新分析这些文件。此选项仅适用于 BEAM 文件,不适用于源文件。--apps applications
- 默认情况下,会将警告报告给--apps
给出的所有应用程序。但是,如果使用--warning_apps
,则只会报告给--warning_apps
给出的那些应用程序。所有由--apps
给出但不属于--warning_apps
的应用程序将进行分析,为分析提供上下文,但不会为其报告警告。例如,你可能希望在分析中包含你依赖的库,使用--apps
以便可以找到它们用法中的差异,但只在自己的代码中包含--warning_apps
,以便仅在你拥有的代码中报告差异。--warning_apps applications
- 此选项通常在构建或修改 PLT 时使用,例如dialyzer --build_plt --apps erts kernel stdlib mnesia ...
方便地引用与 Erlang/OTP 安装对应的库应用程序。此选项也可以在分析期间使用,以引用 Erlang/OTP 应用程序。还可以包含文件或目录名称,例如
dialyzer --apps inets ssl ./ebin ../other_lib/ebin/my_module.beam
--build_plt
- 分析从空的 PLT 开始,并从-c
和-r
指定的文件创建一个新的 PLT。此选项仅适用于 BEAM 文件。要覆盖默认的 PLT 位置,请使用--plt
或--output_plt
。--check_plt
- 检查 PLT 的一致性,并在 PLT 不是最新的情况下重建它。-Dname
(或-Dname=value
) - 从源代码进行分析时,将 define 传递给 Dialyzer。(**)--dump_callgraph file
- 将调用图转储到指定的文件中,文件的格式由文件名扩展名确定。支持的扩展名为:raw
、dot
和ps
。如果使用其他扩展名作为文件名扩展名,则使用默认的.raw
格式。--error_location column | line
- 使用{Line, Column}
对或整数Line
来精确定位警告的位置。默认是使用{Line, Column}
对。格式化时,行和列之间用冒号分隔。files_or_dirs
(为了向后兼容,也用作-c files_or_dirs
) - 从命令行使用 Dialyzer 来检测指定的文件或目录中的缺陷,这些文件或目录包含.erl
或.beam
文件,具体取决于分析的类型。--fullpath
- 显示发出警告的文件的完整路径名。--get_warnings
- 使 Dialyzer 即使在操作 PLT 时也发出警告。只会为分析的文件发出警告。--help
(或-h
) - 打印帮助消息并退出。-I include_dir
- 从源代码进行分析时,将include_dir
传递给 Dialyzer。(**)--input_list_file file
- 分析指定文件中列出的文件名(每行一个文件名)。--no_check_plt
- 运行 Dialyzer 时跳过 PLT 检查。这在处理从不更改的已安装 PLT 时非常有用。--incremental
- 分析从现有的增量 PLT 开始,或者在不存在增量 PLT 时从头开始构建,并运行最少的额外分析以报告给定应用程序集中的所有问题。值得注意的是,增量 PLT 文件与“经典”PLT 文件不兼容,反之亦然。除非给出备选的输出增量 PLT,否则初始增量 PLT 将被更新。--no_indentation
- 格式化警告时,不要在类型、契约和 Erlang 代码中插入换行符。--no_spec
- 忽略函数规范。当怀疑某些规范不正确时,这对于调试非常有用。-o outfile
(或--output outfile
) - 从命令行使用 Dialyzer 时,将分析结果发送到指定的 outfile,而不是stdout
。--metrics_file file
- 将有关 Dialyzer 增量的信息(例如,考虑的模块总数、自上次更新 PLT 以来更改的模块数、需要分析的模块数)写入文件。这对于跟踪和调试 Dialyzer 的增量非常有用。--output_plt file
- 构建 PLT 后,将其存储在指定的文件中。-pa dir
- 将dir
包含在 Erlang 的路径中。这在分析具有-include_lib()
指令的文件时非常有用。--plt plt
- 使用指定的 PLT 作为初始 PLT。如果在设置期间构建了 PLT,则会检查文件的一致性。--plt_info
- 使 Dialyzer 打印有关 PLT 的信息,然后退出。可以使用--plt(s)
指定 PLT。--plts plt*
- 合并指定的 PLT 以创建初始 PLT。这要求 PLT 是不相交的(即,没有任何模块出现在多个 PLT 中)。PLT 以通常的方式创建dialyzer --build_plt --output_plt plt_1 files_to_include ... dialyzer --build_plt --output_plt plt_n files_to_include
然后,它们可以通过以下两种方式中的任一种使用
dialyzer files_to_analyze --plts plt_1 ... plt_n
或
dialyzer --plts plt_1 ... plt_n -- files_to_analyze
请注意第二种情况下的
--
分隔符。--quiet
(或-q
) - 使 Dialyzer 更安静一些。-r dirs
- 与files_or_dirs
相同,但指定的目录会递归搜索包含.erl
或.beam
文件的子目录,具体取决于分析的类型。--raw
- 从命令行使用 Dialyzer 时,输出原始分析结果(Erlang 术语),而不是格式化的结果。原始格式更容易进行后处理(例如,筛选警告或输出 HTML 页面)。--remove_from_plt
- 从 PLT 中删除使用-c
和-r
指定的文件中的信息。请注意,这可能会导致重新分析其余的依赖文件。--src
- 覆盖默认值,即分析 BEAM 文件,改为从 Erlang 源代码开始分析。--statistics
- 打印有关执行进度的信息(分析阶段、每个阶段花费的时间以及相对输入的大小)。--verbose
- 使 Dialyzer 更详细一些。--version
(或-v
) - 打印 Dialyzer 版本和一些更多信息并退出。-Wwarn
- 一系列用于选择性地打开/关闭警告的选项。(有关警告名称的帮助,请使用dialyzer -Whelp
。)请注意,这些选项也可以在文件中使用-dialyzer()
属性指定。有关详细信息,请参阅在源文件中请求或抑制警告部分。
注意
** defines 和 includes 的语法与 erlc 使用的语法相同。
警告选项
-Werror_handling
(***) - 包括仅通过异常返回的函数的警告。-Wextra_return
(***) - 警告其规范包含该函数无法返回的类型的函数。-Wmissing_return
(***) - 警告函数返回的值不符合规范。-Wno_behaviours
- 抑制关于行为回调偏离已发布的推荐接口的警告。-Wno_contracts
- 抑制关于无效契约的警告。-Wno_fail_call
- 抑制关于失败调用的警告。-Wno_fun_app
- 抑制关于将要失败的 fun 应用的警告。-Wno_improper_lists
- 抑制关于构造不当列表的警告。-Wno_match
- 抑制关于未使用或无法匹配的模式的警告。-Wno_missing_calls
- 抑制关于调用缺失函数的警告。-Wno_opaque
- 抑制关于数据类型不透明性的违规警告。-Wno_return
- 抑制关于永远不会返回值的函数的警告。-Wno_undefined_callbacks
- 抑制关于其回调没有-callback
属性的行为的警告。-Wno_unused
- 抑制关于未使用函数的警告。-Wno_unknown
- 抑制关于未知函数和类型的警告。默认情况下,当设置退出状态时,会警告未知函数和类型。当从 Erlang 中使用 Dialyzer 时,会返回关于未知函数和类型的警告。-Wunderspecs
(***) - 警告欠规范的函数(规范比成功类型更宽松)。-Wunmatched_returns
(***) - 包括关于忽略结构化返回值或不匹配多个可能返回值之一的函数调用的警告。但是,如果可能的返回值是原子联合或数字联合,则不包括警告。
以下选项也可用,但不建议使用(它们主要用于 Dialyzer 开发人员和内部调试)
-Woverspecs
(***) - 警告过度规范的函数(规范比成功类型更严格)。-Wspecdiffs
(***) - 当规范与成功类型不同时发出警告。
注意
*** 表示开启警告而不是关闭警告的选项。
以下选项不是严格必需的,因为它们指定了默认值。它们主要用于 -dialyzer
属性。有关示例,请参阅 在源文件中请求或抑制警告 部分。
-Wno_underspecs
- 抑制关于欠规范的函数的警告(规范比成功类型更宽松)。-Wno_extra_return
- 抑制关于其规范包含函数无法返回的类型的警告。-Wno_missing_return
- 抑制关于函数返回的值不符合规范的警告。
从 Erlang 使用 Dialyzer
可以直接从 Erlang 使用 Dialyzer。选项与从命令行给出的选项类似。请参阅 从命令行使用 Dialyzer 部分。
默认 Dialyzer 选项
(主机操作系统)环境变量 ERL_COMPILER_OPTIONS
可用于提供默认的 Dialyzer 选项。其值必须是有效的 Erlang 项。如果该值是列表,则按原样使用。如果它不是列表,则将其放入列表中。
该列表会附加到任何给 run/1
或命令行提供的选项。
可以使用 compile:env_compiler_options/0
检索该列表。
当前唯一使用的选项是 error_location
选项。
Dialyzer 配置文件
Dialyzer 的配置文件也可用于增强默认选项和直接提供给 Dialyzer 命令的选项。它通常用于避免重复选项,否则每次调用 Dialyzer 时都需要显式给出这些选项。
配置文件的位置可以通过 DIALYZER_CONFIG
环境变量设置,并且默认为 filename:basedir/3
中的 user_config
内。
一个示例配置文件的内容可能是
{incremental,
{default_apps,[stdlib,kernel,erts]},
{default_warning_apps,[stdlib]}
}.
{warnings, [no_improper_lists]}.
{add_pathsa,["/users/samwise/potatoes/ebin"]}.
{add_pathsz,["/users/smeagol/fish/ebin"]}.
在源文件中请求或抑制警告
属性 -dialyzer()
可用于通过指定函数或警告选项来关闭模块中的警告。例如,要关闭函数 f/0
的所有警告,请包含以下行
-dialyzer({nowarn_function, f/0}).
要关闭关于不当列表的警告,请将以下行添加到源文件中
-dialyzer(no_improper_lists).
函数声明后允许使用属性 -dialyzer()
。允许使用警告选项或函数的列表
-dialyzer([{nowarn_function, [f/0]}, no_improper_lists]).
警告选项可以限制为特定的函数
-dialyzer({no_improper_lists, g/0}).
-dialyzer({[no_return, no_match], [g/0, h/0]}).
关于欠规范函数的警告选项 -Wunderspecs
可能会产生有用的警告,但是通常具有规范比成功类型更宽松的函数不容易修改为不太宽松。要关闭欠规范函数 f/0
的警告,请包含以下行
-dialyzer({no_underspecs, f/0}).
有关警告选项的帮助,请使用 dialyzer -Whelp
。这些选项也已枚举,请参阅类型 warn_option/0
。
属性 -dialyzer()
也可用于开启警告。例如,如果一个模块已修复了关于不匹配返回的问题,则添加以下行可以帮助确保不会引入新的不匹配返回警告
-dialyzer(unmatched_returns).
总结
类型
选项 from
默认为 byte_code
。选项 init_plt
和 plts
会更改默认值。
如果此选项的值为 line
,则整数 Line
将用作消息中的 Location
。如果该值为 column
,则将使用一对 {Line, Column}
作为 Location
。默认值为 column
。
有关警告选项的描述,请参阅 警告选项 部分。
类型
-type dial_option() :: {files, [FileName :: file:filename()]} | {files_rec, [DirName :: file:filename()]} | {defines, [{Macro :: atom(), Value :: term()}]} | {from, src_code | byte_code} | {init_plt, FileName :: file:filename()} | {plts, [FileName :: file:filename()]} | {include_dirs, [DirName :: file:filename()]} | {output_file, FileName :: file:filename()} | {metrics_file, FileName :: file:filename()} | {module_lookup_file, FileName :: file:filename()} | {output_plt, FileName :: file:filename()} | {check_plt, boolean()} | {analysis_type, succ_typings | plt_add | plt_build | plt_check | plt_remove | incremental} | {warnings, [warn_option()]} | {get_warnings, boolean()} | {use_spec, boolean()} | {filename_opt, filename_opt()} | {callgraph_file, file:filename()} | {mod_deps_file, file:filename()} | {warning_files_rec, [DirName :: file:filename()]} | {error_location, error_location()}.
选项 from
默认为 byte_code
。选项 init_plt
和 plts
会更改默认值。
-type dial_warn_tag() ::
warn_behaviour | warn_bin_construction | warn_callgraph | warn_contract_extra_return |
warn_contract_missing_return | warn_contract_not_equal | warn_contract_range |
warn_contract_subtype | warn_contract_supertype | warn_contract_syntax | warn_contract_types |
warn_failing_call | warn_fun_app | warn_map_construction | warn_matching |
warn_non_proper_list | warn_not_called | warn_opaque | warn_overlapping_contract |
warn_return_no_exit | warn_return_only_exit | warn_undefined_callbacks | warn_unknown |
warn_umatched_return.
-type dial_warning() :: {Tag :: dial_warn_tag(), Id :: file_location(), Msg :: {atom(), [term()]}}.
-type error_location() :: column | line.
如果此选项的值为 line
,则整数 Line
将用作消息中的 Location
。如果该值为 column
,则将使用一对 {Line, Column}
作为 Location
。默认值为 column
。
-type file_location() :: {File :: file:filename(), Location :: erl_anno:location()}.
-type filename_opt() :: basename | fullpath.
-type format_option() :: {indent_opt, boolean()} | {filename_opt, filename_opt()} | {error_location, error_location()}.
-type warn_option() ::
error_handling | no_behaviours | no_contracts | no_fail_call | no_fun_app |
no_improper_lists | no_match | no_missing_calls | no_opaque | no_return |
no_undefined_callbacks | no_underspecs | no_unknown | no_unused | underspecs | unknown |
unmatched_returns | overspecs | specdiffs | overlapping_contract | extra_return |
no_extra_return | missing_return | no_missing_return.
有关警告选项的描述,请参阅 警告选项 部分。
函数
-spec format_warning(Warnings) -> string() when Warnings :: dial_warning().
从 run/1
返回的警告中获取字符串。
-spec format_warning(Warnings, Options) -> string() when Warnings :: dial_warning(), Options :: filename_opt() | [format_option()].
从 run/1
返回的警告中获取字符串。
如果 indent_opt
设置为 true
(默认值),则会在类型、契约和 Erlang 代码中插入换行符以提高可读性。
如果 error_location
设置为 column
(默认值),如果列号可用,则位置格式化为 行号:列号
,否则即使列号可用,位置也会格式化为 行号
。
-spec plt_info(Plt) -> {ok, ClassicResult | IncrementalResult} | {error, Reason} when Plt :: file:filename(), ClassicResult :: [{files, [file:filename()]}], IncrementalResult :: {incremental, [{modules, [module()]}]}, Reason :: not_valid | no_such_file | read_error.
返回有关指定 PLT 的信息。
-spec run(Options) -> Warnings when Options :: [dial_option()], Warnings :: [dial_warning()].
运行 Dialyzer 并返回警告。