Add llc integration for LLVM IR (#979)

Check LLVM IR with llc
This commit is contained in:
Linda_pp 2017-10-10 18:13:09 +09:00 committed by w0rp
parent a809c4fa3a
commit 70177480ba
6 changed files with 157 additions and 4 deletions

View File

@ -103,8 +103,9 @@ formatting.
| Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) |
| JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [prettier](https://github.com/prettier/prettier), prettier-eslint >= 4.2.0, prettier-standard, [standard](http://standardjs.com/), [xo](https://github.com/sindresorhus/xo)
| JSON | [jsonlint](http://zaa.ch/jsonlint/), [prettier](https://github.com/prettier/prettier) |
| Kotlin | [kotlinc](https://kotlinlang.org) !!, [ktlint](https://ktlint.github.io) !! see `:help ale-integration-kotlin` for configuration instructions
| Kotlin | [kotlinc](https://kotlinlang.org) !!, [ktlint](https://ktlint.github.io) !! see `:help ale-integration-kotlin` for configuration instructions |
| LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck), [proselint](http://proselint.com/) |
| LLVM | [llc](https://llvm.org/docs/CommandGuide/llc.html) |
| Lua | [luacheck](https://github.com/mpeterv/luacheck) |
| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) |
| MATLAB | [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) |
@ -113,7 +114,7 @@ formatting.
| nroff | [proselint](http://proselint.com/)|
| Objective-C | [clang](http://clang.llvm.org/) |
| Objective-C++ | [clang](http://clang.llvm.org/) |
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions |
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
| PHP | [hack](http://hacklang.org/), [langserver](https://github.com/felixfbecker/php-language-server), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer) |
| Pod | [proselint](http://proselint.com/)|
@ -121,7 +122,7 @@ formatting.
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
| Python | [autopep8](https://github.com/hhatto/autopep8), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pylint](https://www.pylint.org/) !!, [yapf](https://github.com/google/yapf) |
| R | [lintr](https://github.com/jimhester/lintr) |
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions |
| reStructuredText | [proselint](http://proselint.com/) |
| RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) |
| Ruby | [brakeman](http://brakemanscanner.org/) !!, [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) !!, [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) |
@ -129,7 +130,7 @@ formatting.
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
| SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint), [prettier](https://github.com/prettier/prettier) |
| Scala | [scalac](http://scala-lang.org), [scalastyle](http://www.scalastyle.org) |
| Slim | [slim-lint](https://github.com/sds/slim-lint)
| Slim | [slim-lint](https://github.com/sds/slim-lint) |
| SML | [smlnj](http://www.smlnj.org/) |
| Solidity | [solium](https://github.com/duaraghav8/Solium) |
| Stylus | [stylelint](https://github.com/stylelint/stylelint) |

35
ale_linters/llvm/llc.vim Normal file
View File

@ -0,0 +1,35 @@
" Author: rhysd <https://rhysd.github.io>
" Description: Support for checking LLVM IR with llc
call ale#Set('llvm_llc_executable', 'llc')
function! ale_linters#llvm#llc#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'llvm_llc_executable')
endfunction
function! ale_linters#llvm#llc#GetCommand(buffer) abort
return ale#Escape(ale_linters#llvm#llc#GetExecutable(a:buffer))
\ . ' -filetype=null -o='
\ . ale#Escape(g:ale#util#nul_file)
endfunction
function! ale_linters#llvm#llc#HandleErrors(buffer, lines) abort
" Handle '{path}: {file}:{line}:{col}: error: {message}' format
let l:pattern = '\v^[a-zA-Z]?:?[^:]+: [^:]+:(\d+):(\d+): (.+)$'
let l:matches = ale#util#GetMatches(a:lines, l:pattern)
return map(l:matches, "{
\ 'lnum': str2nr(v:val[1]),
\ 'col': str2nr(v:val[2]),
\ 'text': v:val[3],
\ 'type': 'E',
\}")
endfunction
call ale#linter#Define('llvm', {
\ 'name': 'llc',
\ 'executable_callback': 'ale_linters#llvm#llc#GetExecutable',
\ 'output_stream': 'stderr',
\ 'command_callback': 'ale_linters#llvm#llc#GetCommand',
\ 'callback': 'ale_linters#llvm#llc#HandleErrors',
\})

19
doc/ale-llvm.txt Normal file
View File

@ -0,0 +1,19 @@
===============================================================================
ALE LLVM Integration *ale-llvm-options*
===============================================================================
llc *ale-llvm-llc*
g:ale_llvm_llc_executable *g:ale_llvm_llc_executable*
*b:ale_llvm_llc_executable*
Type: |String|
Default: "llc"
The command to use for checking. This variable is useful when llc command
has suffix like "llc-5.0".
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -95,6 +95,8 @@ CONTENTS *ale-contents*
kotlin................................|ale-kotlin-options|
kotlinc.............................|ale-kotlin-kotlinc|
ktlint..............................|ale-kotlin-ktlint|
llvm..................................|ale-llvm-options|
llc.................................|ale-llvm-llc|
lua...................................|ale-lua-options|
luacheck............................|ale-lua-luacheck|
objc..................................|ale-objc-options|
@ -255,6 +257,7 @@ Notes:
* JSON: `jsonlint`, `prettier`
* Kotlin: `kotlinc`, `ktlint`
* LaTeX (tex): `chktex`, `lacheck`, `proselint`
* LLVM: `llc`
* Lua: `luacheck`
* Markdown: `mdl`, `proselint`, `vale`
* MATLAB: `mlint`

View File

@ -0,0 +1,39 @@
Before:
Save g:ale_llvm_llc_executable
unlet! g:ale_llvm_llc_executable
unlet! b:ale_llvm_llc_executable
runtime ale_linters/llvm/llc.vim
function! AssertHasPrefix(str, prefix) abort
let msg = printf("'%s' is expected to be prefixed with '%s'", a:str, a:prefix)
AssertEqual stridx(a:str, a:prefix), 0, msg
endfunction
After:
unlet! g:ale_llvm_llc_executable
unlet! b:ale_llvm_llc_executable
delfunction AssertHasPrefix
Restore
Execute(llc command is customizable):
let cmd = ale_linters#llvm#llc#GetCommand(bufnr(''))
call AssertHasPrefix(cmd, ale#Escape('llc'))
let g:ale_llvm_llc_executable = 'llc-5.0'
let cmd = ale_linters#llvm#llc#GetCommand(bufnr(''))
call AssertHasPrefix(cmd, ale#Escape('llc-5.0'))
let b:ale_llvm_llc_executable = 'llc-4.0'
let cmd = ale_linters#llvm#llc#GetCommand(bufnr(''))
call AssertHasPrefix(cmd, ale#Escape('llc-4.0'))
Execute(GetCommand() escapes the returned path):
let b:ale_llvm_llc_executable = '/path/space contained/llc'
let cmd = ale_linters#llvm#llc#GetCommand(bufnr(''))
call AssertHasPrefix(cmd, ale#Escape('/path/space contained/llc'))
Execute(GetExecutable() does not escape the returned path):
let b:ale_llvm_llc_executable = '/path/space contained/llc'
AssertEqual ale_linters#llvm#llc#GetExecutable(bufnr('')), '/path/space contained/llc'

View File

@ -0,0 +1,56 @@
Before:
runtime! ale_linters/llvm/llc.vim
Execute(llc handler should parse errors output for STDIN):
AssertEqual
\ [
\ {
\ 'lnum': 10,
\ 'col': 7,
\ 'text': "error: value doesn't match function result type 'i32'",
\ 'type': 'E',
\ },
\ {
\ 'lnum': 10,
\ 'col': 13,
\ 'text': "error: use of undefined value '@foo'",
\ 'type': 'E',
\ },
\ ],
\ ale_linters#llvm#llc#HandleErrors(bufnr(''), [
\ "llc: <stdin>:10:7: error: value doesn't match function result type 'i32'",
\ 'ret i64 0',
\ ' ^',
\ '',
\ "llc: <stdin>:10:13: error: use of undefined value '@foo'",
\ 'call void @foo(i64 %0)',
\ ' ^',
\ ])
Execute(llc handler should parse errors output for some file):
call ale#test#SetFilename('test.ll')
AssertEqual
\ [
\ {
\ 'lnum': 10,
\ 'col': 7,
\ 'text': "error: value doesn't match function result type 'i32'",
\ 'type': 'E',
\ },
\ {
\ 'lnum': 10,
\ 'col': 13,
\ 'text': "error: use of undefined value '@foo'",
\ 'type': 'E',
\ },
\ ],
\ ale_linters#llvm#llc#HandleErrors(bufnr(''), [
\ "llc: /path/to/test.ll:10:7: error: value doesn't match function result type 'i32'",
\ 'ret i64 0',
\ ' ^',
\ '',
\ "llc: /path/to/test.ll:10:13: error: use of undefined value '@foo'",
\ 'call void @foo(i64 %0)',
\ ' ^',
\ ])