You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by kx...@apache.org on 2015/09/23 14:29:10 UTC

[16/50] rebar commit: updated refs/heads/import to 5dea85d

Add Dialyzer plugin

Build project-specific PLT
$ rebar build-plt

Check the PLT for consistency and rebuild it if it is not up-to-date
$ rebar check-plt

Analyze the code for discrepancies
$ rebar dialyze

Delete project-specific PLT
$ rebar delete-plt

Valid rebar.config options:
  %% Store PLT in ~/.rebar/plt (Default)
  {dialyzer_plt_location,shared}
  %% Store PLT locally inside the project in .rebar
  {dialyzer_plt_location,local}
  %% Store PLT in custom directory
  {dialyzer_plt_location,"custom_path"}
  {dialyzer_plt_extra_apps,[app1,app2]}
  {dialyzer_warnings,[unmatched_returns,error_handling]}


Project: http://git-wip-us.apache.org/repos/asf/couchdb-rebar/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-rebar/commit/850a8a3d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-rebar/tree/850a8a3d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-rebar/diff/850a8a3d

Branch: refs/heads/import
Commit: 850a8a3dcedaf400a2e9d1afa67c80ebfd370a60
Parents: 094b74e
Author: Tuncer Ayaz <tu...@gmail.com>
Authored: Fri Feb 27 23:17:24 2015 +0100
Committer: Tuncer Ayaz <tu...@gmail.com>
Committed: Fri May 22 09:53:09 2015 +0200

----------------------------------------------------------------------
 .gitignore                       |   1 -
 Makefile                         |  41 +-----
 dialyzer_reference               |   3 -
 ebin/rebar.app                   |  25 +++-
 priv/shell-completion/bash/rebar |   6 +-
 priv/shell-completion/zsh/_rebar |   5 +-
 rebar.config                     |  12 ++
 rebar.config.sample              |  16 +++
 src/rebar.erl                    |  10 ++
 src/rebar_dialyzer.erl           | 234 ++++++++++++++++++++++++++++++++++
 10 files changed, 304 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 15668a7..671ac10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
 *.orig
 .*.swp
 /rt.work
-/dialyzer_warnings
 /rebar.cmd
 /.eunit
 /deps

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
index ed8dd48..9f8ea7a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,7 @@
-.PHONY: clean dialyzer_warnings xref_warnings deps test test_eunit test_inttest
+.PHONY: clean xref_warnings deps test test_eunit test_inttest
 
 REBAR=$(PWD)/rebar
 RETEST=$(PWD)/deps/retest/retest
-OTPVSNCMD='io:fwrite("~s",[rebar_utils:otp_release()]), halt().'
-OTPVSN=$(shell erl -pa ebin/ -noshell -eval $(OTPVSNCMD))
-PLT_FILENAME=~/.dialyzer_rebar_$(OTPVSN)_plt
 LOG_LEVEL?=debug
 RT_TARGETS?=inttest
 
@@ -12,11 +9,9 @@ all:
 	./bootstrap
 
 clean:
-	@rm -rf rebar ebin/*.beam inttest/rt.work rt.work .eunit
-	@rm -f .rebarinfo
+	@rm -rf rebar .rebar ebin/*.beam inttest/rt.work rt.work .eunit
 
 distclean: clean
-	@rm -f dialyzer_warnings
 	@rm -rf deps
 
 debug:
@@ -28,36 +23,10 @@ xref:
 	@./rebar xref
 
 build_plt:
-	-dialyzer --build_plt --output_plt $(PLT_FILENAME) --apps \
-		erts \
-		kernel \
-		stdlib \
-		crypto \
-		compiler \
-		asn1 \
-		eunit \
-		tools \
-		ssl \
-		edoc \
-		reltool \
-		snmp \
-		sasl
-	-dialyzer --add_to_plt --plt $(PLT_FILENAME) \
-		--output_plt $(PLT_FILENAME) \
-		--apps diameter
+	@./rebar build-plt
 
-dialyzer: dialyzer_warnings
-	@diff -U0 dialyzer_reference dialyzer_warnings
-
-dialyzer_warnings:
-	-@dialyzer --plt $(PLT_FILENAME) -q -nn -n ebin \
-		-Wunmatched_returns \
-		-Werror_handling \
-		-Wrace_conditions \
-		> dialyzer_warnings
-
-typer:
-	typer -r --plt $(PLT_FILENAME) ./src -I ./include
+dialyzer:
+	@./rebar dialyze
 
 binary: VSN = $(shell ./rebar -V)
 binary: clean all

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/dialyzer_reference
----------------------------------------------------------------------
diff --git a/dialyzer_reference b/dialyzer_reference
deleted file mode 100644
index 41b1cff..0000000
--- a/dialyzer_reference
+++ /dev/null
@@ -1,3 +0,0 @@
-
-rebar_eunit.erl:471: Call to missing or unexported function eunit_test:function_wrapper/2
-rebar_utils.erl:222: Call to missing or unexported function escript:foldl/3

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/ebin/rebar.app
----------------------------------------------------------------------
diff --git a/ebin/rebar.app b/ebin/rebar.app
index 1f3a895..9ebc83c 100644
--- a/ebin/rebar.app
+++ b/ebin/rebar.app
@@ -17,6 +17,7 @@
               rebar_cover_utils,
               rebar_ct,
               rebar_deps,
+              rebar_dialyzer,
               rebar_edoc,
               rebar_erlc_compiler,
               rebar_erlydtl_compiler,
@@ -46,13 +47,22 @@
               rebar_getopt,
               rebar_mustache ]},
   {registered, []},
-  {applications, [kernel,
-                  stdlib,
-                  sasl,
-                  compiler,
-                  crypto,
-                  syntax_tools,
-                  tools]},
+  {applications,
+   [
+    kernel,
+    stdlib,
+    sasl,
+    compiler,
+    crypto,
+    syntax_tools,
+    tools,
+    eunit,
+    reltool,
+    dialyzer,
+    asn1,
+    snmp,
+    edoc
+   ]},
   {env, [
          %% Default log level
          {log_level, warn},
@@ -76,6 +86,7 @@
                                rebar_neotoma_compiler,
                                rebar_asn1_compiler,
                                rebar_dia_compiler,
+                               rebar_dialyzer,
                                rebar_erlc_compiler,
                                rebar_lfe_compiler,
                                rebar_erlydtl_compiler,

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/priv/shell-completion/bash/rebar
----------------------------------------------------------------------
diff --git a/priv/shell-completion/bash/rebar b/priv/shell-completion/bash/rebar
index 0baf389..c017d20 100644
--- a/priv/shell-completion/bash/rebar
+++ b/priv/shell-completion/bash/rebar
@@ -17,14 +17,18 @@ _rebar()
         --keep-going \
         --recursive \
         --version"
-    cmdsnvars="check-deps \
+    cmdsnvars=" \
+        build-plt \
+        check-deps \
         clean \
         compile \
+        check-plt \
         create \
         create-app \
         create-lib \
         create-node \
         ct \
+        dialyze \
         doc \
         delete-deps \
         escriptize \

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/priv/shell-completion/zsh/_rebar
----------------------------------------------------------------------
diff --git a/priv/shell-completion/zsh/_rebar b/priv/shell-completion/zsh/_rebar
index 0390881..2ba7cdc 100644
--- a/priv/shell-completion/zsh/_rebar
+++ b/priv/shell-completion/zsh/_rebar
@@ -28,13 +28,16 @@ _rebar () {
   case $state in
     cmd_and_var)
       _values -S = 'variables' \
+        'dialyze[Analyze the code for discrepancies]' \
+        'build-plt[Build project-specific PLT]' \
+        'check-plt[Check the plt for consistency and rebuild it if it is not up-to-date]' \
         'clean[Clean]' \
         'compile[Compile sources]' \
         'create[Create skel based on template and vars]' \
         'create-app[Create simple app skel]' \
         'create-lib[Create simple lib skel]' \
         'create-node[Create simple node skel]' \
-        'list-template[List avaiavle templates]' \
+        'list-template[List available templates]' \
         'doc[Generate Erlang program documentation]' \
         'check-deps[Display to be fetched dependencies]' \
         'prepare-deps[Fetch and build dependencies]' \

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/rebar.config
----------------------------------------------------------------------
diff --git a/rebar.config b/rebar.config
index 33d2aea..370bc8f 100644
--- a/rebar.config
+++ b/rebar.config
@@ -31,3 +31,15 @@
       - (\"diameter_dict_util\":\"format_error\"/\"1\")
       - (\"diameter_dict_util\":\"parse\"/\"2\"))",
          []}]}.
+
+{dialyzer_plt_extra_apps,
+ [
+  diameter
+ ]}.
+
+{dialyzer_warnings,
+ [
+  unmatched_returns,
+  error_handling,
+  race_conditions
+ ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/rebar.config.sample
----------------------------------------------------------------------
diff --git a/rebar.config.sample b/rebar.config.sample
index b650bc9..41a96a4 100644
--- a/rebar.config.sample
+++ b/rebar.config.sample
@@ -266,3 +266,19 @@
 {xref_queries,
  [{"(XC - UC) || (XU - X - B"
    " - (\"mod\":\".*foo\"/\"4\"))",[]}]}.
+
+%% == Dialyzer ==
+
+%% Store PLT in ~/.rebar/plt (Default)
+{dialyzer_plt_location, shared}.
+
+%% Store PLT locally inside the project in .rebar
+{dialyzer_plt_location, local}.
+
+%% Store PLT in custom directory
+{dialyzer_plt_location, "custom_path"}.
+
+%% Extra apps to include in the PLT
+{dialyzer_plt_extra_apps, [app1, app2]}.
+
+{dialyzer_warnings, [unmatched_returns, error_handling]}.

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/src/rebar.erl
----------------------------------------------------------------------
diff --git a/src/rebar.erl b/src/rebar.erl
index 2d356dd..9a5fc28 100644
--- a/src/rebar.erl
+++ b/src/rebar.erl
@@ -456,6 +456,12 @@ qc                                       Test QuickCheck properties
 
 xref                                     Run cross reference analysis
 
+dialyze                                  Analyze the code for discrepancies
+build-plt                                Build project-specific PLT
+check-plt                                Check the PLT for consistency and
+                                         rebuild it if it is not up-to-date
+delete-plt                               Delete project-specific PLT
+
 shell                                    Start a shell similar to
                                          'erl -pa ebin -pa deps/*/ebin'
 
