summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ale_linters/solidity/solhint.vim31
-rw-r--r--autoload/ale/handlers/solhint.vim98
-rw-r--r--test/handler/test_solhint_handler.vader28
-rw-r--r--test/linter/test_solhint.vader28
-rw-r--r--test/test-files/solhint/Contract.sol0
-rw-r--r--test/test-files/solhint/node_modules/.bin/solhint0
-rw-r--r--test/test-files/solhint/node_modules/solhint/index.js0
-rw-r--r--test/test-files/solhint/package.json0
8 files changed, 159 insertions, 26 deletions
diff --git a/ale_linters/solidity/solhint.vim b/ale_linters/solidity/solhint.vim
index 8ea33e07..505bd5bb 100644
--- a/ale_linters/solidity/solhint.vim
+++ b/ale_linters/solidity/solhint.vim
@@ -1,29 +1,12 @@
-" Author: Franco Victorio - https://github.com/fvictorio
+" Authors: Franco Victorio - https://github.com/fvictorio, Henrique Barcelos
+" https://github.com/hbarcelos
" Description: Report errors in Solidity code with solhint
-function! ale_linters#solidity#solhint#Handle(buffer, lines) abort
- " Matches patterns like the following:
- " /path/to/file/file.sol: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)
- let l:pattern = '\v^[^:]+: line (\d+), col (\d+), (Error|Warning) - (.*) \((.*)\)$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- let l:isError = l:match[3] is? 'error'
- call add(l:output, {
- \ 'lnum': l:match[1] + 0,
- \ 'col': l:match[2] + 0,
- \ 'text': l:match[4],
- \ 'code': l:match[5],
- \ 'type': l:isError ? 'E' : 'W',
- \})
- endfor
-
- return l:output
-endfunction
-
call ale#linter#Define('solidity', {
\ 'name': 'solhint',
-\ 'executable': 'solhint',
-\ 'command': 'solhint --formatter compact %t',
-\ 'callback': 'ale_linters#solidity#solhint#Handle',
+\ 'output_stream': 'both',
+\ 'executable': function('ale#handlers#solhint#GetExecutable'),
+\ 'cwd': function('ale#handlers#solhint#GetCwd'),
+\ 'command': function('ale#handlers#solhint#GetCommand'),
+\ 'callback': 'ale#handlers#solhint#Handle',
\})
diff --git a/autoload/ale/handlers/solhint.vim b/autoload/ale/handlers/solhint.vim
new file mode 100644
index 00000000..61ab2a60
--- /dev/null
+++ b/autoload/ale/handlers/solhint.vim
@@ -0,0 +1,98 @@
+" Author: Henrique Barcelos <@hbarcelos>
+" Description: Functions for working with local solhint for checking *.sol files.
+
+let s:executables = [
+\ 'node_modules/.bin/solhint',
+\ 'node_modules/solhint/solhint.js',
+\ 'solhint',
+\]
+
+let s:sep = has('win32') ? '\' : '/'
+
+call ale#Set('solidity_solhint_options', '')
+call ale#Set('solidity_solhint_executable', 'solhint')
+call ale#Set('solidity_solhint_use_global', get(g:, 'ale_use_global_executables', 0))
+
+function! ale#handlers#solhint#Handle(buffer, lines) abort
+ " Matches patterns like the following:
+ " /path/to/file/file.sol: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)
+ let l:output = []
+
+ let l:lint_pattern = '\v^[^:]+: line (\d+), col (\d+), (Error|Warning) - (.*) \((.*)\)$'
+
+ for l:match in ale#util#GetMatches(a:lines, l:lint_pattern)
+ let l:isError = l:match[3] is? 'error'
+ call add(l:output, {
+ \ 'lnum': l:match[1] + 0,
+ \ 'col': l:match[2] + 0,
+ \ 'text': l:match[4],
+ \ 'code': l:match[5],
+ \ 'type': l:isError ? 'E' : 'W',
+ \})
+ endfor
+
+ let l:syntax_pattern = '\v^[^:]+: line (\d+), col (\d+), (Error|Warning) - (Parse error): (.*)$'
+
+ for l:match in ale#util#GetMatches(a:lines, l:syntax_pattern)
+ let l:isError = l:match[3] is? 'error'
+ call add(l:output, {
+ \ 'lnum': l:match[1] + 0,
+ \ 'col': l:match[2] + 0,
+ \ 'text': l:match[5],
+ \ 'code': l:match[4],
+ \ 'type': l:isError ? 'E' : 'W',
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+function! ale#handlers#solhint#FindConfig(buffer) abort
+ for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
+ for l:basename in [
+ \ '.solhintrc.js',
+ \ '.solhintrc.json',
+ \ '.solhintrc',
+ \]
+ let l:config = ale#path#Simplify(join([l:path, l:basename], s:sep))
+
+ if filereadable(l:config)
+ return l:config
+ endif
+ endfor
+ endfor
+
+ return ale#path#FindNearestFile(a:buffer, 'package.json')
+endfunction
+
+function! ale#handlers#solhint#GetExecutable(buffer) abort
+ return ale#node#FindExecutable(a:buffer, 'solidity_solhint', s:executables)
+endfunction
+
+" Given a buffer, return an appropriate working directory for solhint.
+function! ale#handlers#solhint#GetCwd(buffer) abort
+ " If solhint is installed in a directory which contains the buffer, assume
+ " it is the solhint project root. Otherwise, use nearest node_modules.
+ " Note: If node_modules not present yet, can't load local deps anyway.
+ let l:executable = ale#node#FindNearestExecutable(a:buffer, s:executables)
+
+ if !empty(l:executable)
+ let l:nmi = strridx(l:executable, 'node_modules')
+ let l:project_dir = l:executable[0:l:nmi - 2]
+ else
+ let l:modules_dir = ale#path#FindNearestDirectory(a:buffer, 'node_modules')
+ let l:project_dir = !empty(l:modules_dir) ? fnamemodify(l:modules_dir, ':h:h') : ''
+ endif
+
+ return !empty(l:project_dir) ? l:project_dir : ''
+endfunction
+
+function! ale#handlers#solhint#GetCommand(buffer) abort
+ let l:executable = ale#handlers#solhint#GetExecutable(a:buffer)
+
+ let l:options = ale#Var(a:buffer, 'solidity_solhint_options')
+
+ return ale#node#Executable(a:buffer, l:executable)
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' --formatter compact %s'
+endfunction
diff --git a/test/handler/test_solhint_handler.vader b/test/handler/test_solhint_handler.vader
index a3ed5d57..f8fffb60 100644
--- a/test/handler/test_solhint_handler.vader
+++ b/test/handler/test_solhint_handler.vader
@@ -4,7 +4,7 @@ Before:
After:
call ale#linter#Reset()
-Execute(The vint handler should parse error messages correctly):
+Execute(The solhint handler should parse linter error messages correctly):
AssertEqual
\ [
\ {
@@ -50,7 +50,7 @@ Execute(The vint handler should parse error messages correctly):
\ 'type': 'E',
\ },
\ ],
- \ ale_linters#solidity#solhint#Handle(bufnr(''), [
+ \ ale#handlers#solhint#Handle(bufnr(''), [
\ 'contracts/Bounty.sol: line 1, col 17, Warning - Compiler version must be fixed (compiler-fixed)',
\ 'contracts/Bounty.sol: line 4, col 8, Error - Use double quotes for string literals (quotes)',
\ 'contracts/Bounty.sol: line 5, col 8, Error - Use double quotes for string literals (quotes)',
@@ -58,3 +58,27 @@ Execute(The vint handler should parse error messages correctly):
\ 'contracts/Bounty.sol: line 14, col 3, Error - Expected indentation of 4 spaces but found 2 (indent)',
\ 'contracts/Bounty.sol: line 47, col 3, Error - Function order is incorrect, public function can not go after internal function. (func-order)',
\ ])
+
+
+Execute(The solhint handler should parse syntax error messages correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 30,
+ \ 'col': 4,
+ \ 'text': "missing ';' at 'uint248'",
+ \ 'code': 'Parse error',
+ \ 'type': 'E',
+ \ },
+ \ {
+ \ 'lnum': 203,
+ \ 'col': 4,
+ \ 'text': "no viable alternative at input '_loserStakeMultiplier}'",
+ \ 'code': 'Parse error',
+ \ 'type': 'E',
+ \ },
+ \ ],
+ \ ale#handlers#solhint#Handle(bufnr(''), [
+ \ "contracts/Bounty.sol: line 30, col 4, Error - Parse error: missing ';' at 'uint248'",
+ \ "contracts/Bounty.sol: line 203, col 4, Error - Parse error: no viable alternative at input '_loserStakeMultiplier}'",
+ \ ])
diff --git a/test/linter/test_solhint.vader b/test/linter/test_solhint.vader
new file mode 100644
index 00000000..fc5afa9b
--- /dev/null
+++ b/test/linter/test_solhint.vader
@@ -0,0 +1,28 @@
+Before:
+ call ale#assert#SetUpLinterTest('solidity', 'solhint')
+ runtime autoload/ale/handlers/solhint.vim
+
+ let b:args = ' --formatter compact %s'
+
+After:
+ unlet! b:args
+ unlet! b:executable
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinterCwd ''
+ AssertLinter 'solhint', ale#Escape('solhint') . b:args
+
+Execute(The options should be configurable):
+ let g:ale_solidity_solhint_options = '--foobar'
+
+ AssertLinter 'solhint', ale#Escape('solhint') . ' --foobar' . b:args
+
+
+Execute(solhint should be run from a containing project with solhint executable):
+ call ale#test#SetFilename('../test-files/solhint/Contract.sol')
+
+ let b:executable = ale#path#Simplify(g:dir . '/../test-files/solhint/node_modules/.bin/solhint')
+
+ AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/solhint')
+ AssertLinter b:executable, ale#Escape(b:executable) . b:args
diff --git a/test/test-files/solhint/Contract.sol b/test/test-files/solhint/Contract.sol
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/solhint/Contract.sol
diff --git a/test/test-files/solhint/node_modules/.bin/solhint b/test/test-files/solhint/node_modules/.bin/solhint
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/solhint/node_modules/.bin/solhint
diff --git a/test/test-files/solhint/node_modules/solhint/index.js b/test/test-files/solhint/node_modules/solhint/index.js
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/solhint/node_modules/solhint/index.js
diff --git a/test/test-files/solhint/package.json b/test/test-files/solhint/package.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/solhint/package.json