From 25d2af0b2529006ba869a5906afae028f7b9f28e Mon Sep 17 00:00:00 2001 From: Gerry Agbobada <10496163+gagbo@users.noreply.github.com> Date: Wed, 25 Oct 2017 23:29:36 +0200 Subject: Handle multiple files localtion lists with gcc handler (#1034) Handle multiple files in the GCC handler. --- autoload/ale/handlers/gcc.vim | 76 ++++++++++++++++----------------- test/handler/test_clang_handler.vader | 12 ++---- test/handler/test_gcc_handler.vader | 43 +++++++++---------- test/handler/test_vint_handler.vader | 6 +++ test/sign/test_linting_sets_signs.vader | 3 +- 5 files changed, 69 insertions(+), 71 deletions(-) diff --git a/autoload/ale/handlers/gcc.vim b/autoload/ale/handlers/gcc.vim index ad5cab39..a3f2a302 100644 --- a/autoload/ale/handlers/gcc.vim +++ b/autoload/ale/handlers/gcc.vim @@ -43,6 +43,10 @@ endfunction function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort let l:include_pattern = '\v^(In file included | *)from ([^:]*):(\d+)' + " Include pattern looks for lines like : + " + " In file included from test.h:1:0, + " from test.cpp:1: let l:include_lnum = 0 let l:include_lines = [] let l:included_filename = '' @@ -58,51 +62,42 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort let l:match = matchlist(l:line, l:pattern) if empty(l:match) - " Check for matches in includes. - " We will keep matching lines until we hit the last file, which - " is our file. let l:include_match = matchlist(l:line, l:include_pattern) - - if empty(l:include_match) - " If this isn't another include header line, then we - " need to collect it. - call add(l:include_lines, l:line) - else - " GCC and clang return the lists of files in different orders, - " so we'll only grab the line number from lines which aren't - " header files. - if !s:IsHeaderFile(l:include_match[2]) - " Get the line number out of the parsed include line, - " and reset the other variables. - let l:include_lnum = str2nr(l:include_match[3]) - endif - - let l:include_lines = [] - let l:included_filename = '' + " If the line has an 'included from' pattern, store the line to + " create a gutter sign at the appropriate location in linted file + if !empty(l:include_match) + " We don't check if l:include_match[2] is linted filename + " because the last line matching include_pattern in a group + " of contiguous lines is probably concerning the linted file + " anyway + let l:include_lnum = l:include_match[3] endif - elseif l:include_lnum > 0 - \&& (empty(l:included_filename) || l:included_filename is# l:match[1]) - " If we hit the first error after an include header, or the - " errors below have the same name as the first filename we see, - " then include these lines, and remember what that filename was. - let l:included_filename = l:match[1] - call add(l:include_lines, l:line) else - " If we hit a regular error again, then add the previously - " collected lines as one error, and reset the include variables. - call s:AddIncludedErrors(l:output, l:include_lnum, l:include_lines) - let l:include_lnum = 0 - let l:include_lines = [] - let l:included_filename = '' - + " Filter out the pragma errors if s:IsHeaderFile(bufname(bufnr(''))) \&& l:match[5][:len(s:pragma_error) - 1] is# s:pragma_error continue endif + " If the 'error type' is a note, make it detail related to + " the previous error parsed in output + if l:match[4] is# 'note' + let l:output[-1]['detail'] = get(l:output[-1], 'detail', '') + \ . s:RemoveUnicodeQuotes(l:match[0]) . "\n" + continue + endif + + " If l:include_lnum is non-null, then the error relates to + " an included file and l:include_lnum is the line number + " where a gutter sign would be needed in linted file + + " The ternary operator in filename filters out the 'dummy' + " filenames like or and leave the location + " handling to engine#FixLocList let l:item = { + \ 'filename': (l:match[1][:0] is# '<') ? '' : l:match[1], \ 'lnum': str2nr(l:match[2]), - \ 'type': l:match[4] =~# 'error' ? 'E' : 'W', + \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'text': s:RemoveUnicodeQuotes(l:match[5]), \} @@ -110,12 +105,17 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort let l:item.col = str2nr(l:match[3]) endif + " Finish filtering out filename : if the key exists but is empty, + " unlet it. + if get(l:item, 'filename', 'dummy_no_key_to_unlet') is# '' + unlet l:item['filename'] + endif + call add(l:output, l:item) + " Reset include_lnum after an error has been added + let l:include_lnum = 0 endif endfor - " Add remaining include errors after we go beyond the last line. - call s:AddIncludedErrors(l:output, l:include_lnum, l:include_lines) - return l:output endfunction diff --git a/test/handler/test_clang_handler.vader b/test/handler/test_clang_handler.vader index d28b9eb8..278737a8 100644 --- a/test/handler/test_clang_handler.vader +++ b/test/handler/test_clang_handler.vader @@ -2,15 +2,11 @@ Execute(clang errors from included files should be parsed correctly): AssertEqual \ [ \ { - \ 'lnum': 3, + \ 'lnum': 1, + \ 'col': 1, + \ 'filename': './b.h', \ 'type': 'E', - \ 'text': 'Problems were found in the header (See :ALEDetail)', - \ 'detail': join([ - \ './b.h:1:1: error: expected identifier or ''(''', - \ '{{{', - \ '^', - \ '1 error generated.', - \ ], "\n"), + \ 'text': 'expected identifier or ''(''', \ }, \ ], \ ale#handlers#gcc#HandleGCCFormat(347, [ diff --git a/test/handler/test_gcc_handler.vader b/test/handler/test_gcc_handler.vader index 2f60390c..be9e90ee 100644 --- a/test/handler/test_gcc_handler.vader +++ b/test/handler/test_gcc_handler.vader @@ -2,14 +2,11 @@ Execute(GCC errors from included files should be parsed correctly): AssertEqual \ [ \ { - \ 'lnum': 3, + \ 'lnum': 1, + \ 'col': 1, + \ 'filename': 'broken.h', \ 'type': 'E', - \ 'text': 'Problems were found in the header (See :ALEDetail)', - \ 'detail': join([ - \ 'broken.h:1:1: error: expected identifier or ''('' before ''{'' token', - \ ' {{{', - \ ' ^', - \ ], "\n"), + \ 'text': 'expected identifier or ''('' before ''{'' token', \ }, \ ], \ ale#handlers#gcc#HandleGCCFormat(347, [ @@ -22,14 +19,11 @@ Execute(GCC errors from included files should be parsed correctly): AssertEqual \ [ \ { - \ 'lnum': 3, + \ 'lnum': 1, + \ 'col': 1, + \ 'filename': 'b.h', \ 'type': 'E', - \ 'text': 'Problems were found in the header (See :ALEDetail)', - \ 'detail': join([ - \ 'b.h:1:1: error: expected identifier or ''('' before ''{'' token', - \ ' {{{', - \ ' ^', - \ ], "\n"), + \ 'text': 'expected identifier or ''('' before ''{'' token', \ }, \ ], \ ale#handlers#gcc#HandleGCCFormat(347, [ @@ -43,17 +37,18 @@ Execute(GCC errors from included files should be parsed correctly): AssertEqual \ [ \ { - \ 'lnum': 3, + \ 'lnum': 1, + \ 'col': 1, + \ 'filename': 'b.h', \ 'type': 'E', - \ 'text': 'Problems were found in the header (See :ALEDetail)', - \ 'detail': join([ - \ 'b.h:1:1: error: unknown type name ‘bad_type’', - \ ' bad_type x;', - \ ' ^', - \ 'b.h:2:1: error: unknown type name ‘other_bad_type’', - \ ' other_bad_type y;', - \ ' ^', - \ ], "\n"), + \ 'text': 'unknown type name ''bad_type''', + \ }, + \ { + \ 'lnum': 2, + \ 'col': 1, + \ 'filename': 'b.h', + \ 'type': 'E', + \ 'text': 'unknown type name ''other_bad_type''', \ }, \ ], \ ale#handlers#gcc#HandleGCCFormat(347, [ diff --git a/test/handler/test_vint_handler.vader b/test/handler/test_vint_handler.vader index 8747979c..c542b4ea 100644 --- a/test/handler/test_vint_handler.vader +++ b/test/handler/test_vint_handler.vader @@ -10,12 +10,14 @@ Execute(The vint handler should parse error messages correctly): \ { \ 'lnum': 1, \ 'col': 1, + \ 'filename': 'gcc.vim', \ 'text': 'Use scriptencoding when multibyte char exists (see :help :script encoding)', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'col': 17, + \ 'filename': 'gcc.vim', \ 'end_col': 18, \ 'text': 'Use robust operators ''==#'' or ''==?'' instead of ''=='' (see Google VimScript Style Guide (Matching))', \ 'type': 'W', @@ -23,6 +25,7 @@ Execute(The vint handler should parse error messages correctly): \ { \ 'lnum': 3, \ 'col': 8, + \ 'filename': 'gcc.vim', \ 'end_col': 15, \ 'text': 'Make the scope explicit like ''l:filename'' (see Anti-pattern of vimrc (Scope of identifier))', \ 'type': 'W', @@ -30,6 +33,7 @@ Execute(The vint handler should parse error messages correctly): \ { \ 'lnum': 7, \ 'col': 8, + \ 'filename': 'gcc.vim', \ 'end_col': 15, \ 'text': 'Undefined variable: filename (see :help E738)', \ 'type': 'W', @@ -37,6 +41,7 @@ Execute(The vint handler should parse error messages correctly): \ { \ 'lnum': 8, \ 'col': 11, + \ 'filename': 'gcc.vim', \ 'end_col': 16, \ 'text': 'E128: Function name must start with a capital or contain a colon: foobar (see ynkdir/vim-vimlparser)', \ 'type': 'E', @@ -44,6 +49,7 @@ Execute(The vint handler should parse error messages correctly): \ { \ 'lnum': 9, \ 'col': 12, + \ 'filename': 'gcc.vim', \ 'end_col': 13, \ 'text': 'Use robust operators ''=~#'' or ''=~?'' instead of ''=~'' (see Google VimScript Style Guide (Matching))', \ 'type': 'W', diff --git a/test/sign/test_linting_sets_signs.vader b/test/sign/test_linting_sets_signs.vader index f9bd63b0..271540e2 100644 --- a/test/sign/test_linting_sets_signs.vader +++ b/test/sign/test_linting_sets_signs.vader @@ -20,7 +20,8 @@ Before: let l:actual_sign_list = [] for l:line in split(l:output, "\n") - let l:match = matchlist(l:line, 'line=\(\d\+\).*name=\(ALE[a-zA-Z]\+\)') + let l:match = matchlist(l:line, '\m\s*line=\(\d\+\).*name=\(ALE[a-zA-Z]\+\)') + if len(l:match) > 0 call add(l:actual_sign_list, [l:match[1], l:match[2]]) -- cgit v1.2.3