mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 02:34:59 -07:00
vim-patch:65311c6: runtime(compiler): include spotbugs Java linter
closes: vim/vim#16001
65311c6f47
Co-authored-by: Konfekt <Konfekt@users.noreply.github.com>
Co-authored-by: Aliaksei Budavei <0x000c70@gmail.com>
This commit is contained in:
parent
146b8300a1
commit
8d7d225caa
250
runtime/autoload/spotbugs.vim
Normal file
250
runtime/autoload/spotbugs.vim
Normal file
@ -0,0 +1,250 @@
|
||||
" Default pre- and post-compiler actions for SpotBugs
|
||||
" Maintainers: @konfekt and @zzzyxwvut
|
||||
" Last Change: 2024 Nov 27
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
if v:version > 900
|
||||
|
||||
function! spotbugs#DeleteClassFiles() abort
|
||||
if !exists('b:spotbugs_class_files')
|
||||
return
|
||||
endif
|
||||
|
||||
for pathname in b:spotbugs_class_files
|
||||
let classname = pathname =~# "^'.\\+\\.class'$"
|
||||
\ ? eval(pathname)
|
||||
\ : pathname
|
||||
|
||||
if classname =~# '\.class$' && filereadable(classname)
|
||||
" Since v9.0.0795.
|
||||
let octad = readblob(classname, 0, 8)
|
||||
|
||||
" Test the magic number and the major version number (45 for v1.0).
|
||||
" Since v9.0.2027.
|
||||
if len(octad) == 8 && octad[0 : 3] == 0zcafe.babe &&
|
||||
\ or((octad[6] << 8), octad[7]) >= 45
|
||||
echomsg printf('Deleting %s: %d', classname, delete(classname))
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
let b:spotbugs_class_files = []
|
||||
endfunction
|
||||
|
||||
else
|
||||
|
||||
function! s:DeleteClassFilesWithNewLineCodes(classname) abort
|
||||
" The distribution of "0a"s in class file versions 2560 and 2570:
|
||||
"
|
||||
" 0zca.fe.ba.be.00.00.0a.00 0zca.fe.ba.be.00.00.0a.0a
|
||||
" 0zca.fe.ba.be.00.0a.0a.00 0zca.fe.ba.be.00.0a.0a.0a
|
||||
" 0zca.fe.ba.be.0a.00.0a.00 0zca.fe.ba.be.0a.00.0a.0a
|
||||
" 0zca.fe.ba.be.0a.0a.0a.00 0zca.fe.ba.be.0a.0a.0a.0a
|
||||
let numbers = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let offset = 0
|
||||
let lines = readfile(a:classname, 'b', 4)
|
||||
|
||||
" Track NL byte counts to handle files of less than 8 bytes.
|
||||
let nl_cnt = len(lines)
|
||||
" Track non-NL byte counts for "0zca.fe.ba.be.0a.0a.0a.0a".
|
||||
let non_nl_cnt = 0
|
||||
|
||||
for line in lines
|
||||
for idx in range(strlen(line))
|
||||
" Remap NLs to Nuls.
|
||||
let numbers[offset] = (line[idx] == "\n") ? 0 : char2nr(line[idx]) % 256
|
||||
let non_nl_cnt += 1
|
||||
let offset += 1
|
||||
|
||||
if offset > 7
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
let nl_cnt -= 1
|
||||
|
||||
if offset > 7 || (nl_cnt < 1 && non_nl_cnt > 4)
|
||||
break
|
||||
endif
|
||||
|
||||
" Reclaim NLs.
|
||||
let numbers[offset] = 10
|
||||
let offset += 1
|
||||
|
||||
if offset > 7
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Test the magic number and the major version number (45 for v1.0).
|
||||
if offset > 7 && numbers[0] == 0xca && numbers[1] == 0xfe &&
|
||||
\ numbers[2] == 0xba && numbers[3] == 0xbe &&
|
||||
\ (numbers[6] * 256 + numbers[7]) >= 45
|
||||
echomsg printf('Deleting %s: %d', a:classname, delete(a:classname))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DeleteClassFiles() abort
|
||||
if !exists('b:spotbugs_class_files')
|
||||
return
|
||||
endif
|
||||
|
||||
let encoding = &encoding
|
||||
|
||||
try
|
||||
set encoding=latin1
|
||||
|
||||
for pathname in b:spotbugs_class_files
|
||||
let classname = pathname =~# "^'.\\+\\.class'$"
|
||||
\ ? eval(pathname)
|
||||
\ : pathname
|
||||
|
||||
if classname =~# '\.class$' && filereadable(classname)
|
||||
let line = get(readfile(classname, 'b', 1), 0, '')
|
||||
let length = strlen(line)
|
||||
|
||||
" Test the magic number and the major version number (45 for v1.0).
|
||||
if length > 3 && line[0 : 3] == "\xca\xfe\xba\xbe"
|
||||
if length > 7 && ((line[6] == "\n" ? 0 : char2nr(line[6]) % 256) * 256 +
|
||||
\ (line[7] == "\n" ? 0 : char2nr(line[7]) % 256)) >= 45
|
||||
echomsg printf('Deleting %s: %d', classname, delete(classname))
|
||||
else
|
||||
call s:DeleteClassFilesWithNewLineCodes(classname)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
finally
|
||||
let &encoding = encoding
|
||||
endtry
|
||||
|
||||
let b:spotbugs_class_files = []
|
||||
endfunction
|
||||
|
||||
endif
|
||||
|
||||
function! spotbugs#DefaultPostCompilerAction() abort
|
||||
" Since v7.4.191.
|
||||
make %:S
|
||||
endfunction
|
||||
|
||||
" Look for "spotbugs#compiler" in "ftplugin/java.vim".
|
||||
let s:compiler = exists('spotbugs#compiler') ? spotbugs#compiler : ''
|
||||
let s:readable = filereadable($VIMRUNTIME . '/compiler/' . s:compiler . '.vim')
|
||||
|
||||
if s:readable && s:compiler ==# 'maven' && executable('mvn')
|
||||
|
||||
function! spotbugs#DefaultPreCompilerAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler maven
|
||||
make compile
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultPreCompilerTestAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler maven
|
||||
make test-compile
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultProperties() abort
|
||||
return {
|
||||
\ 'PreCompilerAction':
|
||||
\ function('spotbugs#DefaultPreCompilerAction'),
|
||||
\ 'PreCompilerTestAction':
|
||||
\ function('spotbugs#DefaultPreCompilerTestAction'),
|
||||
\ 'PostCompilerAction':
|
||||
\ function('spotbugs#DefaultPostCompilerAction'),
|
||||
\ 'sourceDirPath': 'src/main/java',
|
||||
\ 'classDirPath': 'target/classes',
|
||||
\ 'testSourceDirPath': 'src/test/java',
|
||||
\ 'testClassDirPath': 'target/test-classes',
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
unlet s:readable s:compiler
|
||||
elseif s:readable && s:compiler ==# 'ant' && executable('ant')
|
||||
|
||||
function! spotbugs#DefaultPreCompilerAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler ant
|
||||
make compile
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultPreCompilerTestAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler ant
|
||||
make compile-test
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultProperties() abort
|
||||
return {
|
||||
\ 'PreCompilerAction':
|
||||
\ function('spotbugs#DefaultPreCompilerAction'),
|
||||
\ 'PreCompilerTestAction':
|
||||
\ function('spotbugs#DefaultPreCompilerTestAction'),
|
||||
\ 'PostCompilerAction':
|
||||
\ function('spotbugs#DefaultPostCompilerAction'),
|
||||
\ 'sourceDirPath': 'src',
|
||||
\ 'classDirPath': 'build/classes',
|
||||
\ 'testSourceDirPath': 'test',
|
||||
\ 'testClassDirPath': 'build/test/classes',
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
unlet s:readable s:compiler
|
||||
elseif s:readable && s:compiler ==# 'javac' && executable('javac')
|
||||
|
||||
function! spotbugs#DefaultPreCompilerAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler javac
|
||||
|
||||
if get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')) =~ '\s@\S'
|
||||
" Read options and filenames from @options [@sources ...].
|
||||
make
|
||||
else
|
||||
" Let Javac figure out what files to compile.
|
||||
execute 'make ' . join(map(filter(copy(v:argv),
|
||||
\ "v:val =~# '\\.java\\=$'"),
|
||||
\ 'shellescape(v:val)'), ' ')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultPreCompilerTestAction() abort
|
||||
call spotbugs#DefaultPreCompilerAction()
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultProperties() abort
|
||||
return {
|
||||
\ 'PreCompilerAction':
|
||||
\ function('spotbugs#DefaultPreCompilerAction'),
|
||||
\ 'PreCompilerTestAction':
|
||||
\ function('spotbugs#DefaultPreCompilerTestAction'),
|
||||
\ 'PostCompilerAction':
|
||||
\ function('spotbugs#DefaultPostCompilerAction'),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
unlet s:readable s:compiler
|
||||
else
|
||||
|
||||
function! spotbugs#DefaultPreCompilerAction() abort
|
||||
echomsg printf('Not supported: "%s"', s:compiler)
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultPreCompilerTestAction() abort
|
||||
call spotbugs#DefaultPreCompilerAction()
|
||||
endfunction
|
||||
|
||||
function! spotbugs#DefaultProperties() abort
|
||||
return {}
|
||||
endfunction
|
||||
|
||||
unlet s:readable
|
||||
endif
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim: set foldmethod=syntax shiftwidth=2 expandtab:
|
@ -1,7 +1,7 @@
|
||||
" Vim compiler file
|
||||
" Compiler: Java Development Kit Compiler
|
||||
" Maintainer: Doug Kearns <dougkearns@gmail.com>
|
||||
" Last Change: 2024 Jun 14
|
||||
" Last Change: 2024 Nov 19 (enable local javac_makeprg_params)
|
||||
|
||||
if exists("current_compiler")
|
||||
finish
|
||||
@ -11,11 +11,7 @@ let current_compiler = "javac"
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
if exists("g:javac_makeprg_params")
|
||||
execute $'CompilerSet makeprg=javac\ {escape(g:javac_makeprg_params, ' \|"')}'
|
||||
else
|
||||
CompilerSet makeprg=javac
|
||||
endif
|
||||
execute $'CompilerSet makeprg=javac\ {escape(get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')), ' \|"')}'
|
||||
|
||||
CompilerSet errorformat=%E%f:%l:\ error:\ %m,
|
||||
\%W%f:%l:\ warning:\ %m,
|
||||
|
@ -14,7 +14,7 @@ if exists("current_compiler")
|
||||
endif
|
||||
let current_compiler = "maven"
|
||||
|
||||
CompilerSet makeprg=mvn\ --batch-mode
|
||||
execute $'CompilerSet makeprg=mvn\ --batch-mode\ {escape(get(b:, 'maven_makeprg_params', get(g:, 'maven_makeprg_params', '')), ' \|"')}'
|
||||
|
||||
" Error message for POM
|
||||
CompilerSet errorformat=[FATAL]\ Non-parseable\ POM\ %f:\ %m%\\s%\\+@%.%#line\ %l\\,\ column\ %c%.%#,
|
||||
|
189
runtime/compiler/spotbugs.vim
Normal file
189
runtime/compiler/spotbugs.vim
Normal file
@ -0,0 +1,189 @@
|
||||
" Vim compiler file
|
||||
" Compiler: Spotbugs (Java static checker; needs javac compiled classes)
|
||||
" Maintainer: @konfekt and @zzzyxwvut
|
||||
" Last Change: 2024 Nov 27
|
||||
|
||||
if exists('g:current_compiler') || bufname() !~# '\.java\=$' || wordcount().chars < 9
|
||||
finish
|
||||
endif
|
||||
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" Unfortunately Spotbugs does not output absolute paths, so you need to
|
||||
" pass the directory of the files being checked as `-sourcepath` parameter.
|
||||
" The regex, auxpath and glob try to include all dependent classes of the
|
||||
" current buffer. See https://github.com/spotbugs/spotbugs/issues/856
|
||||
|
||||
" FIXME: When "search()" is used with the "e" flag, it makes no _further_
|
||||
" progress after claiming an EOL match (i.e. "\_" or "\n", but not "$").
|
||||
" XXX: Omit anonymous class declarations
|
||||
let s:keywords = '\C\<\%(\.\@1<!class\|@\=interface\|enum\|record\|package\)\%(\s\|$\)'
|
||||
let s:type_names = '\C\<\%(\.\@1<!class\|@\=interface\|enum\|record\)\s*\(\K\k*\)\>'
|
||||
" Capture ";" for counting a class file directory (see s:package_dir_heads below)
|
||||
let s:package_names = '\C\<package\s*\(\K\%(\k*\.\=\)\+;\)'
|
||||
let s:package = ''
|
||||
|
||||
if has('syntax') && exists('g:syntax_on') && exists('b:current_syntax') &&
|
||||
\ b:current_syntax == 'java' && hlexists('javaClassDecl')
|
||||
|
||||
function! s:GetDeclaredTypeNames() abort
|
||||
if bufname() =~# '\<\%(module\|package\)-info\.java\=$'
|
||||
return [expand('%:t:r')]
|
||||
endif
|
||||
defer execute('silent! normal! g``')
|
||||
call cursor(1, 1)
|
||||
let type_names = []
|
||||
let lnum = search(s:keywords, 'eW')
|
||||
while lnum > 0
|
||||
let name_attr = synIDattr(synID(lnum, (col('.') - 1), 0), 'name')
|
||||
if name_attr ==# 'javaClassDecl'
|
||||
let tokens = matchlist(getline(lnum)..getline(lnum + 1), s:type_names)
|
||||
if !empty(tokens) | call add(type_names, tokens[1]) | endif
|
||||
elseif name_attr ==# 'javaExternal'
|
||||
let tokens = matchlist(getline(lnum)..getline(lnum + 1), s:package_names)
|
||||
if !empty(tokens) | let s:package = tokens[1] | endif
|
||||
endif
|
||||
let lnum = search(s:keywords, 'eW')
|
||||
endwhile
|
||||
return type_names
|
||||
endfunction
|
||||
|
||||
else
|
||||
function! s:GetDeclaredTypeNames() abort
|
||||
if bufname() =~# '\<\%(module\|package\)-info\.java\=$'
|
||||
return [expand('%:t:r')]
|
||||
endif
|
||||
" Undo the unsetting of &hls, see below
|
||||
if &hls
|
||||
defer execute('set hls')
|
||||
endif
|
||||
" Possibly restore the current values for registers '"' and "y", see below
|
||||
defer call('setreg', ['"', getreg('"'), getregtype('"')])
|
||||
defer call('setreg', ['y', getreg('y'), getregtype('y')])
|
||||
defer execute('silent bwipeout')
|
||||
" Copy buffer contents for modification
|
||||
silent %y y
|
||||
new
|
||||
" Apply ":help scratch-buffer" effects and match "$" in Java (generated)
|
||||
" type names (see s:type_names)
|
||||
setlocal iskeyword+=$ buftype=nofile bufhidden=hide noswapfile nohls
|
||||
0put y
|
||||
" Discard text blocks and strings
|
||||
silent keeppatterns %s/\\\@<!"""\_.\{-}\\\@<!"""\|\\"//ge
|
||||
silent keeppatterns %s/".*"//ge
|
||||
" Discard comments
|
||||
silent keeppatterns %s/\/\/.\+$//ge
|
||||
silent keeppatterns %s/\/\*\_.\{-}\*\///ge
|
||||
call cursor(1, 1)
|
||||
let type_names = []
|
||||
let lnum = search(s:keywords, 'eW')
|
||||
while lnum > 0
|
||||
let line = getline(lnum)
|
||||
if line =~# '\<package\>'
|
||||
let tokens = matchlist(line..getline(lnum + 1), s:package_names)
|
||||
if !empty(tokens) | let s:package = tokens[1] | endif
|
||||
else
|
||||
let tokens = matchlist(line..getline(lnum + 1), s:type_names)
|
||||
if !empty(tokens) | call add(type_names, tokens[1]) | endif
|
||||
endif
|
||||
let lnum = search(s:keywords, 'eW')
|
||||
endwhile
|
||||
return type_names
|
||||
endfunction
|
||||
endif
|
||||
|
||||
if has('win32')
|
||||
|
||||
function! s:GlobClassFiles(src_type_name) abort
|
||||
return glob(a:src_type_name..'$*.class', 1, 1)
|
||||
endfunction
|
||||
|
||||
else
|
||||
function! s:GlobClassFiles(src_type_name) abort
|
||||
return glob(a:src_type_name..'\$*.class', 1, 1)
|
||||
endfunction
|
||||
endif
|
||||
|
||||
if exists('g:spotbugs_properties') &&
|
||||
\ (has_key(g:spotbugs_properties, 'sourceDirPath') &&
|
||||
\ has_key(g:spotbugs_properties, 'classDirPath')) ||
|
||||
\ (has_key(g:spotbugs_properties, 'testSourceDirPath') &&
|
||||
\ has_key(g:spotbugs_properties, 'testClassDirPath'))
|
||||
|
||||
function! s:FindClassFiles(src_type_name) abort
|
||||
let class_files = []
|
||||
" Match pairwise the components of source and class pathnames
|
||||
for [src_dir, bin_dir] in filter([
|
||||
\ [get(g:spotbugs_properties, 'sourceDirPath', ''),
|
||||
\ get(g:spotbugs_properties, 'classDirPath', '')],
|
||||
\ [get(g:spotbugs_properties, 'testSourceDirPath', ''),
|
||||
\ get(g:spotbugs_properties, 'testClassDirPath', '')]],
|
||||
\ '!(empty(v:val[0]) || empty(v:val[1]))')
|
||||
" Since only the rightmost "src" is sought, while there can be any number of
|
||||
" such filenames, no "fnamemodify(a:src_type_name, ':p:s?src?bin?')" is used
|
||||
let tail_idx = strridx(a:src_type_name, src_dir)
|
||||
" No such directory or no such inner type (i.e. without "$")
|
||||
if tail_idx < 0 | continue | endif
|
||||
" Substitute "bin_dir" for the rightmost "src_dir"
|
||||
let candidate_type_name = strpart(a:src_type_name, 0, tail_idx)..
|
||||
\ bin_dir..
|
||||
\ strpart(a:src_type_name, (tail_idx + strlen(src_dir)))
|
||||
for candidate in insert(s:GlobClassFiles(candidate_type_name),
|
||||
\ candidate_type_name..'.class')
|
||||
if filereadable(candidate) | call add(class_files, shellescape(candidate)) | endif
|
||||
endfor
|
||||
if !empty(class_files) | break | endif
|
||||
endfor
|
||||
return class_files
|
||||
endfunction
|
||||
|
||||
else
|
||||
function! s:FindClassFiles(src_type_name) abort
|
||||
let class_files = []
|
||||
for candidate in insert(s:GlobClassFiles(a:src_type_name),
|
||||
\ a:src_type_name..'.class')
|
||||
if filereadable(candidate) | call add(class_files, shellescape(candidate)) | endif
|
||||
endfor
|
||||
return class_files
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:CollectClassFiles() abort
|
||||
" Get a platform-independent pathname prefix, cf. "expand('%:p:h')..'/'"
|
||||
let pathname = expand('%:p')
|
||||
let tail_idx = strridx(pathname, expand('%:t'))
|
||||
let src_pathname = strpart(pathname, 0, tail_idx)
|
||||
let all_class_files = []
|
||||
" Get all type names in the current buffer and let the filename globbing
|
||||
" discover inner type names from arbitrary type names
|
||||
for type_name in s:GetDeclaredTypeNames()
|
||||
call extend(all_class_files, s:FindClassFiles(src_pathname..type_name))
|
||||
endfor
|
||||
return all_class_files
|
||||
endfunction
|
||||
|
||||
" Expose class files for removal etc.
|
||||
let b:spotbugs_class_files = s:CollectClassFiles()
|
||||
let s:package_dir_heads = repeat(':h', (1 + strlen(substitute(s:package, '[^.;]', '', 'g'))))
|
||||
let g:current_compiler = 'spotbugs'
|
||||
" CompilerSet makeprg=spotbugs
|
||||
let &l:makeprg = 'spotbugs'..(has('win32') ? '.bat' : '')..' '..
|
||||
\ get(b:, 'spotbugs_makeprg_params', get(g:, 'spotbugs_makeprg_params', '-workHard -experimental'))..
|
||||
\ ' -textui -emacs -auxclasspath %:p'..s:package_dir_heads..':S -sourcepath %:p'..s:package_dir_heads..':S '..
|
||||
\ join(b:spotbugs_class_files, ' ')
|
||||
" Emacs expects doubled line numbers
|
||||
setlocal errorformat=%f:%l:%*[0-9]\ %m,%f:-%*[0-9]:-%*[0-9]\ %m
|
||||
|
||||
" " This compiler is meant to be used for a single buffer only
|
||||
" exe 'CompilerSet makeprg='..escape(&l:makeprg, ' \|"')
|
||||
" exe 'CompilerSet errorformat='..escape(&l:errorformat, ' \|"')
|
||||
|
||||
delfunction s:CollectClassFiles
|
||||
delfunction s:FindClassFiles
|
||||
delfunction s:GlobClassFiles
|
||||
delfunction s:GetDeclaredTypeNames
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:package_dir_heads s:package s:package_names s:type_names s:keywords s:cpo_save
|
||||
|
||||
" vim: set foldmethod=syntax shiftwidth=2 expandtab:
|
@ -1317,9 +1317,117 @@ g:compiler_gcc_ignore_unmatched_lines
|
||||
JAVAC *compiler-javac*
|
||||
|
||||
Commonly used compiler options can be added to 'makeprg' by setting the
|
||||
g:javac_makeprg_params variable. For example: >
|
||||
b/g:javac_makeprg_params variable. For example: >
|
||||
|
||||
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
|
||||
<
|
||||
|
||||
MAVEN *compiler-maven*
|
||||
|
||||
Commonly used compiler options can be added to 'makeprg' by setting the
|
||||
b/g:maven_makeprg_params variable. For example: >
|
||||
|
||||
let g:maven_makeprg_params = "-DskipTests -U -X"
|
||||
|
||||
SPOTBUGS *compiler-spotbugs*
|
||||
|
||||
SpotBugs is a static analysis tool that can be used to find bugs in Java.
|
||||
It scans the Java bytecode of all classes in the currently open buffer.
|
||||
(Therefore, `:compiler! spotbugs` is not supported.)
|
||||
|
||||
Commonly used compiler options can be added to 'makeprg' by setting the
|
||||
"b:" or "g:spotbugs_makeprg_params" variable. For example: >
|
||||
|
||||
let b:spotbugs_makeprg_params = "-longBugCodes -effort:max -low"
|
||||
|
||||
The global default is "-workHard -experimental".
|
||||
|
||||
By default, the class files are searched in the directory where the source
|
||||
files are placed. However, typical Java projects use distinct directories
|
||||
for source files and class files. To make both known to SpotBugs, assign
|
||||
their paths (distinct and relative to their common root directory) to the
|
||||
following properties (using the example of a common Maven project): >
|
||||
|
||||
let g:spotbugs_properties = {
|
||||
\ 'sourceDirPath': 'src/main/java',
|
||||
\ 'classDirPath': 'target/classes',
|
||||
\ 'testSourceDirPath': 'src/test/java',
|
||||
\ 'testClassDirPath': 'target/test-classes',
|
||||
\ }
|
||||
|
||||
Note that values for the path keys describe only for SpotBugs where to look
|
||||
for files; refer to the documentation for particular compiler plugins for more
|
||||
information.
|
||||
|
||||
The default pre- and post-compiler actions are provided for Ant, Maven, and
|
||||
Javac compiler plugins and can be selected by assigning the name of a compiler
|
||||
plugin to the "compiler" key: >
|
||||
|
||||
let g:spotbugs_properties = {
|
||||
\ 'compiler': 'maven',
|
||||
\ }
|
||||
|
||||
This single setting is essentially equivalent to all the settings below, with
|
||||
the exception made for the "PreCompilerAction" and "PreCompilerTestAction"
|
||||
values: their listed |Funcref|s will obtain no-op implementations whereas the
|
||||
implicit Funcrefs of the "compiler" key will obtain the requested defaults if
|
||||
available. >
|
||||
|
||||
let g:spotbugs_properties = {
|
||||
\ 'PreCompilerAction':
|
||||
\ function('spotbugs#DefaultPreCompilerAction'),
|
||||
\ 'PreCompilerTestAction':
|
||||
\ function('spotbugs#DefaultPreCompilerTestAction'),
|
||||
\ 'PostCompilerAction':
|
||||
\ function('spotbugs#DefaultPostCompilerAction'),
|
||||
\ 'sourceDirPath': 'src/main/java',
|
||||
\ 'classDirPath': 'target/classes',
|
||||
\ 'testSourceDirPath': 'src/test/java',
|
||||
\ 'testClassDirPath': 'target/test-classes',
|
||||
\ }
|
||||
|
||||
With default actions, the compiler of choice will attempt to rebuild the class
|
||||
files for the buffer (and possibly for the whole project) as soon as a Java
|
||||
syntax file is loaded; then, `spotbugs` will attempt to analyze the quality of
|
||||
the compilation unit of the buffer.
|
||||
|
||||
When default actions are not suited to a desired workflow, consider writing
|
||||
arbitrary functions yourself and matching their |Funcref|s to the supported
|
||||
keys: "PreCompilerAction", "PreCompilerTestAction", and "PostCompilerAction".
|
||||
|
||||
The next example re-implements the default pre-compiler actions for a Maven
|
||||
project and requests other default Maven settings with the "compiler" entry: >
|
||||
|
||||
function! MavenPreCompilerAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler maven
|
||||
make compile
|
||||
endfunction
|
||||
|
||||
function! MavenPreCompilerTestAction() abort
|
||||
call spotbugs#DeleteClassFiles()
|
||||
compiler maven
|
||||
make test-compile
|
||||
endfunction
|
||||
|
||||
let g:spotbugs_properties = {
|
||||
\ 'compiler': 'maven',
|
||||
\ 'PreCompilerAction':
|
||||
\ function('MavenPreCompilerAction'),
|
||||
\ 'PreCompilerTestAction':
|
||||
\ function('MavenPreCompilerTestAction'),
|
||||
\ }
|
||||
|
||||
Note that all entered custom settings will take precedence over the matching
|
||||
default settings in "g:spotbugs_properties".
|
||||
|
||||
The "g:spotbugs_properties" variable is consulted by the Java filetype plugin
|
||||
(|ft-java-plugin|) to arrange for the described automation, and, therefore, it
|
||||
must be defined before |FileType| events can take place for the buffers loaded
|
||||
with Java source files. It could, for example, be set in a project-local
|
||||
|vimrc| loaded by [0].
|
||||
|
||||
[0] https://github.com/MarcWeber/vim-addon-local-vimrc/
|
||||
|
||||
GNU MAKE *compiler-make*
|
||||
|
||||
Since the default make program is "make", the compiler plugin for make,
|
||||
|
@ -3,7 +3,7 @@
|
||||
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
|
||||
" Former Maintainer: Dan Sharp
|
||||
" Repository: https://github.com/zzzyxwvut/java-vim.git
|
||||
" Last Change: 2024 Sep 26
|
||||
" Last Change: 2024 Nov 24
|
||||
" 2024 Jan 14 by Vim Project (browsefilter)
|
||||
" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
|
||||
|
||||
@ -90,10 +90,127 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
|
||||
endif
|
||||
endif
|
||||
|
||||
" The support for pre- and post-compiler actions for SpotBugs.
|
||||
if exists("g:spotbugs_properties") && has_key(g:spotbugs_properties, 'compiler')
|
||||
try
|
||||
let spotbugs#compiler = g:spotbugs_properties.compiler
|
||||
let g:spotbugs_properties = extend(
|
||||
\ spotbugs#DefaultProperties(),
|
||||
\ g:spotbugs_properties,
|
||||
\ 'force')
|
||||
catch
|
||||
echomsg v:errmsg
|
||||
finally
|
||||
call remove(g:spotbugs_properties, 'compiler')
|
||||
endtry
|
||||
endif
|
||||
|
||||
if exists("g:spotbugs_properties") &&
|
||||
\ filereadable($VIMRUNTIME . '/compiler/spotbugs.vim')
|
||||
let s:request = 0
|
||||
|
||||
if has_key(g:spotbugs_properties, 'PreCompilerAction')
|
||||
let s:dispatcher = 'call g:spotbugs_properties.PreCompilerAction() | '
|
||||
let s:request += 1
|
||||
endif
|
||||
|
||||
if has_key(g:spotbugs_properties, 'PreCompilerTestAction')
|
||||
let s:dispatcher = 'call g:spotbugs_properties.PreCompilerTestAction() | '
|
||||
let s:request += 2
|
||||
endif
|
||||
|
||||
if has_key(g:spotbugs_properties, 'PostCompilerAction')
|
||||
let s:request += 4
|
||||
endif
|
||||
|
||||
if (s:request == 3 || s:request == 7) &&
|
||||
\ has_key(g:spotbugs_properties, 'sourceDirPath') &&
|
||||
\ has_key(g:spotbugs_properties, 'testSourceDirPath')
|
||||
function! s:DispatchAction(path_action_pairs) abort
|
||||
let name = expand('%:p')
|
||||
|
||||
for [path, Action] in a:path_action_pairs
|
||||
if name =~# (path . '.\{-}\.java\=$')
|
||||
call Action()
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
let s:dispatcher = printf('call s:DispatchAction(%s) | ',
|
||||
\ string([[g:spotbugs_properties.sourceDirPath,
|
||||
\ g:spotbugs_properties.PreCompilerAction],
|
||||
\ [g:spotbugs_properties.testSourceDirPath,
|
||||
\ g:spotbugs_properties.PreCompilerTestAction]]))
|
||||
endif
|
||||
|
||||
if s:request
|
||||
if exists("b:spotbugs_syntax_once")
|
||||
let s:actions = [{'event': 'BufWritePost'}]
|
||||
else
|
||||
" XXX: Handle multiple FileType events when vimrc contains more
|
||||
" than one filetype setting for the language, e.g.:
|
||||
" :filetype plugin indent on
|
||||
" :autocmd BufRead,BufNewFile *.java setlocal filetype=java ...
|
||||
" XXX: DO NOT ADD b:spotbugs_syntax_once TO b:undo_ftplugin !
|
||||
let b:spotbugs_syntax_once = 1
|
||||
let s:actions = [{
|
||||
\ 'event': 'Syntax',
|
||||
\ 'once': 1,
|
||||
\ }, {
|
||||
\ 'event': 'BufWritePost',
|
||||
\ }]
|
||||
endif
|
||||
|
||||
for s:idx in range(len(s:actions))
|
||||
if s:request == 7 || s:request == 6 || s:request == 5
|
||||
let s:actions[s:idx].cmd = s:dispatcher . 'compiler spotbugs | ' .
|
||||
\ 'call g:spotbugs_properties.PostCompilerAction()'
|
||||
elseif s:request == 4
|
||||
let s:actions[s:idx].cmd = 'compiler spotbugs | ' .
|
||||
\ 'call g:spotbugs_properties.PostCompilerAction()'
|
||||
elseif s:request == 3 || s:request == 2 || s:request == 1
|
||||
let s:actions[s:idx].cmd = s:dispatcher . 'compiler spotbugs'
|
||||
else
|
||||
let s:actions[s:idx].cmd = ''
|
||||
endif
|
||||
endfor
|
||||
|
||||
if !exists("#java_spotbugs")
|
||||
augroup java_spotbugs
|
||||
augroup END
|
||||
endif
|
||||
|
||||
" The events are defined in s:actions.
|
||||
silent! autocmd! java_spotbugs BufWritePost <buffer>
|
||||
silent! autocmd! java_spotbugs Syntax <buffer>
|
||||
|
||||
for s:action in s:actions
|
||||
execute printf('autocmd java_spotbugs %s <buffer> %s',
|
||||
\ s:action.event,
|
||||
\ s:action.cmd . (has_key(s:action, 'once')
|
||||
\ ? printf(' | autocmd! java_spotbugs %s <buffer>',
|
||||
\ s:action.event)
|
||||
\ : ''))
|
||||
endfor
|
||||
|
||||
unlet! s:action s:actions s:idx s:dispatcher
|
||||
endif
|
||||
|
||||
unlet s:request
|
||||
endif
|
||||
|
||||
function! JavaFileTypeCleanUp() abort
|
||||
setlocal suffixes< suffixesadd< formatoptions< comments< commentstring< path< includeexpr<
|
||||
unlet! b:browsefilter
|
||||
|
||||
" The concatenated removals may be misparsed as a BufWritePost autocmd.
|
||||
silent! autocmd! java_spotbugs BufWritePost <buffer>
|
||||
silent! autocmd! java_spotbugs Syntax <buffer>
|
||||
endfunction
|
||||
|
||||
" Undo the stuff we changed.
|
||||
let b:undo_ftplugin = "setlocal suffixes< suffixesadd<" .
|
||||
\ " formatoptions< comments< commentstring< path< includeexpr<" .
|
||||
\ " | unlet! b:browsefilter"
|
||||
let b:undo_ftplugin = 'call JavaFileTypeCleanUp() | delfunction JavaFileTypeCleanUp'
|
||||
|
||||
" See ":help vim9-mix".
|
||||
if !has("vim9script")
|
||||
@ -114,6 +231,19 @@ if exists("s:zip_func_upgradable")
|
||||
setlocal suffixesadd<
|
||||
endif
|
||||
|
||||
if exists("*s:DispatchAction")
|
||||
def! s:DispatchAction(path_action_pairs: list<list<any>>)
|
||||
const name: string = expand('%:p')
|
||||
|
||||
for [path: string, Action: func: any] in path_action_pairs
|
||||
if name =~# (path .. '.\{-}\.java\=$')
|
||||
Action()
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
enddef
|
||||
endif
|
||||
|
||||
" Restore the saved compatibility options.
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
Loading…
Reference in New Issue
Block a user