summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--ale_linters/php/phpstan.vim40
-rw-r--r--doc/ale-php.txt19
-rw-r--r--doc/ale.txt3
-rw-r--r--test/test_phpstan_executable_detection.vader113
5 files changed, 175 insertions, 2 deletions
diff --git a/README.md b/README.md
index 38ad43e3..e94d70a6 100644
--- a/README.md
+++ b/README.md
@@ -98,7 +98,7 @@ name. That seems to be the fairest way to arrange this table.
| Objective-C++ | [clang](http://clang.llvm.org/) |
| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-ocaml-merlin` for configuration instructions
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) |
-| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org) |
+| PHP | [hack](http://hacklang.org/), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan) |
| Pod | [proselint](http://proselint.com/)|
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
diff --git a/ale_linters/php/phpstan.vim b/ale_linters/php/phpstan.vim
new file mode 100644
index 00000000..69173ef4
--- /dev/null
+++ b/ale_linters/php/phpstan.vim
@@ -0,0 +1,40 @@
+" Author: medains <https://github.com/medains>, ardis <https://github.com/ardisdreelath>
+" Description: phpstan for PHP files
+
+" Set to change the ruleset
+let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpstan')
+let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '4')
+
+function! ale_linters#php#phpstan#GetCommand(buffer) abort
+ return ale#Var(a:buffer, 'php_phpstan_executable')
+ \ . ' analyze -l'
+ \ . ale#Var(a:buffer, 'php_phpstan_level')
+ \ . ' --errorFormat raw'
+ \ . ' %s'
+endfunction
+
+function! ale_linters#php#phpstan#Handle(buffer, lines) abort
+ " Matches against lines like the following:
+ "
+ " filename.php:15:message
+ " C:\folder\filename.php:15:message
+ let l:pattern = '^\([a-zA-Z]:\)\?[^:]\+:\(\d\+\):\(.*\)$'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'lnum': l:match[2] + 0,
+ \ 'text': l:match[3],
+ \ 'type': 'W',
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('php', {
+\ 'name': 'phpstan',
+\ 'executable': 'phpstan',
+\ 'command_callback': 'ale_linters#php#phpstan#GetCommand',
+\ 'callback': 'ale_linters#php#phpstan#Handle',
+\})
diff --git a/doc/ale-php.txt b/doc/ale-php.txt
index 51902ca1..4109673a 100644
--- a/doc/ale-php.txt
+++ b/doc/ale-php.txt
@@ -43,5 +43,24 @@ g:ale_php_phpmd_ruleset *g:ale_php_phpmd_ruleset*
the available phpmd rulesets
+------------------------------------------------------------------------------
+phpstan *ale-php-stan*
+
+g:ale_php_phpstan_executable *g:ale_php_phpstan_executable*
+ *b:ale_php_phpstan_executable*
+ Type: |String|
+ Default: `'phpstan'`
+
+ This variable sets executable used for phpstan.
+
+
+g:ale_php_phpstan_level *g:ale_php_phpstan_level*
+ *b:ale_php_phpstan_level*
+ Type: |Number|
+ Default: `4`
+
+ This variable controls the rule levels. 0 is the loosest and 4 is the
+ strictest.
+
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale.txt b/doc/ale.txt
index 642d3883..883525f9 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -74,6 +74,7 @@ CONTENTS *ale-contents*
php...................................|ale-php-options|
phpcs...............................|ale-php-phpcs|
phpmd...............................|ale-php-phpmd|
+ phpstan.............................|ale-php-phpstan|
pug...................................|ale-pug-options|
puglint.............................|ale-pug-puglint|
python................................|ale-python-options|
@@ -195,7 +196,7 @@ The following languages and tools are supported.
* Objective-C++: 'clang'
* OCaml: 'merlin' (see |ale-linter-integration-ocaml-merlin|)
* Perl: 'perl' (-c flag), 'perlcritic'
-* PHP: 'hack', 'php' (-l flag), 'phpcs', 'phpmd'
+* PHP: 'hack', 'php' (-l flag), 'phpcs', 'phpmd', 'phpstan'
* Pod: 'proselint'
* Pug: 'pug-lint'
* Puppet: 'puppet', 'puppet-lint'
diff --git a/test/test_phpstan_executable_detection.vader b/test/test_phpstan_executable_detection.vader
new file mode 100644
index 00000000..24ba8cd8
--- /dev/null
+++ b/test/test_phpstan_executable_detection.vader
@@ -0,0 +1,113 @@
+Before:
+ Save g:ale_php_phpstan_executable
+ Save g:ale_php_phpstan_level
+
+ let g:ale_php_phpstan_executable = 'phpstan_test'
+
+ call ale#test#SetDirectory('/testplugin/test')
+
+ runtime ale_linters/php/phpstan.vim
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+Execute(project with level set to 3):
+ call ale#test#SetFilename('phpstan-test-files/foo/test.php')
+ let g:ale_php_phpstan_level = 3
+
+ AssertEqual
+ \ 'phpstan_test analyze -l3 --errorFormat raw %s',
+ \ ale_linters#php#phpstan#GetCommand(bufnr(''))
+
+Execute(project with default level):
+ call ale#test#SetFilename('phpstan-test-files/foo/test.php')
+
+ AssertEqual
+ \ 'phpstan_test analyze -l4 --errorFormat raw %s',
+ \ ale_linters#php#phpstan#GetCommand(bufnr(''))
+
+Execute(parse output without errors):
+ call ale#test#SetFilename('phpstan-test-files/foo/test.php')
+
+ AssertEqual
+ \ [],
+ \ ale_linters#php#phpstan#Handle(bufnr(''), [" 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%"])
+
+Execute(parse output with one error):
+ call ale#test#SetFilename('phpstan-test-files/foo/test.php')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 9,
+ \ 'text': 'Access to an undefined property Test::$var.',
+ \ 'type': 'W'
+ \ }
+ \ ],
+ \ ale_linters#php#phpstan#Handle(bufnr(''), [
+ \ ' 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%',
+ \ 'phpstan-test-files/foo/test.php:9:Access to an undefined property Test::$var.',
+ \])
+
+Execute(parse output with three errors):
+ call ale#test#SetFilename('phpstan-test-files/foo/test.php')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 9,
+ \ 'text': 'Call to method format() on an unknown class DateTimeImutable.',
+ \ 'type': 'W'
+ \ },
+ \ {
+ \ 'lnum': 16,
+ \ 'text': 'Sample message.',
+ \ 'type': 'W'
+ \ },
+ \ {
+ \ 'lnum': 192,
+ \ 'text': 'Invalid command testCommand.',
+ \ 'type': 'W'
+ \ }
+ \ ],
+ \ ale_linters#php#phpstan#Handle(bufnr(''), [
+ \ ' 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%',
+ \ 'phpstan-test-files/foo/test.php:9:Call to method format() on an unknown class DateTimeImutable.',
+ \ 'phpstan-test-files/foo/test.php:16:Sample message.',
+ \ 'phpstan-test-files/foo/test.php:192:Invalid command testCommand.',
+ \])
+
+Execute(parse output for windows filesystem):
+ call ale#test#SetFilename('phpstan-test-files/foo/test.php')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 9,
+ \ 'text': 'Access to an undefined property Test::$var.',
+ \ 'type': 'W'
+ \ }
+ \ ],
+ \ ale_linters#php#phpstan#Handle(bufnr(''), [
+ \ ' 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%',
+ \ 'D:\phpstan-test-files\foo\test.php:9:Access to an undefined property Test::$var.',
+ \])
+
+Execute(parse output for not php file):
+ call ale#test#SetFilename('phpstan-test-files/test.inc')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 9,
+ \ 'text': 'Access to an undefined property Test::$var.',
+ \ 'type': 'W'
+ \ }
+ \ ],
+ \ ale_linters#php#phpstan#Handle(bufnr(''), [
+ \ ' 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%',
+ \ '/phpstan-test-files/foo/test.inc:9:Access to an undefined property Test::$var.',
+ \])