Merge pull request #892 from jparise/thrift
Add a linter for Apache Thrift IDL files
This commit is contained in:
commit
b8f5a4923c
@ -135,6 +135,7 @@ formatting.
|
|||||||
| Tcl | [nagelfar](http://nagelfar.sourceforge.net) !! |
|
| Tcl | [nagelfar](http://nagelfar.sourceforge.net) !! |
|
||||||
| Texinfo | [proselint](http://proselint.com/)|
|
| Texinfo | [proselint](http://proselint.com/)|
|
||||||
| Text^ | [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) |
|
| Text^ | [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) |
|
||||||
|
| Thrift | [thrift](http://thrift.apache.org/) |
|
||||||
| TypeScript | [eslint](http://eslint.org/), [tslint](https://github.com/palantir/tslint), tsserver, typecheck |
|
| TypeScript | [eslint](http://eslint.org/), [tslint](https://github.com/palantir/tslint), tsserver, typecheck |
|
||||||
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
|
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
|
||||||
| Vim | [vint](https://github.com/Kuniwak/vint) |
|
| Vim | [vint](https://github.com/Kuniwak/vint) |
|
||||||
|
91
ale_linters/thrift/thrift.vim
Normal file
91
ale_linters/thrift/thrift.vim
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
" Author: Jon Parise <jon@indelible.org>
|
||||||
|
|
||||||
|
call ale#Set('thrift_thrift_executable', 'thrift')
|
||||||
|
call ale#Set('thrift_thrift_generators', ['cpp'])
|
||||||
|
call ale#Set('thrift_thrift_includes', [])
|
||||||
|
call ale#Set('thrift_thrift_options', '-strict')
|
||||||
|
|
||||||
|
function! ale_linters#thrift#thrift#GetExecutable(buffer) abort
|
||||||
|
return ale#Var(a:buffer, 'thrift_thrift_executable')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale_linters#thrift#thrift#GetCommand(buffer) abort
|
||||||
|
let l:generators = ale#Var(a:buffer, 'thrift_thrift_generators')
|
||||||
|
let l:includes = ale#Var(a:buffer, 'thrift_thrift_includes')
|
||||||
|
|
||||||
|
" The thrift compiler requires at least one generator. If none are set,
|
||||||
|
" fall back to our default value to avoid silently failing. We could also
|
||||||
|
" `throw` here, but that seems even less helpful.
|
||||||
|
if empty(l:generators)
|
||||||
|
let l:generators = ['cpp']
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:output_dir = tempname()
|
||||||
|
call mkdir(l:output_dir)
|
||||||
|
call ale#engine#ManageDirectory(a:buffer, l:output_dir)
|
||||||
|
|
||||||
|
return ale#Escape(ale_linters#thrift#thrift#GetExecutable(a:buffer))
|
||||||
|
\ . ' ' . join(map(copy(l:generators), "'--gen ' . v:val"))
|
||||||
|
\ . ' ' . join(map(copy(l:includes), "'-I ' . v:val"))
|
||||||
|
\ . ' ' . ale#Var(a:buffer, 'thrift_thrift_options')
|
||||||
|
\ . ' -out ' . ale#Escape(l:output_dir)
|
||||||
|
\ . ' %t'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale_linters#thrift#thrift#Handle(buffer, lines) abort
|
||||||
|
" Matches lines like the following:
|
||||||
|
"
|
||||||
|
" [SEVERITY:/path/filename.thrift:31] Message text
|
||||||
|
" [ERROR:/path/filename.thrift:31] (last token was ';')
|
||||||
|
let l:pattern = '\v^\[(\u+):(.*):(\d+)\] (.*)$'
|
||||||
|
|
||||||
|
let l:index = 0
|
||||||
|
let l:output = []
|
||||||
|
|
||||||
|
" Roll our own output-matching loop instead of using ale#util#GetMatches
|
||||||
|
" because we need to support error messages that span multiple lines.
|
||||||
|
while l:index < len(a:lines)
|
||||||
|
let l:line = a:lines[l:index]
|
||||||
|
|
||||||
|
let l:match = matchlist(l:line, l:pattern)
|
||||||
|
if empty(l:match)
|
||||||
|
let l:index += 1
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:severity = l:match[1]
|
||||||
|
if l:severity is# 'WARNING'
|
||||||
|
let l:type = 'W'
|
||||||
|
else
|
||||||
|
let l:type = 'E'
|
||||||
|
endif
|
||||||
|
|
||||||
|
" If our text looks like "(last token was ';')", the *next* line
|
||||||
|
" should contain a more descriptive error message.
|
||||||
|
let l:text = l:match[4]
|
||||||
|
if l:text =~# '\(last token was .*\)'
|
||||||
|
let l:index += 1
|
||||||
|
let l:text = get(a:lines, l:index, 'Unknown error ' . l:text)
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add(l:output, {
|
||||||
|
\ 'lnum': l:match[3] + 0,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': l:type,
|
||||||
|
\ 'text': l:text,
|
||||||
|
\})
|
||||||
|
|
||||||
|
let l:index += 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return l:output
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call ale#linter#Define('thrift', {
|
||||||
|
\ 'name': 'thrift',
|
||||||
|
\ 'executable': 'thrift',
|
||||||
|
\ 'output_stream': 'both',
|
||||||
|
\ 'executable_callback': 'ale_linters#thrift#thrift#GetExecutable',
|
||||||
|
\ 'command_callback': 'ale_linters#thrift#thrift#GetCommand',
|
||||||
|
\ 'callback': 'ale_linters#thrift#thrift#Handle',
|
||||||
|
\})
|
46
doc/ale-thrift.txt
Normal file
46
doc/ale-thrift.txt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
===============================================================================
|
||||||
|
ALE Thrift Integration *ale-thrift-options*
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
thrift *ale-thrift-thrift*
|
||||||
|
|
||||||
|
The `thrift` linter works by compiling the buffer's contents and reporting any
|
||||||
|
errors reported by the parser and the configured code generator(s).
|
||||||
|
|
||||||
|
g:ale_thrift_thrift_executable *g:ale_thrift_thrift_executable*
|
||||||
|
*b:ale_thrift_thrift_executable*
|
||||||
|
Type: |String|
|
||||||
|
Default: `'thrift'`
|
||||||
|
|
||||||
|
See |ale-integrations-local-executables|
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_thrift_thrift_generators *g:ale_thrift_thrift_generators*
|
||||||
|
*b:ale_thrift_thrift_generators*
|
||||||
|
Type: |List| of |String|s
|
||||||
|
Default: `['cpp']`
|
||||||
|
|
||||||
|
This list must contain one or more named code generators. Generator options
|
||||||
|
can be included as part of each string, e.g. `['py:dynamic']`.
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_thrift_thrift_includes *g:ale_thrift_thrift_includes*
|
||||||
|
*b:ale_thrift_thrift_includes*
|
||||||
|
Type: |List| of |String|s
|
||||||
|
Default: `[]`
|
||||||
|
|
||||||
|
This list contains paths that will be searched for thrift `include`
|
||||||
|
directives.
|
||||||
|
|
||||||
|
|
||||||
|
g:ale_thrift_thrift_options *g:ale_thrift_thrift_options*
|
||||||
|
*b:ale_thrift_thrift_options*
|
||||||
|
Type: |String|
|
||||||
|
Default: `'-strict'`
|
||||||
|
|
||||||
|
This variable can be changed to customize the additional command-line
|
||||||
|
arguments that are passed to the thrift compiler.
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
|
@ -127,6 +127,8 @@ CONTENTS *ale-contents*
|
|||||||
tex...................................|ale-tex-options|
|
tex...................................|ale-tex-options|
|
||||||
chktex..............................|ale-tex-chktex|
|
chktex..............................|ale-tex-chktex|
|
||||||
lacheck.............................|ale-tex-lacheck|
|
lacheck.............................|ale-tex-lacheck|
|
||||||
|
thrift................................|ale-thrift-options|
|
||||||
|
thrift..............................|ale-thrift-thrift|
|
||||||
typescript............................|ale-typescript-options|
|
typescript............................|ale-typescript-options|
|
||||||
eslint..............................|ale-typescript-eslint|
|
eslint..............................|ale-typescript-eslint|
|
||||||
tslint..............................|ale-typescript-tslint|
|
tslint..............................|ale-typescript-tslint|
|
||||||
@ -248,6 +250,7 @@ Notes:
|
|||||||
* Tcl: `nagelfar`!!
|
* Tcl: `nagelfar`!!
|
||||||
* Texinfo: `proselint`
|
* Texinfo: `proselint`
|
||||||
* Text^: `proselint`, `vale`
|
* Text^: `proselint`, `vale`
|
||||||
|
* Thrift: `thrift`
|
||||||
* TypeScript: `eslint`, `tslint`, `tsserver`, `typecheck`
|
* TypeScript: `eslint`, `tslint`, `tsserver`, `typecheck`
|
||||||
* Verilog: `iverilog`, `verilator`
|
* Verilog: `iverilog`, `verilator`
|
||||||
* Vim: `vint`
|
* Vim: `vint`
|
||||||
|
61
test/command_callback/test_thrift_command_callback.vader
Normal file
61
test/command_callback/test_thrift_command_callback.vader
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
Before:
|
||||||
|
Save g:ale_thrift_thrift_executable
|
||||||
|
Save g:ale_thrift_thrift_generators
|
||||||
|
Save g:ale_thrift_thrift_includes
|
||||||
|
Save g:ale_thrift_thrift_options
|
||||||
|
|
||||||
|
unlet! b:ale_thrift_thrift_executable
|
||||||
|
unlet! b:ale_thrift_thrift_generators
|
||||||
|
unlet! b:ale_thrift_thrift_includes
|
||||||
|
unlet! b:ale_thrift_thrift_options
|
||||||
|
|
||||||
|
function! GetCommand(buffer) abort
|
||||||
|
call ale#engine#InitBufferInfo(a:buffer)
|
||||||
|
let l:result = ale_linters#thrift#thrift#GetCommand(a:buffer)
|
||||||
|
call ale#engine#Cleanup(a:buffer)
|
||||||
|
return l:result
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
runtime ale_linters/thrift/thrift.vim
|
||||||
|
|
||||||
|
After:
|
||||||
|
Restore
|
||||||
|
delfunction GetCommand
|
||||||
|
unlet! b:ale_thrift_thrift_executable
|
||||||
|
unlet! b:ale_thrift_thrift_generators
|
||||||
|
unlet! b:ale_thrift_thrift_includes
|
||||||
|
unlet! b:ale_thrift_thrift_options
|
||||||
|
call ale#linter#Reset()
|
||||||
|
|
||||||
|
Execute(The executable should be configurable):
|
||||||
|
AssertEqual 'thrift', ale_linters#thrift#thrift#GetExecutable(bufnr(''))
|
||||||
|
|
||||||
|
let b:ale_thrift_thrift_executable = 'foobar'
|
||||||
|
AssertEqual 'foobar', ale_linters#thrift#thrift#GetExecutable(bufnr(''))
|
||||||
|
|
||||||
|
Execute(The executable should be used in the command):
|
||||||
|
Assert GetCommand(bufnr('%')) =~# "^'thrift'"
|
||||||
|
|
||||||
|
let b:ale_thrift_thrift_executable = 'foobar'
|
||||||
|
Assert GetCommand(bufnr('%')) =~# "^'foobar'"
|
||||||
|
|
||||||
|
Execute(The list of generators should be configurable):
|
||||||
|
Assert GetCommand(bufnr('%')) =~# '--gen cpp'
|
||||||
|
|
||||||
|
let b:ale_thrift_thrift_generators = ['java', 'py:dynamic']
|
||||||
|
Assert GetCommand(bufnr('%')) =~# '--gen java --gen py:dynamic'
|
||||||
|
|
||||||
|
let b:ale_thrift_thrift_generators = []
|
||||||
|
Assert GetCommand(bufnr('%')) =~# '--gen cpp'
|
||||||
|
|
||||||
|
Execute(The list of include paths should be configurable):
|
||||||
|
Assert GetCommand(bufnr('%')) !~# '-I'
|
||||||
|
|
||||||
|
let b:ale_thrift_thrift_includes = ['included/path']
|
||||||
|
Assert GetCommand(bufnr('%')) =~# '-I included/path'
|
||||||
|
|
||||||
|
Execute(The string of compiler options should be configurable):
|
||||||
|
Assert GetCommand(bufnr('%')) =~# '-strict'
|
||||||
|
|
||||||
|
let b:ale_thrift_thrift_options = '-strict --allow-64bit-consts'
|
||||||
|
Assert GetCommand(bufnr('%')) =~# '-strict --allow-64bit-consts'
|
63
test/handler/test_thrift_handler.vader
Normal file
63
test/handler/test_thrift_handler.vader
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
Before:
|
||||||
|
runtime ale_linters/thrift/thrift.vim
|
||||||
|
|
||||||
|
After:
|
||||||
|
call ale#linter#Reset()
|
||||||
|
|
||||||
|
Execute(The thrift handler should handle basic warnings and errors):
|
||||||
|
AssertEqual
|
||||||
|
\ [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 17,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ 'text': 'The "byte" type is a compatibility alias for "i8". Use i8" to emphasize the signedness of this type.',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 20,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': 'W',
|
||||||
|
\ 'text': 'Could not find include file include.thrift',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 83,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ 'text': 'Enum FOO is already defined!',
|
||||||
|
\ },
|
||||||
|
\ ],
|
||||||
|
\ ale_linters#thrift#thrift#Handle(1, [
|
||||||
|
\ '[WARNING:/path/filename.thrift:17] The "byte" type is a compatibility alias for "i8". Use i8" to emphasize the signedness of this type.',
|
||||||
|
\ '[WARNING:/path/filename.thrift:20] Could not find include file include.thrift',
|
||||||
|
\ '[FAILURE:/path/filename.thrift:83] Enum FOO is already defined!',
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
Execute(The thrift handler should handle multiline errors):
|
||||||
|
AssertEqual
|
||||||
|
\ [
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 75,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ 'text': 'This integer is too big: "11111111114213213453243"',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 76,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ 'text': 'Implicit field keys are deprecated and not allowed with -strict',
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'lnum': 77,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'type': 'E',
|
||||||
|
\ 'text': "Unknown error (last token was ';')",
|
||||||
|
\ },
|
||||||
|
\ ],
|
||||||
|
\ ale_linters#thrift#thrift#Handle(1, [
|
||||||
|
\ "[ERROR:/path/filename.thrift:75] (last token was '11111111114213213453243')",
|
||||||
|
\ 'This integer is too big: "11111111114213213453243"',
|
||||||
|
\ "[ERROR:/path/filename.thrift:76] (last token was ';')",
|
||||||
|
\ 'Implicit field keys are deprecated and not allowed with -strict',
|
||||||
|
\ "[ERROR:/path/filename.thrift:77] (last token was ';')",
|
||||||
|
\ ])
|
Loading…
x
Reference in New Issue
Block a user