diff --git a/README.md b/README.md index 4540ac9f..b6f1aa09 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ formatting. | Language | Tools | | -------- | ----- | +| Ada | [gcc](https://gcc.gnu.org) | | ASM | [gcc](https://gcc.gnu.org) | | Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) | | API Blueprint | [drafter](https://github.com/apiaryio/drafter) | diff --git a/ale_linters/ada/gcc.vim b/ale_linters/ada/gcc.vim new file mode 100644 index 00000000..d6f973ae --- /dev/null +++ b/ale_linters/ada/gcc.vim @@ -0,0 +1,54 @@ +" Author: Martino Pilia +" Description: Lint Ada files with GCC + +call ale#Set('ada_gcc_executable', 'gcc') + +" -gnatwa: activate most optional warnings +" -gnatq: try semantic analysis even if syntax errors have been found +call ale#Set('ada_gcc_options', '-gnatwa -gnatq') + +function! ale_linters#ada#gcc#GetCommand(buffer) abort + " Build a suitable output file name. The output file is specified because + " the .ali file may be created even if no code generation is attempted. + " The output file name must match the source file name (except for the + " extension), so here we cannot use the null file as output. + let l:tmp_dir = fnamemodify(ale#engine#CreateDirectory(a:buffer), ':p') + let l:out_file = l:tmp_dir . fnamemodify(bufname(a:buffer), ':t:r') . '.o' + + " -gnatc: Check syntax and semantics only (no code generation attempted) + return '%e -x ada -c -gnatc' + \ . ' -o ' . ale#Escape(l:out_file) + \ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) + \ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options')) + \ . ' %t' +endfunction + +" For the message format please refer to: +" https://gcc.gnu.org/onlinedocs/gnat_ugn/Output-and-Error-Message-Control.html +" https://gcc.gnu.org/onlinedocs/gnat_ugn/Warning-Message-Control.html +function! ale_linters#ada#gcc#Handle(buffer, lines) abort + " Error format: ::: + " Warning format: ::: warning: + let l:re = '\v(.+):([0-9]+):([0-9]+):\s+(warning:)?\s*(.+)\s*' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:re) + call add(l:output, { + \ 'bufnr': a:buffer, + \ 'lnum': str2nr(l:match[2]), + \ 'col': str2nr(l:match[3]), + \ 'type': l:match[4] is# 'warning:' ? 'W' : 'E', + \ 'text': l:match[5], + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('ada', { +\ 'name': 'gcc', +\ 'output_stream': 'stderr', +\ 'executable_callback': ale#VarFunc('ada_gcc_executable'), +\ 'command_callback': 'ale_linters#ada#gcc#GetCommand', +\ 'callback': 'ale_linters#ada#gcc#Handle', +\}) diff --git a/doc/ale-ada.txt b/doc/ale-ada.txt new file mode 100644 index 00000000..93e3261a --- /dev/null +++ b/doc/ale-ada.txt @@ -0,0 +1,25 @@ +=============================================================================== +ALE Ada Integration *ale-ada-options* + + +=============================================================================== +gcc *ale-ada-gcc* + +g:ale_ada_gcc_executable *g:ale_ada_gcc_executable* + *b:ale_ada_gcc_executable* + Type: |String| + Default: `'gcc'` + +This variable can be changed to use a different executable for gcc. + + +g:ale_ada_gcc_options *g:ale_ada_gcc_options* + *b:ale_ada_gcc_options* + Type: |String| + Default: `'-gnatwa -gnatq'` + + This variable can be set to pass additional options to gcc. + + +=============================================================================== + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale.txt b/doc/ale.txt index 85f6b6f8..de054e4d 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -21,6 +21,8 @@ CONTENTS *ale-contents* 6.1 Highlights........................|ale-highlights| 6.2 Options for write-good Linter.....|ale-write-good-options| 7. Integration Documentation............|ale-integrations| + ada...................................|ale-ada-options| + gcc.................................|ale-ada-gcc| ansible...............................|ale-ansible-options| ansible-lint........................|ale-ansible-ansible-lint| asciidoc..............................|ale-asciidoc-options| @@ -392,6 +394,7 @@ Notes: `^` No linters for text or Vim help filetypes are enabled by default. `!!` These linters check only files on disk. See |ale-lint-file-linters| +* Ada: `gcc` * ASM: `gcc` * Ansible: `ansible-lint` * API Blueprint: `drafter` diff --git a/test/command_callback/test_ada_gcc_command_callbacks.vader b/test/command_callback/test_ada_gcc_command_callbacks.vader new file mode 100644 index 00000000..de6e355e --- /dev/null +++ b/test/command_callback/test_ada_gcc_command_callbacks.vader @@ -0,0 +1,44 @@ +Before: + call ale#assert#SetUpLinterTest('ada', 'gcc') + call ale#test#SetFilename('dummy.adb') + + function! GetOutputDir(command) abort + let l:split_command = split(a:command) + let l:index = index(l:split_command, '-o') + return l:split_command[l:index + 1] + endfunction + + let b:out_file = GetOutputDir(ale_linters#ada#gcc#GetCommand(bufnr(''))) + +After: + delfunction GetOutputDir + + unlet! b:out_file + + call ale#assert#TearDownLinterTest() + +Execute(The executable should be configurable): + + AssertLinter 'gcc', + \ ale#Escape('gcc') . ' -x ada -c -gnatc' + \ . ' -o ' . b:out_file + \ . ' -I ' . ale#Escape(getcwd()) + \ . ' -gnatwa -gnatq %t' + + let b:ale_ada_gcc_executable = 'foo' + + AssertLinter 'foo', + \ ale#Escape('foo') . ' -x ada -c -gnatc' + \ . ' -o ' . b:out_file + \ . ' -I ' . ale#Escape(getcwd()) + \ . ' -gnatwa -gnatq %t' + +Execute(The options should be configurable): + + let g:ale_ada_gcc_options = '--foo --bar' + + AssertLinter 'gcc', + \ ale#Escape('gcc') . ' -x ada -c -gnatc' + \ . ' -o ' . b:out_file + \ . ' -I ' . ale#Escape(getcwd()) + \ . ' --foo --bar %t' diff --git a/test/handler/test_ada_gcc_handler.vader b/test/handler/test_ada_gcc_handler.vader new file mode 100644 index 00000000..06ddfe1f --- /dev/null +++ b/test/handler/test_ada_gcc_handler.vader @@ -0,0 +1,36 @@ +Before: + runtime ale_linters/ada/gcc.vim + +After: + call ale#linter#Reset() + +Execute(The gcc handler for Ada should parse input correctly): + AssertEqual + \ [ + \ { + \ 'bufnr': 0, + \ 'lnum': 8, + \ 'col': 5, + \ 'type': 'W', + \ 'text': 'variable "X" is assigned but never read', + \ }, + \ { + \ 'bufnr': 0, + \ 'lnum': 6, + \ 'col': 22, + \ 'type': 'E', + \ 'text': 'type definition expected', + \ }, + \ { + \ 'bufnr': 0, + \ 'lnum': 8, + \ 'col': 9, + \ 'type': 'E', + \ 'text': 'aspect specifications not allowed here', + \ }, + \ ], + \ ale_linters#ada#gcc#Handle(0, [ + \ 'foobar.adb:8:05: warning: variable "X" is assigned but never read', + \ 'foobar.ads:6:22: type definition expected', + \ 'foobar.ads:8:09: aspect specifications not allowed here', + \ ])