From 592046d7c5f4937f08befb0432f773d0254513bf Mon Sep 17 00:00:00 2001 From: Sergey Urbanovich Date: Tue, 5 Sep 2017 20:58:27 -0700 Subject: [PATCH 1/2] Use printf instead of echo -e echo -e is not posix-compatible and doesn't work on bsd-like systems --- test/test.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/test.sh b/test/test.sh index 8739d51..9a44b4c 100755 --- a/test/test.sh +++ b/test/test.sh @@ -11,28 +11,30 @@ function check() { local predicate="$4" local pattern="$5" - echo -en "${file}\t" + printf "%s\t" "${file}" output=$(${SYNTAXERL} ${SCRIPT_DIR}/${file}) ret=$? - echo -n code: ${code}/${ret} " " + printf "code: %s/%s " "${code}" "${ret}" if [[ ${ret} == ${code} && ${predicate} == "w/" && ${pattern} == "" ]]; then - echo -e "\e[32mOK\e[0m" + printf "\e[32mOK\e[0m\n" elif [[ ${ret} == ${code} ]]; then echo ${output} | grep "${pattern}" > /dev/null ret2=$? - echo -n grep: ${ret2} " " + printf "grep: %s " "${ret2}" if [[ ${ret2} == 0 && "${predicate}" == "w/" ]]; then - echo -e "\e[32mOK\e[0m" + printf "\e[32mOK\e[0m\n" elif [[ ${ret2} == 1 && "${predicate}" == "w/o" ]]; then - echo -e "\e[32mOK\e[0m" + printf "\e[32mOK\e[0m\n" else - echo -e "\e[31mFAIL\e[0m" + printf "\e[31mFAIL\e[0m\n" + printf "\tOutput: %s\n" "${output}" >&2 EXIT=1 fi else - echo -e "\e[31mFAIL\e[0m" + printf "\e[31mFAIL\e[0m\n" + printf "\tOutput: %s\n" "${output}" >&2 EXIT=1 fi } From 3751b5ad9da3127cc93a61636eeb6218bd9bac41 Mon Sep 17 00:00:00 2001 From: Sergey Urbanovich Date: Tue, 5 Sep 2017 21:12:00 -0700 Subject: [PATCH 2/2] Show correct source of errors and warnings --- src/issues_spec.hrl | 6 ++-- src/syntaxerl.erl | 4 +-- src/syntaxerl_escript.erl | 20 +++++++++--- src/syntaxerl_format.erl | 32 +++++++++---------- src/syntaxerl_hrl.erl | 24 ++++++++++---- src/syntaxerl_script.erl | 21 ++++++++++-- src/syntaxerl_terms.erl | 8 ++--- src/syntaxerl_utils.erl | 26 +++++++++------ .../rebar3-apps/apps/app1/include/bad.hrl | 1 + .../rebar3-apps/apps/app1/src/include.erl | 3 ++ test/test.sh | 2 ++ 11 files changed, 98 insertions(+), 49 deletions(-) create mode 100644 test/projects/rebar3-apps/apps/app1/include/bad.hrl create mode 100644 test/projects/rebar3-apps/apps/app1/src/include.erl diff --git a/src/issues_spec.hrl b/src/issues_spec.hrl index 76865dd..3168809 100644 --- a/src/issues_spec.hrl +++ b/src/issues_spec.hrl @@ -1,9 +1,9 @@ -ifndef(issues_spec_hrl). -define(issues_spec_hrl, included). --type warning() :: {warning, Line::pos_integer(), Description::string()}. --type error() :: {error, Description::string()} | - {error, Line::pos_integer(), Description::string()}. +-type warning() :: {warning, Filename::file:filename(), Line::pos_integer(), Description::string()}. +-type error() :: {error, Filename::file:filename(), Description::string()} | + {error, Filename::file:filename(), Line::pos_integer(), Description::string()}. -type issue() :: warning() | error(). diff --git a/src/syntaxerl.erl b/src/syntaxerl.erl index 09b545e..8ed6418 100644 --- a/src/syntaxerl.erl +++ b/src/syntaxerl.erl @@ -71,10 +71,10 @@ check_syntax(FileName, BaseFileName, Debug) -> syntaxerl_logger:debug(Debug, "Selected handler: ~p", [Handler]), case Handler:check_syntax(FileName, BaseFileName, Debug) of {ok, Issues} -> - syntaxerl_utils:print_issues(FileName, Issues), + syntaxerl_utils:print_issues(BaseFileName, FileName, Issues), halt(?EXIT_SUCCESS); {error, Issues} -> - syntaxerl_utils:print_issues(FileName, Issues), + syntaxerl_utils:print_issues(BaseFileName, FileName, Issues), halt(?EXIT_FAILURE) end. diff --git a/src/syntaxerl_escript.erl b/src/syntaxerl_escript.erl index c130416..ab3d3d8 100644 --- a/src/syntaxerl_escript.erl +++ b/src/syntaxerl_escript.erl @@ -44,18 +44,20 @@ check_syntax(FileName, BaseFileName, Debug) -> {ok, _ModuleName} -> {ok, []}; {ok, _ModuleName, Warnings} -> - io:format("Warnings: ~p~n", [Warnings]), + Warnings0 = fix_file_names(NewFileName, FileName, Warnings), {ok, syntaxerl_format:format_warnings( - ?MODULE, fix_line_numbers(Warnings))}; + ?MODULE, fix_line_numbers(Warnings0))}; {error, Errors, Warnings} -> + Errors0 = fix_file_names(NewFileName, FileName, Errors), + Warnings0 = fix_file_names(NewFileName, FileName, Warnings), case syntaxerl_format:format_errors( - ?MODULE, fix_line_numbers(Errors)) of + ?MODULE, fix_line_numbers(Errors0)) of [] -> {ok, syntaxerl_format:format_warnings( - ?MODULE, fix_line_numbers(Warnings))}; + ?MODULE, fix_line_numbers(Warnings0))}; Errors2 -> {error, Errors2 ++ syntaxerl_format:format_warnings( - ?MODULE, fix_line_numbers(Warnings))} + ?MODULE, fix_line_numbers(Warnings0))} end end; {error, Reason} -> @@ -73,6 +75,14 @@ output_warning(_) -> true. %% Internal %% =================================================================== +fix_file_names(TmpFileName, FileName, ErrorList) -> + [fix_file_name(TmpFileName, FileName, Error) || Error <- ErrorList]. + +fix_file_name(TmpFileName, FileName, {TmpFileName, ErrorList}) -> + {FileName, ErrorList}; +fix_file_name(_TmpFileName, _FileName, {FileName, ErrorList}) -> + {FileName, ErrorList}. + fix_line_numbers(ErrorList) -> ErrorList0 = skip_expected_errors(ErrorList), [{F, [{fix_line_number(L), M, E} || {L, M, E} <- Es]} diff --git a/src/syntaxerl_format.erl b/src/syntaxerl_format.erl index a55f019..299e98a 100644 --- a/src/syntaxerl_format.erl +++ b/src/syntaxerl_format.erl @@ -12,33 +12,31 @@ %% API %% =================================================================== --spec format_errors(module(), error_list()) -> - [{error, integer(), string()}]. -format_errors(_Handler, []) -> - []; -format_errors(Handler, [{_FileName, Errors} | _]) -> - [format_error(E) || E <- Errors, Handler:output_error(E)]. - --spec format_warnings(module(), warning_list()) -> - [{warning, integer(), string()}]. -format_warnings(_Handler, []) -> - []; -format_warnings(Handler, [{_FileName, Warnings} | _]) -> - [format_warning(W) || W <- Warnings, Handler:output_warning(W)]. +-spec format_errors(module(), error_list()) -> [error()]. +format_errors(Handler, List) -> + lists:flatmap(fun ({FileName, Errors}) -> + [format_error(FileName, E) || E <- Errors, Handler:output_error(E)] + end, List). + +-spec format_warnings(module(), warning_list()) -> [warning()]. +format_warnings(Handler, List) -> + lists:flatmap(fun ({FileName, Warnings}) -> + [format_warning(FileName, W) || W <- Warnings, Handler:output_warning(W)] + end, List). %% =================================================================== %% Internal %% =================================================================== -format_error({Line, _Module, _Term} = Error) -> +format_error(FileName, {Line, _Module, _Term} = Error) -> Description = error_description(Error), FixedLine = fix_line_number(Line), - {error, FixedLine, Description}. + {error, FileName, FixedLine, Description}. -format_warning({Line, _Module, _Term} = Error) -> +format_warning(FileName, {Line, _Module, _Term} = Error) -> Description = error_description(Error), FixedLine = fix_line_number(Line), - {warning, FixedLine, Description}. + {warning, FileName, FixedLine, Description}. -spec error_description({integer(), module(), term()}) -> string(). error_description({_Line, Module, Error}) -> diff --git a/src/syntaxerl_hrl.erl b/src/syntaxerl_hrl.erl index 0855bb8..c89db7c 100644 --- a/src/syntaxerl_hrl.erl +++ b/src/syntaxerl_hrl.erl @@ -43,24 +43,27 @@ check_syntax(FileName, BaseFileName, Debug) -> {ok, _ModuleName} -> {ok, []}; {ok, _ModuleName, Warnings} -> + Warnings0 = fix_file_names(NewFileName, FileName, Warnings), {ok, syntaxerl_format:format_warnings( - ?MODULE, fix_line_numbers(Warnings))}; + ?MODULE, fix_line_numbers(Warnings0))}; {error, Errors, Warnings} -> + Errors0 = fix_file_names(NewFileName, FileName, Errors), + Warnings0 = fix_file_names(NewFileName, FileName, Warnings), case syntaxerl_format:format_errors( - ?MODULE, fix_line_numbers(Errors)) of + ?MODULE, fix_line_numbers(Errors0)) of [] -> {ok, syntaxerl_format:format_warnings( - ?MODULE, fix_line_numbers(Warnings))}; + ?MODULE, fix_line_numbers(Warnings0))}; Errors2 -> {error, Errors2 ++ syntaxerl_format:format_warnings( - ?MODULE, fix_line_numbers(Warnings))} + ?MODULE, fix_line_numbers(Warnings0))} end end; {error, Reason} -> - {error, [{error, file:format_error(Reason)}]} + {error, [{FileName, file:format_error(Reason)}]} end; {error, Reason} -> - {error, [{error, file:format_error(Reason)}]} + {error, [{FileName, file:format_error(Reason)}]} end. %% skip errors that might occur in pure header files. @@ -76,6 +79,15 @@ output_warning(_) -> true. %% Internal %% =================================================================== +fix_file_names(TmpFileName, FileName, ErrorList) -> + [fix_file_name(TmpFileName, FileName, Error) || Error <- ErrorList]. + +fix_file_name(TmpFileName, FileName, {TmpFileName, ErrorList}) -> + {FileName, ErrorList}; +fix_file_name(_TmpFileName, _FileName, {FileName, ErrorList}) -> + {FileName, ErrorList}. + + fix_line_numbers(ErrorList) -> [{F, [{fix_line_number(L), M, E} || {L, M, E} <- Es]} || {F, Es} <- ErrorList]. diff --git a/src/syntaxerl_script.erl b/src/syntaxerl_script.erl index daefd3a..2e91239 100644 --- a/src/syntaxerl_script.erl +++ b/src/syntaxerl_script.erl @@ -6,7 +6,8 @@ -export([ check_syntax/3, output_error/1, - output_warning/1 + output_warning/1, + format_error/2 ]). -include("check_syntax_spec.hrl"). @@ -20,9 +21,25 @@ check_syntax(FileName, _BaseFileName, _Debug) -> {ok, _} -> {ok, []}; {error, Error} -> - {error, [{error, file:format_error(Error)}]} + %% unfortunately the `file:consult' returns only the first error. + format_error(FileName, Error) end. output_error(_) -> true. output_warning(_) -> true. + +%% =================================================================== +%% Internal +%% =================================================================== + +-spec format_error(file:filename(), Error) -> {ok, term()} | {error, error()} + when Error :: file:posix() | badarg | terminated | system_limit | + {Line :: integer(), Mod :: module(), Term :: term()}. +format_error(FileName, {Line, Mod, Term}) -> + ErrorStrPrefix = iolist_to_binary(io_lib:format("~p: ", [Line])), + ErrorStr = iolist_to_binary(file:format_error({Line, Mod, Term})), + [<<>>, ErrorStr0] = binary:split(ErrorStr, ErrorStrPrefix), + {error, [{error, FileName, Line, ErrorStr0}]}; +format_error(FileName, Error) -> + {error, [{error, FileName, 1, file:format_error(Error)}]}. diff --git a/src/syntaxerl_terms.erl b/src/syntaxerl_terms.erl index ce04b76..5245a5a 100644 --- a/src/syntaxerl_terms.erl +++ b/src/syntaxerl_terms.erl @@ -16,12 +16,12 @@ %% =================================================================== check_syntax(FileName, _BaseFileName, _Debug) -> - case file:eval(FileName) of - ok -> + case file:consult(FileName) of + {ok, _} -> {ok, []}; {error, Error} -> - %% unfortunately the `file:eval' returns only the first error. - {error, [{error, file:format_error(Error)}]} + %% unfortunately the `file:consult' returns only the first error. + syntaxerl_script:format_error(FileName, Error) end. output_error(_) -> true. diff --git a/src/syntaxerl_utils.erl b/src/syntaxerl_utils.erl index 6b4bd0d..93b101c 100644 --- a/src/syntaxerl_utils.erl +++ b/src/syntaxerl_utils.erl @@ -3,7 +3,7 @@ -export([ incls_deps_opts/1, - print_issues/2, + print_issues/3, consult_file/1 ]). @@ -134,18 +134,16 @@ deps_opts(BaseDir, OtpStdDirs, ErlcStdOpts, Profile) -> UniqErlcOpts = uniq(ErlcStdOpts ++ ErlcOpts), {UniqDepsDirs, UniqErlcOpts}. --spec print_issues(FileName::file:filename(), Issues::[issue()]) -> ok. -print_issues(_FileName, []) -> - ok; -print_issues(FileName, [Issue | Issues]) -> - print_issue(FileName, Issue), - print_issues(FileName, Issues). +-spec print_issues(FileName::file:filename(), BaseFileName::file:filename(), Issues::[issue()]) -> ok. +print_issues(OrigFileName, BaseFileName, List) -> + List0 = fix_file_names(OrigFileName, BaseFileName, List), + lists:foreach(fun print_issue/1, List0). -print_issue(FileName, {warning, Line, Description}) -> +print_issue({warning, FileName, Line, Description}) -> io:format("~s:~p: warning: ~s~n", [FileName, Line, Description]); -print_issue(FileName, {error, Description}) -> +print_issue({error, FileName, Description}) -> io:format("~s:~s~n", [FileName, Description]); -print_issue(FileName, {error, Line, Description}) -> +print_issue({error, FileName, Line, Description}) -> io:format("~s:~p: ~s~n", [FileName, Line, Description]). -spec consult_file(file:filename()) -> {ok, term()} | {error, error()}. @@ -443,6 +441,14 @@ try_consult(File) -> syntaxerl_logger:debug(true, "Failed to read config file ~s: ~p~n", [File, Reason]) end. +fix_file_names(FileName, BaseFileName, ErrorList) -> + [fix_file_name(FileName, BaseFileName, Error) || Error <- ErrorList]. + +fix_file_name(FileName, BaseFileName, {Type, FileName, Line, Description}) -> + {Type, BaseFileName, Line, Description}; +fix_file_name(_TmpFileName, _FileName, Issue) -> + Issue. + bs(Vars) -> lists:foldl(fun({K,V}, Bs) -> erl_eval:add_binding(K, V, Bs) diff --git a/test/projects/rebar3-apps/apps/app1/include/bad.hrl b/test/projects/rebar3-apps/apps/app1/include/bad.hrl new file mode 100644 index 0000000..7cb23c2 --- /dev/null +++ b/test/projects/rebar3-apps/apps/app1/include/bad.hrl @@ -0,0 +1 @@ +-define(macros). diff --git a/test/projects/rebar3-apps/apps/app1/src/include.erl b/test/projects/rebar3-apps/apps/app1/src/include.erl new file mode 100644 index 0000000..0b02a31 --- /dev/null +++ b/test/projects/rebar3-apps/apps/app1/src/include.erl @@ -0,0 +1,3 @@ +-module(include). + +-include("bad.hrl"). diff --git a/test/test.sh b/test/test.sh index 9a44b4c..b5d335a 100755 --- a/test/test.sh +++ b/test/test.sh @@ -72,4 +72,6 @@ check projects/rebar3-apps/apps/app1/src/subdir/subsrc.erl code 0 w/ "" check projects/rebar3-apps/_build/default/lib/lib2/src/src.erl code 0 w/ "" check projects/rebar3-apps/apps/app1/src/types.erl code 0 w/ "" +check projects/rebar3-apps/apps/app1/src/include.erl code 1 w/ "bad.hrl:1: badly formed 'define'" + exit ${EXIT}