1 %% -*- mode: Erlang; fill-column: 80; comment-column: 75; -*-
2 %%%---------------------------------------------------------------------------
3 %%% @author Eric Merritt
5 %%% Uses dialyzer to analyze the project sources and output messages.
7 %%% @copyright (C) 2006-2011 Erlware
8 %%%---------------------------------------------------------------------------
9 -module(sin_task_dialyzer
).
13 -include_lib("sinan/include/sinan.hrl").
16 -export([description
/0, do_task
/2,
19 -define(TASK
, dialyzer
).
20 -define(DEPS
, [build
]).
23 %%====================================================================
25 %%====================================================================
26 %% @doc provide a description of the system for the caller
27 -spec
description() -> sin_task:task_description().
34 This task runs dialyzer on a project. It checks the 'dialyzer' state of the
35 project and builds or updates the relevant per project plt files. This task may
36 take a (very) long time to complete.
38 One problem that dialyzer has is that all applications being analyzed project
39 apps and dependencies must be built with debug information. If not, dialyzer
40 will blow up with some not very useful information. You can get around this by
41 asking the dialyzer task to ignore certain applications.
43 Do this in your build config with the following entry.
45 {dialyzer_ignore, [IgnoredApps::atom()]}.
47 The downside, of course, is figuring out which apps actually have the
48 problem. This task tries to help by printing out a list of applications that
49 where under analysis when the blowup occurred.
51 By default all dialyzer warnings are enabled. You can
52 override this with the directive
54 {dialyzer_warnings, [Warnings::term()]}.
56 Just put the warning options listed in the dialyzer
57 documentation to get the specific warnings that you would like
58 to see. Unfortunately, you can not do over ride that on a per
59 application basis as dialyzer is a whole program analysis
66 short_desc
= "Run the Dialyzer analyzer on the project",
71 do_task(Config0
, State0
) ->
72 sin_log:verbose(Config0
, "Starting analyzation, this may take awhile ..."),
73 BuildDir
= sin_state:get_value(build_dir
,State0
),
74 {ProjectPlt
, DepPlt
} = get_plt_location(BuildDir
),
75 DepList
= sin_state:get_value(release_deps
, State0
),
76 AppList
= sin_state:get_value(project_apps
, State0
),
77 sin_log:verbose(Config0
, "Doing plt for all dependencies ..."),
78 update_dep_plt(Config0
, State0
, DepPlt
, DepList
),
79 sin_log:verbose(Config0
, "Doing plt for project apps ..."),
80 update_dep_plt(Config0
, State0
, ProjectPlt
, AppList
),
82 WarningTypes
= Config0:match(dialyzer_warnings
, default_warnings()),
83 Paths
= [filename:join(Path
, "ebin") ||
84 #app
{path
=Path
} <- AppList
],
85 Opts
= [{analysis_type
, succ_typings
},
88 {warnings
, WarningTypes
},
89 {plts
, [ProjectPlt
, DepPlt
]}],
91 case dialyzer:run(Opts
) of
96 {warnings
, Warnings
, AppList
})
99 _:{dialyzer_error
, Error
} ->
101 {error_processing_apps
, Error
, AppList
})
105 -spec
format_exception(sin_exceptions:exception()) ->
107 format_exception(?
SIN_EXEP_UNPARSE(_
,
108 {error_processing_apps
, Error
, AppList
})) ->
109 [io_lib:format("~s~n", [Error
]),
110 "while processing the following apps~n",
111 lists:map(fun(#app
{name
=Name
}) ->
112 io_lib:format(" ~s~n", [Name
])
114 format_exception(?
SIN_EXEP_UNPARSE(_
,
115 {warnings
, Warnings
, _AppList
})) ->
116 [lists:map(fun(Warning
) ->
117 dialyzer:format_warning(Warning
)
118 end, Warnings
), "~n"];
119 format_exception(Exception
) ->
120 sin_exceptions:format_exception(Exception
).
122 %%====================================================================
123 %%% Internal functions
124 %%====================================================================
125 get_plt_location(BuildDir
) ->
126 {filename:join([BuildDir
, "project.plt"]),
127 filename:join([BuildDir
, "deps.plt"])}.
129 update_dep_plt(Config0
, State0
, DepPlt
, AppList0
) ->
130 Ignores
= Config0:match(dialyzer_ignore
, []),
132 App
= #app
{name
=Name
} <- AppList0
,
133 not
lists:member(Name
, Ignores
)],
135 case sin_utils:file_exists(State0
, DepPlt
) of
137 sin_log:verbose(Config0
, "Plt is built, checking/updating ..."),
138 [{analysis_type
, plt_check
},
141 sin_log:verbose(Config0
, "Building the plt, this is really going to "
142 "take a long time ..."),
143 [{analysis_type
, plt_build
},
144 {output_plt
, DepPlt
}]
147 Paths
= [filename:join(Path
, "ebin") ||
148 #app
{path
=Path
} <- AppList1
],
150 Opts
= [{files_rec
, Paths
},
151 {from
, byte_code
}] ++ Opts0
,
155 _:{dialyzer_error
, Error
} ->
157 {error_processing_apps
, Error
, AppList1
})
160 default_warnings() ->