@@ -527,7 +533,9 @@ filter_flags(Config, [Item | Rest], Commands) ->
 
 command_names() ->
     [
+     "build-plt",
      "check-deps",
+     "check-plt",
      "clean",
      "compile",
      "create",
@@ -535,7 +543,9 @@ command_names() ->
      "create-lib",
      "create-node",
      "ct",
+     "delete-plt",
      "delete-deps",
+     "dialyze",
      "doc",
      "eunit",
      "escriptize",

http://git-wip-us.apache.org/repos/asf/couchdb-rebar/blob/850a8a3d/src/rebar_dialyzer.erl
----------------------------------------------------------------------
diff --git a/src/rebar_dialyzer.erl b/src/rebar_dialyzer.erl
new file mode 100644
index 0000000..5f0cb1e
--- /dev/null
+++ b/src/rebar_dialyzer.erl
@@ -0,0 +1,234 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014-2015 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(rebar_dialyzer).
+
+-export([
+         dialyze/2,
+         'build-plt'/2,
+         'check-plt'/2,
+         'delete-plt'/2
+        ]).
+
+%% for internal use only
+-export([info/2]).
+
+-include("rebar.hrl").
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+
+dialyze(Config, AppFile) ->
+    {NewConfig, Plt} = plt(Config, AppFile),
+    ok = check_plt_existence(Plt),
+
+    Opts = [
+            {analysis_type, succ_typings},
+            %% http://erlang.org/pipermail/erlang-bugs/2015-February/004781.html
+            %% TODO: remove once the minimum required Erlang/OTP release
+            %% includes a Dialyzer version without the bug, or alternatively
+            %% add a config option to always check the PLT, as this may be
+            %% needed by some users.
+            {check_plt, false},
+            {init_plt, Plt},
+            {files_rec, ["ebin"]},
+            {warnings, warnings(Config)}
+           ],
+    ?DEBUG("dialyze opts:~n~p~n", [Opts]),
+    case run(Opts) of
+        [] ->
+            {ok, NewConfig};
+        Ws ->
+            print_warnings(Ws),
+            ?FAIL
+    end.
+
+'build-plt'(Config, AppFile) ->
+    {Config1, AppDirs} = app_dirs(Config, AppFile),
+    {NewConfig, Plt} = plt(Config1, AppFile),
+    Opts = [
+            {analysis_type, plt_build},
+            {output_plt, Plt},
+            {files_rec, AppDirs}
+           ],
+    ?DEBUG("build-plt opts:~n~p~n", [Opts]),
+    case run(Opts) of
+        [] ->
+            {ok, NewConfig};
+        Ws ->
+            %% As plt_build may raise warnings but still successfully
+            %% create the PLT, we cannot interpret this as failure,
+            %% and therefore all we can do is report warnings.
+            print_warnings(Ws)
+    end.
+
+'check-plt'(Config, AppFile) ->
+    {NewConfig, Plt} = plt(Config, AppFile),
+    ok = check_plt_existence(Plt),
+
+    Opts = [
+            {analysis_type, plt_check},
+            %% http://erlang.org/pipermail/erlang-bugs/2015-February/004781.html
+            %% Without this, the PLT will be checked twice.
+            %% TODO: remove once the minimum required Erlang/OTP release
+            %% includes a Dialyzer version without the bug.
+            {check_plt, false},
+            {init_plt, Plt}
+           ],
+    ?DEBUG("build-plt opts:~n~p~n", [Opts]),
+    case run(Opts) of
+        [] ->
+            {ok, NewConfig};
+        Ws ->
+            print_warnings(Ws),
+            ?FAIL
+    end.
+
+'delete-plt'(Config, AppFile) ->
+    {NewConfig, Plt} = plt(Config, AppFile),
+    ?DEBUG("Delete PLT '~s'~n", [Plt]),
+    ok = rebar_file_utils:delete_each([Plt]),
+    {ok, NewConfig}.
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, dialyze) ->
+    info_help("Analyze the code for discrepancies");
+info(help, 'build-plt') ->
+    info_help("Build project-specific PLT");
+info(help, 'check-plt') ->
+    info_help("Check the PLT for consistency and rebuild it if it"
+              " is not up-to-date");
+info(help, 'delete-plt') ->
+    info_help("Delete project-specific PLT").
+
+info_help(Description) ->
+    ?CONSOLE(
+       "~s.~n"
+       "~n"
+       "Valid rebar.config options:~n"
+       "  ~p~n"
+       "  ~p~n"
+       "  ~p~n"
+       "  ~p~n"
+       "  ~p~n",
+       [
+        Description,
+        {dialyzer_plt_location, shared},
+        {dialyzer_plt_location, local},
+        {dialyzer_plt_location, "custom_path"},
+        {dialyzer_plt_extra_apps, [app1, app2]},
+        {dialyzer_warnings, [unmatched_returns, error_handling]}
+       ]).
+
+plt(Config, AppFile) ->
+    PltDir = plt_dir(Config),
+    {NewConfig, RawAppName} = rebar_app_utils:app_name(Config, AppFile),
+    AppName = atom_to_list(RawAppName),
+    OtpRel = rebar_utils:otp_release(),
+    Plt = filename:join([PltDir, AppName ++ "_" ++ OtpRel ++ "_plt"]),
+    ok = filelib:ensure_dir(Plt),
+    {NewConfig, Plt}.
+
+plt_dir(Config) ->
+    Location = rebar_config:get_local(Config, dialyzer_plt_location, shared),
+    plt_dir1(Config, Location).
+
+plt_dir1(_Config, Location) when is_list(Location) ->
+    case filelib:is_dir(Location) of
+        false ->
+            ?ABORT("PLT directory does not exist: ~s~n", [Location]);
+        true ->
+            Location
+    end;
+plt_dir1(_Config, shared) ->
+    {ok, Home} = init:get_argument(home),
+    filename:join([Home, ".rebar", "plt"]);
+plt_dir1(Config, local) ->
+    BaseDir = rebar_utils:base_dir(Config),
+    filename:join([BaseDir, ".rebar"]).
+
+check_plt_existence(Plt) ->
+    case filelib:is_regular(Plt) of
+        true ->
+            ok;
+        false ->
+            ?ABORT("PLT '~s' does not exist.~n"
+                   "Please run 'rebar build-plt' first.~n", [Plt])
+    end.
+
+%% dialyzer:run/1 wrapper to gracefully fail in case of Dialyzer errors
+run(Opts) ->
+    try dialyzer:run(Opts) of
+        Ws -> Ws
+    catch
+        throw:{dialyzer_error, Reason} ->
+            ?ABORT("Dialyzer error:~n~s~n", [Reason])
+    end.
+
+warnings(Config) ->
+    rebar_config:get_local(Config, dialyzer_warnings, []).
+
+print_warnings(Ws) ->
+    lists:foreach(
+      fun(W) ->
+              ?CONSOLE("~s~n", [format_warning(W)])
+      end,
+      Ws).
+
+format_warning(W) ->
+    dialyzer:format_warning(W, fullpath).
+
+app_dirs(Config, AppFile) ->
+    {NewConfig, AppFileApps} = app_file_apps(Config, AppFile),
+    ?DEBUG("app file apps:~n~p~n", [AppFileApps]),
+    Deps = deps_apps(Config),
+    ?DEBUG("deps apps:~n~p~n", [Deps]),
+    ExtraApps = rebar_config:get_local(Config, dialyzer_plt_extra_apps, []),
+    ?DEBUG("extra apps:~n~p~n", [ExtraApps]),
+    %% erts is assumed, and has to be present unconditionally.
+    Erts = [erts],
+    Apps = ordsets:from_list(Erts ++ AppFileApps ++ Deps ++ ExtraApps),
+    AppDirs = [app_lib_dir(App) || App <- ordsets:to_list(Apps)],
+    ?DEBUG("app dirs:~n~p~n", [AppDirs]),
+    {NewConfig, AppDirs}.
+
+app_file_apps(Config, AppFile) ->
+    rebar_app_utils:app_applications(Config, AppFile).
+
+deps_apps(Config) ->
+    [element(1, Dep) || Dep <- rebar_config:get_local(Config, deps, [])].
+
+app_lib_dir(App) ->
+    case code:lib_dir(App, ebin) of
+        {error, _}=Err ->
+            ?ABORT("Failed to get ebin dir for app: ~p~n~p~n", [App, Err]);
+        Dir ->
+            Dir
+    end.