вторник, февраля 25, 2014

dialyzer + erlang.mk, статический анализ одной командой

(продолжение новичковых конспектов)
В качестве вступления обозначу очевидное.
Есть три способа узнать об ошибке в коде.
Долгий и муторный - поймать её в продакшене.
На порядок быстрее выловить тестами.
Самый шустрый - сразу, с помощью статического анализатора.
Последние два способа хоть и не панацея, но время серьёзно экономят.

Так вот давеча решил: пора навести порядок в коде.
И сделал ещё один подход к dialyzer`у.

Как-то у нас не сложилось, когда я только знакомился с эрлангом.
Но в этот раз использую erlang.mk и процесс упростился донельзя.
Шаг первый, собираем информацию из системных модулей:

dialyzer --build_plt --apps kernel stdlib crypto mnesia sasl common_test eunit
(создаст ~/.dialyzer_plt)
Шаг второй, строим plt для своего проекта:

make build-plt
(создаст .имяпроекта.plt)

Шаг третий - всё, можно приступать:

make dialyze

И даже без добавления описаний типов в код - сразу же вылезла масса затаившихся ошибок.

Из-за используемого lager`а мешали записи вида:
Call to missing or unexported function lager:warning/3

Связано это с тем, что в исходниках lager`а упомянутых методов нету - они создаются во время компиляции.
Поэтому я немного поправил erlang.mk, заменив

dialyze:
 @dialyzer --src src --plt .$(PROJECT).plt --no_native $(DIALYZER_OPTS) 

на

dialyze:
 @dialyzer --src src --plt .$(PROJECT).plt --no_native $(DIALYZER_OPTS) | fgrep -v -f ./dialyzer.ignore-warnings

Создаём файл dialyzer.ignore-warnings:

Call to missing or unexported function lager:warning/3
Call to missing or unexported function lager:warning/1
Call to missing or unexported function lager:warning/2
Call to missing or unexported function lager:info/1
Call to missing or unexported function lager:info/2
Call to missing or unexported function lager:notice/2
Call to missing or unexported function lager:notice/1
Call to missing or unexported function lager:error/1
Call to missing or unexported function lager:error/2

Не забываем, что каждая строка этого файла будет сравниваться со строкой вывода dialyzer`а.
Смотрим чтобы не было лишних пробелов в конце строк.

Дальше самый долгий процесс - добавление информации о типах в проект.
Лучше не откладывать "на потом".
В процессе описания типов найдётся о чём поразмыслить.

Как прописывать типы замечательно описано в LYSE, делать вольный пересказ резона нет.

В некоторых сторонних приложениях уже есть описания используемых типов - некоторые могут пригодиться.

Например в .hrl файле:
-include("deps/sqlite3/include/sqlite3.hrl").
(sqlite3 хороший пример приложения в котором всё тщательно описано)

Комментариев нет: