mirror of
https://github.com/dense-analysis/ale
synced 2024-12-25 15:42:26 +00:00
Fix #4499 - Fix solhint >= 3.4.0
Fix solhint for versions >= 3.4.0, while still supporting older versions. The solhint linter code has been moved out of the `handlers` directory as it does not need to be shared between different filetypes. Code has been simplified. Co-authored-by: Henrique Barcelos <16565602+hbarcelos@users.noreply.github.com>
This commit is contained in:
parent
bd9fc580a1
commit
53b01d6a54
@ -1,12 +1,83 @@
|
||||
" Authors: Franco Victorio - https://github.com/fvictorio, Henrique Barcelos
|
||||
" https://github.com/hbarcelos
|
||||
" Authors: Franco Victorio <@fvictorio>, Henrique Barcelos <@hbarcelos>
|
||||
" Description: Report errors in Solidity code with solhint
|
||||
|
||||
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_linters#solidity#solhint#Handle(buffer, lines) abort
|
||||
let l:output = []
|
||||
|
||||
" Matches lines like the following:
|
||||
" contracts/Bounty.sol:14:3: Expected indentation of 4 spaces but found 2 [Error/indent]
|
||||
let l:lint_pattern = '\v^[^:]+:(\d+):(\d+): %(Parse error: )@<!\ze(.*)\s+\[(Error|Warning)\/([^\]]+)\]$'
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:lint_pattern)
|
||||
let l:is_error = l:match[4] is? 'error'
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'code': l:match[5],
|
||||
\ 'type': l:is_error ? 'E' : 'W',
|
||||
\})
|
||||
endfor
|
||||
|
||||
" Matches lines like the following:
|
||||
" contracts/Bounty.sol:203:4: Parse error: no viable alternative at input '_loserStakeMultiplier}' [Error]
|
||||
let l:syntax_pattern = '\v^[^:]+:(\d+):(\d+): Parse error: (.*)\s+\[Error\]$'
|
||||
|
||||
for l:match in ale#util#GetMatches(a:lines, l:syntax_pattern)
|
||||
call add(l:output, {
|
||||
\ 'lnum': l:match[1] + 0,
|
||||
\ 'col': l:match[2] + 0,
|
||||
\ 'text': l:match[3],
|
||||
\ 'code': 'Parse error',
|
||||
\ 'type': 'E',
|
||||
\})
|
||||
endfor
|
||||
|
||||
return l:output
|
||||
endfunction
|
||||
|
||||
let s:executables = [
|
||||
\ 'node_modules/.bin/solhint',
|
||||
\ 'node_modules/solhint/solhint.js',
|
||||
\ 'solhint',
|
||||
\]
|
||||
let s:sep = has('win32') ? '\' : '/'
|
||||
|
||||
" Given a buffer, return an appropriate working directory for solhint.
|
||||
function! ale_linters#solidity#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#path#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_linters#solidity#solhint#GetExecutable(buffer) abort
|
||||
return ale#path#FindExecutable(a:buffer, 'solidity_solhint', s:executables)
|
||||
endfunction
|
||||
|
||||
call ale#linter#Define('solidity', {
|
||||
\ 'name': 'solhint',
|
||||
\ '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',
|
||||
\ 'executable': function('ale_linters#solidity#solhint#GetExecutable'),
|
||||
\ 'cwd': function('ale_linters#solidity#solhint#GetCwd'),
|
||||
\ 'command': {b ->
|
||||
\ ale#node#Executable(b, ale_linters#solidity#solhint#GetExecutable(b))
|
||||
\ . ale#Pad(ale#Var(b, 'solidity_solhint_options'))
|
||||
\ . ' --formatter unix %s'
|
||||
\ },
|
||||
\ 'callback': 'ale_linters#solidity#solhint#Handle',
|
||||
\})
|
||||
|
@ -1,98 +0,0 @@
|
||||
" 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#path#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#path#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
|
@ -50,16 +50,15 @@ Execute(The solhint handler should parse linter error messages correctly):
|
||||
\ 'type': 'E',
|
||||
\ },
|
||||
\ ],
|
||||
\ 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)',
|
||||
\ 'contracts/Bounty.sol: line 13, col 3, Error - Expected indentation of 4 spaces but found 2 (indent)',
|
||||
\ '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)',
|
||||
\ ale_linters#solidity#solhint#Handle(bufnr(''), [
|
||||
\ 'contracts/Bounty.sol:1:17: Compiler version must be fixed [Warning/compiler-fixed]',
|
||||
\ 'contracts/Bounty.sol:4:8: Use double quotes for string literals [Error/quotes]',
|
||||
\ 'contracts/Bounty.sol:5:8: Use double quotes for string literals [Error/quotes]',
|
||||
\ 'contracts/Bounty.sol:13:3: Expected indentation of 4 spaces but found 2 [Error/indent]',
|
||||
\ 'contracts/Bounty.sol:14:3: Expected indentation of 4 spaces but found 2 [Error/indent]',
|
||||
\ 'contracts/Bounty.sol:47:3: Function order is incorrect, public function can not go after internal function. [Error/func-order]',
|
||||
\ ])
|
||||
|
||||
|
||||
Execute(The solhint handler should parse syntax error messages correctly):
|
||||
AssertEqual
|
||||
\ [
|
||||
@ -78,7 +77,7 @@ Execute(The solhint handler should parse syntax error messages correctly):
|
||||
\ '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}'",
|
||||
\ ale_linters#solidity#solhint#Handle(bufnr(''), [
|
||||
\ "contracts/Bounty.sol:30:4: Parse error: missing ';' at 'uint248' [Error]",
|
||||
\ "contracts/Bounty.sol:203:4: Parse error: no viable alternative at input '_loserStakeMultiplier}' [Error]",
|
||||
\ ])
|
||||
|
@ -1,8 +1,7 @@
|
||||
Before:
|
||||
call ale#assert#SetUpLinterTest('solidity', 'solhint')
|
||||
runtime autoload/ale/handlers/solhint.vim
|
||||
|
||||
let b:args = ' --formatter compact %s'
|
||||
let b:args = ' --formatter unix %s'
|
||||
|
||||
After:
|
||||
unlet! b:args
|
||||
@ -18,7 +17,6 @@ Execute(The options should be configurable):
|
||||
|
||||
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')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user