| " Default pre- and post-compiler actions and commands for SpotBugs |
| " Maintainers: @konfekt and @zzzyxwvut |
| " Last Change: 2024 Dec 08 |
| |
| let s:save_cpo = &cpo |
| set cpo&vim |
| |
| " Look for the setting of "g:spotbugs#state" in "ftplugin/java.vim". |
| let s:state = get(g:, 'spotbugs#state', {}) |
| let s:commands = get(s:state, 'commands', {}) |
| let s:compiler = get(s:state, 'compiler', '') |
| let s:readable = filereadable($VIMRUNTIME . '/compiler/' . s:compiler . '.vim') |
| |
| if has_key(s:commands, 'DefaultPreCompilerCommand') |
| let g:SpotBugsPreCompilerCommand = s:commands.DefaultPreCompilerCommand |
| else |
| |
| function! s:DefaultPreCompilerCommand(arguments) abort |
| execute 'make ' . a:arguments |
| cc |
| endfunction |
| |
| let g:SpotBugsPreCompilerCommand = function('s:DefaultPreCompilerCommand') |
| endif |
| |
| if has_key(s:commands, 'DefaultPreCompilerTestCommand') |
| let g:SpotBugsPreCompilerTestCommand = s:commands.DefaultPreCompilerTestCommand |
| else |
| |
| function! s:DefaultPreCompilerTestCommand(arguments) abort |
| execute 'make ' . a:arguments |
| cc |
| endfunction |
| |
| let g:SpotBugsPreCompilerTestCommand = function('s:DefaultPreCompilerTestCommand') |
| endif |
| |
| if has_key(s:commands, 'DefaultPostCompilerCommand') |
| let g:SpotBugsPostCompilerCommand = s:commands.DefaultPostCompilerCommand |
| else |
| |
| function! s:DefaultPostCompilerCommand(arguments) abort |
| execute 'make ' . a:arguments |
| endfunction |
| |
| let g:SpotBugsPostCompilerCommand = function('s:DefaultPostCompilerCommand') |
| endif |
| |
| 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. |
| call call(g:SpotBugsPostCompilerCommand, ['%:S']) |
| endfunction |
| |
| if s:readable && s:compiler ==# 'maven' && executable('mvn') |
| |
| function! spotbugs#DefaultPreCompilerAction() abort |
| call spotbugs#DeleteClassFiles() |
| compiler maven |
| call call(g:SpotBugsPreCompilerCommand, ['compile']) |
| endfunction |
| |
| function! spotbugs#DefaultPreCompilerTestAction() abort |
| call spotbugs#DeleteClassFiles() |
| compiler maven |
| call call(g:SpotBugsPreCompilerTestCommand, ['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 |
| call call(g:SpotBugsPreCompilerCommand, ['compile']) |
| endfunction |
| |
| function! spotbugs#DefaultPreCompilerTestAction() abort |
| call spotbugs#DeleteClassFiles() |
| compiler ant |
| call call(g:SpotBugsPreCompilerTestCommand, ['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') |
| let s:filename = tempname() |
| |
| function! spotbugs#DefaultPreCompilerAction() abort |
| call spotbugs#DeleteClassFiles() |
| compiler javac |
| |
| if get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')) =~ '\s@\S' |
| " Only read options and filenames from @options [@sources ...] and do |
| " not update these files when filelists change. |
| call call(g:SpotBugsPreCompilerCommand, ['']) |
| else |
| " Collect filenames so that Javac can figure out what to compile. |
| let filelist = [] |
| |
| for arg_num in range(argc(-1)) |
| let arg_name = argv(arg_num) |
| |
| if arg_name =~# '\.java\=$' |
| call add(filelist, fnamemodify(arg_name, ':p:S')) |
| endif |
| endfor |
| |
| for buf_num in range(1, bufnr('$')) |
| if !buflisted(buf_num) |
| continue |
| endif |
| |
| let buf_name = bufname(buf_num) |
| |
| if buf_name =~# '\.java\=$' |
| let buf_name = fnamemodify(buf_name, ':p:S') |
| |
| if index(filelist, buf_name) < 0 |
| call add(filelist, buf_name) |
| endif |
| endif |
| endfor |
| |
| noautocmd call writefile(filelist, s:filename) |
| call call(g:SpotBugsPreCompilerCommand, [shellescape('@' . s:filename)]) |
| endif |
| endfunction |
| |
| function! spotbugs#DefaultPreCompilerTestAction() abort |
| call spotbugs#DefaultPreCompilerAction() |
| endfunction |
| |
| function! spotbugs#DefaultProperties() abort |
| return { |
| \ 'PreCompilerAction': |
| \ function('spotbugs#DefaultPreCompilerAction'), |
| \ 'PostCompilerAction': |
| \ function('spotbugs#DefaultPostCompilerAction'), |
| \ } |
| endfunction |
| |
| unlet s:readable s:compiler g:SpotBugsPreCompilerTestCommand |
| delfunction! s:DefaultPreCompilerTestCommand |
| 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 |
| |
| " XXX: Keep "s:compiler" around for "spotbugs#DefaultPreCompilerAction()", |
| " "s:DefaultPostCompilerCommand" -- "spotbugs#DefaultPostCompilerAction()". |
| unlet s:readable g:SpotBugsPreCompilerCommand g:SpotBugsPreCompilerTestCommand |
| delfunction! s:DefaultPreCompilerCommand |
| delfunction! s:DefaultPreCompilerTestCommand |
| endif |
| |
| function! s:DefineBufferAutocmd(event, ...) abort |
| if !exists('#java_spotbugs#User') |
| return 1 |
| endif |
| |
| for l:event in insert(copy(a:000), a:event) |
| if l:event != 'User' |
| execute printf('silent! autocmd! java_spotbugs %s <buffer>', l:event) |
| execute printf('autocmd java_spotbugs %s <buffer> doautocmd User', l:event) |
| endif |
| endfor |
| |
| return 0 |
| endfunction |
| |
| function! s:RemoveBufferAutocmd(event, ...) abort |
| if !exists('#java_spotbugs') |
| return 1 |
| endif |
| |
| for l:event in insert(copy(a:000), a:event) |
| if l:event != 'User' |
| execute printf('silent! autocmd! java_spotbugs %s <buffer>', l:event) |
| endif |
| endfor |
| |
| return 0 |
| endfunction |
| |
| " Documented in ":help compiler-spotbugs". |
| command! -bar -nargs=+ -complete=event SpotBugsDefineBufferAutocmd |
| \ call s:DefineBufferAutocmd(<f-args>) |
| command! -bar -nargs=+ -complete=event SpotBugsRemoveBufferAutocmd |
| \ call s:RemoveBufferAutocmd(<f-args>) |
| |
| let &cpo = s:save_cpo |
| unlet s:commands s:state s:save_cpo |
| |
| " vim: set foldmethod=syntax shiftwidth=2 expandtab: |