]> git.madduck.net Git - etc/vim.git/blob - autoload/ale/handlers/gcc.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/ale/' content from commit 22185c4c
[etc/vim.git] / autoload / ale / handlers / gcc.vim
1 scriptencoding utf-8
2 " Author: w0rp <devw0rp@gmail.com>
3 " Description: This file defines a handler function which ought to work for
4 " any program which outputs errors in the format that GCC uses.
5
6 let s:pragma_error = '#pragma once in main file'
7
8 " Look for lines like the following.
9 "
10 " <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]
11 " <stdin>:10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’)
12 " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
13 let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+)?:?(\d+)?:? ([^:]+): (.+)$'
14 let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
15
16 function! s:IsHeaderFile(filename) abort
17     return a:filename =~? '\v\.(h|hpp)$'
18 endfunction
19
20 function! s:RemoveUnicodeQuotes(text) abort
21     let l:text = a:text
22     let l:text = substitute(l:text, '[`´‘’]', '''', 'g')
23     let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g')
24     let l:text = substitute(l:text, '[“”]', '"', 'g')
25
26     return l:text
27 endfunction
28
29 function! s:ParseInlinedFunctionProblems(buffer, lines) abort
30     let l:output = []
31     let l:pos_match = []
32
33     for l:line in a:lines
34         let l:match = matchlist(l:line, s:pattern)
35
36         if !empty(l:match) && !empty(l:pos_match)
37             call add(l:output, {
38             \   'lnum': str2nr(l:pos_match[1]),
39             \   'col': str2nr(l:pos_match[2]),
40             \   'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W',
41             \   'text': s:RemoveUnicodeQuotes(l:match[5]),
42             \})
43         endif
44
45         let l:pos_match = matchlist(l:line, s:inline_pattern)
46     endfor
47
48     return l:output
49 endfunction
50
51 " Report problems inside of header files just for gcc and clang
52 function! s:ParseProblemsInHeaders(buffer, lines) abort
53     let l:output = []
54     let l:include_item = {}
55
56     for l:line in a:lines[: -2]
57         let l:include_match = matchlist(l:line, '\v^In file included from')
58
59         if !empty(l:include_item)
60             let l:pattern_match = matchlist(l:line, s:pattern)
61
62             if !empty(l:pattern_match) && l:pattern_match[1] is# '<stdin>'
63                 if has_key(l:include_item, 'lnum')
64                     call add(l:output, l:include_item)
65                 endif
66
67                 let l:include_item = {}
68
69                 continue
70             endif
71
72             let l:include_item.detail .= "\n" . l:line
73         endif
74
75         if !empty(l:include_match)
76             if empty(l:include_item)
77                 let l:include_item = {
78                 \   'text': 'Error found in header. See :ALEDetail',
79                 \   'detail': l:line,
80                 \}
81             endif
82         endif
83
84         if !empty(l:include_item)
85             let l:stdin_match = matchlist(l:line, '\vfrom \<stdin\>:(\d+):(\d*):?$')
86
87             if !empty(l:stdin_match)
88                 let l:include_item.lnum = str2nr(l:stdin_match[1])
89
90                 if str2nr(l:stdin_match[2])
91                     let l:include_item.col = str2nr(l:stdin_match[2])
92                 endif
93             endif
94         endif
95     endfor
96
97     if !empty(l:include_item) && has_key(l:include_item, 'lnum')
98         call add(l:output, l:include_item)
99     endif
100
101     return l:output
102 endfunction
103
104 function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
105     let l:output = []
106
107     for l:match in ale#util#GetMatches(a:lines, s:pattern)
108         " Filter out the pragma errors
109         if s:IsHeaderFile(bufname(bufnr('')))
110         \&& l:match[5][:len(s:pragma_error) - 1] is# s:pragma_error
111             continue
112         endif
113
114         " If the 'error type' is a note, make it detail related to
115         " the previous error parsed in output
116         if l:match[4] is# 'note'
117             if !empty(l:output)
118                 if !has_key(l:output[-1], 'detail')
119                     let l:output[-1].detail = l:output[-1].text
120
121                     " handle macro expansion errors/notes
122                     if l:match[5] =~? '^in expansion of macro ‘\w*\w’$'
123                         " if the macro expansion is in the file we're in, add
124                         " the lnum and col keys to the previous error
125                         if l:match[1] is# '<stdin>'
126                         \ && !has_key(l:output[-1], 'col')
127                             let l:output[-1].lnum = str2nr(l:match[2])
128                             let l:output[-1].col = str2nr(l:match[3])
129                         else
130                             " the error is not in the current file, and since
131                             " macro expansion errors don't show the full path to
132                             " the error from the current file, we have to just
133                             " give out a generic error message
134                             let l:output[-1].text = 'Error found in macro expansion. See :ALEDetail'
135                         endif
136                     endif
137                 endif
138
139                 let l:output[-1].detail = l:output[-1].detail . "\n"
140                 \   . s:RemoveUnicodeQuotes(l:match[0])
141             endif
142
143             continue
144         endif
145
146         let l:item = {
147         \   'lnum': str2nr(l:match[2]),
148         \   'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W',
149         \   'text': s:RemoveUnicodeQuotes(l:match[5]),
150         \}
151
152         if !empty(l:match[3])
153             let l:item.col = str2nr(l:match[3])
154         endif
155
156         " If the filename is something like <stdin>, <nofile> or -, then
157         " this is an error for the file we checked.
158         if l:match[1] isnot# '-' && l:match[1][0] isnot# '<'
159             let l:item['filename'] = l:match[1]
160         endif
161
162         call add(l:output, l:item)
163     endfor
164
165     return l:output
166 endfunction
167
168 " Handle problems with the GCC format, but report problems inside of headers.
169 function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort
170     let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines)
171
172     call extend(l:output, s:ParseInlinedFunctionProblems(a:buffer, a:lines))
173     call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines))
174
175     return l:output
176 endfunction