Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 1 | " Default pre- and post-compiler actions and commands for SpotBugs |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 2 | " Maintainers: @konfekt and @zzzyxwvut |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 3 | " Last Change: 2024 Dec 08 |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 4 | |
| 5 | let s:save_cpo = &cpo |
| 6 | set cpo&vim |
| 7 | |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 8 | " Look for the setting of "g:spotbugs#state" in "ftplugin/java.vim". |
| 9 | let s:state = get(g:, 'spotbugs#state', {}) |
| 10 | let s:commands = get(s:state, 'commands', {}) |
| 11 | let s:compiler = get(s:state, 'compiler', '') |
| 12 | let s:readable = filereadable($VIMRUNTIME . '/compiler/' . s:compiler . '.vim') |
| 13 | |
| 14 | if has_key(s:commands, 'DefaultPreCompilerCommand') |
| 15 | let g:SpotBugsPreCompilerCommand = s:commands.DefaultPreCompilerCommand |
| 16 | else |
| 17 | |
| 18 | function! s:DefaultPreCompilerCommand(arguments) abort |
| 19 | execute 'make ' . a:arguments |
| 20 | cc |
| 21 | endfunction |
| 22 | |
| 23 | let g:SpotBugsPreCompilerCommand = function('s:DefaultPreCompilerCommand') |
| 24 | endif |
| 25 | |
| 26 | if has_key(s:commands, 'DefaultPreCompilerTestCommand') |
| 27 | let g:SpotBugsPreCompilerTestCommand = s:commands.DefaultPreCompilerTestCommand |
| 28 | else |
| 29 | |
| 30 | function! s:DefaultPreCompilerTestCommand(arguments) abort |
| 31 | execute 'make ' . a:arguments |
| 32 | cc |
| 33 | endfunction |
| 34 | |
| 35 | let g:SpotBugsPreCompilerTestCommand = function('s:DefaultPreCompilerTestCommand') |
| 36 | endif |
| 37 | |
| 38 | if has_key(s:commands, 'DefaultPostCompilerCommand') |
| 39 | let g:SpotBugsPostCompilerCommand = s:commands.DefaultPostCompilerCommand |
| 40 | else |
| 41 | |
| 42 | function! s:DefaultPostCompilerCommand(arguments) abort |
| 43 | execute 'make ' . a:arguments |
| 44 | endfunction |
| 45 | |
| 46 | let g:SpotBugsPostCompilerCommand = function('s:DefaultPostCompilerCommand') |
| 47 | endif |
| 48 | |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 49 | if v:version > 900 |
| 50 | |
| 51 | function! spotbugs#DeleteClassFiles() abort |
| 52 | if !exists('b:spotbugs_class_files') |
| 53 | return |
| 54 | endif |
| 55 | |
| 56 | for pathname in b:spotbugs_class_files |
| 57 | let classname = pathname =~# "^'.\\+\\.class'$" |
| 58 | \ ? eval(pathname) |
| 59 | \ : pathname |
| 60 | |
| 61 | if classname =~# '\.class$' && filereadable(classname) |
| 62 | " Since v9.0.0795. |
| 63 | let octad = readblob(classname, 0, 8) |
| 64 | |
| 65 | " Test the magic number and the major version number (45 for v1.0). |
| 66 | " Since v9.0.2027. |
| 67 | if len(octad) == 8 && octad[0 : 3] == 0zcafe.babe && |
| 68 | \ or((octad[6] << 8), octad[7]) >= 45 |
| 69 | echomsg printf('Deleting %s: %d', classname, delete(classname)) |
| 70 | endif |
| 71 | endif |
| 72 | endfor |
| 73 | |
| 74 | let b:spotbugs_class_files = [] |
| 75 | endfunction |
| 76 | |
| 77 | else |
| 78 | |
| 79 | function! s:DeleteClassFilesWithNewLineCodes(classname) abort |
| 80 | " The distribution of "0a"s in class file versions 2560 and 2570: |
| 81 | " |
| 82 | " 0zca.fe.ba.be.00.00.0a.00 0zca.fe.ba.be.00.00.0a.0a |
| 83 | " 0zca.fe.ba.be.00.0a.0a.00 0zca.fe.ba.be.00.0a.0a.0a |
| 84 | " 0zca.fe.ba.be.0a.00.0a.00 0zca.fe.ba.be.0a.00.0a.0a |
| 85 | " 0zca.fe.ba.be.0a.0a.0a.00 0zca.fe.ba.be.0a.0a.0a.0a |
| 86 | let numbers = [0, 0, 0, 0, 0, 0, 0, 0] |
| 87 | let offset = 0 |
| 88 | let lines = readfile(a:classname, 'b', 4) |
| 89 | |
| 90 | " Track NL byte counts to handle files of less than 8 bytes. |
| 91 | let nl_cnt = len(lines) |
| 92 | " Track non-NL byte counts for "0zca.fe.ba.be.0a.0a.0a.0a". |
| 93 | let non_nl_cnt = 0 |
| 94 | |
| 95 | for line in lines |
| 96 | for idx in range(strlen(line)) |
| 97 | " Remap NLs to Nuls. |
| 98 | let numbers[offset] = (line[idx] == "\n") ? 0 : char2nr(line[idx]) % 256 |
| 99 | let non_nl_cnt += 1 |
| 100 | let offset += 1 |
| 101 | |
| 102 | if offset > 7 |
| 103 | break |
| 104 | endif |
| 105 | endfor |
| 106 | |
| 107 | let nl_cnt -= 1 |
| 108 | |
| 109 | if offset > 7 || (nl_cnt < 1 && non_nl_cnt > 4) |
| 110 | break |
| 111 | endif |
| 112 | |
| 113 | " Reclaim NLs. |
| 114 | let numbers[offset] = 10 |
| 115 | let offset += 1 |
| 116 | |
| 117 | if offset > 7 |
| 118 | break |
| 119 | endif |
| 120 | endfor |
| 121 | |
| 122 | " Test the magic number and the major version number (45 for v1.0). |
| 123 | if offset > 7 && numbers[0] == 0xca && numbers[1] == 0xfe && |
| 124 | \ numbers[2] == 0xba && numbers[3] == 0xbe && |
| 125 | \ (numbers[6] * 256 + numbers[7]) >= 45 |
| 126 | echomsg printf('Deleting %s: %d', a:classname, delete(a:classname)) |
| 127 | endif |
| 128 | endfunction |
| 129 | |
| 130 | function! spotbugs#DeleteClassFiles() abort |
| 131 | if !exists('b:spotbugs_class_files') |
| 132 | return |
| 133 | endif |
| 134 | |
| 135 | let encoding = &encoding |
| 136 | |
| 137 | try |
| 138 | set encoding=latin1 |
| 139 | |
| 140 | for pathname in b:spotbugs_class_files |
| 141 | let classname = pathname =~# "^'.\\+\\.class'$" |
| 142 | \ ? eval(pathname) |
| 143 | \ : pathname |
| 144 | |
| 145 | if classname =~# '\.class$' && filereadable(classname) |
| 146 | let line = get(readfile(classname, 'b', 1), 0, '') |
| 147 | let length = strlen(line) |
| 148 | |
| 149 | " Test the magic number and the major version number (45 for v1.0). |
| 150 | if length > 3 && line[0 : 3] == "\xca\xfe\xba\xbe" |
| 151 | if length > 7 && ((line[6] == "\n" ? 0 : char2nr(line[6]) % 256) * 256 + |
| 152 | \ (line[7] == "\n" ? 0 : char2nr(line[7]) % 256)) >= 45 |
| 153 | echomsg printf('Deleting %s: %d', classname, delete(classname)) |
| 154 | else |
| 155 | call s:DeleteClassFilesWithNewLineCodes(classname) |
| 156 | endif |
| 157 | endif |
| 158 | endif |
| 159 | endfor |
| 160 | finally |
| 161 | let &encoding = encoding |
| 162 | endtry |
| 163 | |
| 164 | let b:spotbugs_class_files = [] |
| 165 | endfunction |
| 166 | |
| 167 | endif |
| 168 | |
| 169 | function! spotbugs#DefaultPostCompilerAction() abort |
| 170 | " Since v7.4.191. |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 171 | call call(g:SpotBugsPostCompilerCommand, ['%:S']) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 172 | endfunction |
| 173 | |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 174 | if s:readable && s:compiler ==# 'maven' && executable('mvn') |
| 175 | |
| 176 | function! spotbugs#DefaultPreCompilerAction() abort |
| 177 | call spotbugs#DeleteClassFiles() |
| 178 | compiler maven |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 179 | call call(g:SpotBugsPreCompilerCommand, ['compile']) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 180 | endfunction |
| 181 | |
| 182 | function! spotbugs#DefaultPreCompilerTestAction() abort |
| 183 | call spotbugs#DeleteClassFiles() |
| 184 | compiler maven |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 185 | call call(g:SpotBugsPreCompilerTestCommand, ['test-compile']) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 186 | endfunction |
| 187 | |
| 188 | function! spotbugs#DefaultProperties() abort |
| 189 | return { |
| 190 | \ 'PreCompilerAction': |
| 191 | \ function('spotbugs#DefaultPreCompilerAction'), |
| 192 | \ 'PreCompilerTestAction': |
| 193 | \ function('spotbugs#DefaultPreCompilerTestAction'), |
| 194 | \ 'PostCompilerAction': |
| 195 | \ function('spotbugs#DefaultPostCompilerAction'), |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 196 | \ 'sourceDirPath': ['src/main/java'], |
| 197 | \ 'classDirPath': ['target/classes'], |
| 198 | \ 'testSourceDirPath': ['src/test/java'], |
| 199 | \ 'testClassDirPath': ['target/test-classes'], |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 200 | \ } |
| 201 | endfunction |
| 202 | |
| 203 | unlet s:readable s:compiler |
| 204 | elseif s:readable && s:compiler ==# 'ant' && executable('ant') |
| 205 | |
| 206 | function! spotbugs#DefaultPreCompilerAction() abort |
| 207 | call spotbugs#DeleteClassFiles() |
| 208 | compiler ant |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 209 | call call(g:SpotBugsPreCompilerCommand, ['compile']) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 210 | endfunction |
| 211 | |
| 212 | function! spotbugs#DefaultPreCompilerTestAction() abort |
| 213 | call spotbugs#DeleteClassFiles() |
| 214 | compiler ant |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 215 | call call(g:SpotBugsPreCompilerTestCommand, ['compile-test']) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 216 | endfunction |
| 217 | |
| 218 | function! spotbugs#DefaultProperties() abort |
| 219 | return { |
| 220 | \ 'PreCompilerAction': |
| 221 | \ function('spotbugs#DefaultPreCompilerAction'), |
| 222 | \ 'PreCompilerTestAction': |
| 223 | \ function('spotbugs#DefaultPreCompilerTestAction'), |
| 224 | \ 'PostCompilerAction': |
| 225 | \ function('spotbugs#DefaultPostCompilerAction'), |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 226 | \ 'sourceDirPath': ['src'], |
| 227 | \ 'classDirPath': ['build/classes'], |
| 228 | \ 'testSourceDirPath': ['test'], |
| 229 | \ 'testClassDirPath': ['build/test/classes'], |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 230 | \ } |
| 231 | endfunction |
| 232 | |
| 233 | unlet s:readable s:compiler |
| 234 | elseif s:readable && s:compiler ==# 'javac' && executable('javac') |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 235 | let s:filename = tempname() |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 236 | |
| 237 | function! spotbugs#DefaultPreCompilerAction() abort |
| 238 | call spotbugs#DeleteClassFiles() |
| 239 | compiler javac |
| 240 | |
| 241 | if get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')) =~ '\s@\S' |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 242 | " Only read options and filenames from @options [@sources ...] and do |
| 243 | " not update these files when filelists change. |
| 244 | call call(g:SpotBugsPreCompilerCommand, ['']) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 245 | else |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 246 | " Collect filenames so that Javac can figure out what to compile. |
| 247 | let filelist = [] |
| 248 | |
| 249 | for arg_num in range(argc(-1)) |
| 250 | let arg_name = argv(arg_num) |
| 251 | |
| 252 | if arg_name =~# '\.java\=$' |
| 253 | call add(filelist, fnamemodify(arg_name, ':p:S')) |
| 254 | endif |
| 255 | endfor |
| 256 | |
| 257 | for buf_num in range(1, bufnr('$')) |
| 258 | if !buflisted(buf_num) |
| 259 | continue |
| 260 | endif |
| 261 | |
| 262 | let buf_name = bufname(buf_num) |
| 263 | |
| 264 | if buf_name =~# '\.java\=$' |
| 265 | let buf_name = fnamemodify(buf_name, ':p:S') |
| 266 | |
| 267 | if index(filelist, buf_name) < 0 |
| 268 | call add(filelist, buf_name) |
| 269 | endif |
| 270 | endif |
| 271 | endfor |
| 272 | |
| 273 | noautocmd call writefile(filelist, s:filename) |
| 274 | call call(g:SpotBugsPreCompilerCommand, [shellescape('@' . s:filename)]) |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 275 | endif |
| 276 | endfunction |
| 277 | |
| 278 | function! spotbugs#DefaultPreCompilerTestAction() abort |
| 279 | call spotbugs#DefaultPreCompilerAction() |
| 280 | endfunction |
| 281 | |
| 282 | function! spotbugs#DefaultProperties() abort |
| 283 | return { |
| 284 | \ 'PreCompilerAction': |
| 285 | \ function('spotbugs#DefaultPreCompilerAction'), |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 286 | \ 'PostCompilerAction': |
| 287 | \ function('spotbugs#DefaultPostCompilerAction'), |
| 288 | \ } |
| 289 | endfunction |
| 290 | |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 291 | unlet s:readable s:compiler g:SpotBugsPreCompilerTestCommand |
| 292 | delfunction! s:DefaultPreCompilerTestCommand |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 293 | else |
| 294 | |
| 295 | function! spotbugs#DefaultPreCompilerAction() abort |
| 296 | echomsg printf('Not supported: "%s"', s:compiler) |
| 297 | endfunction |
| 298 | |
| 299 | function! spotbugs#DefaultPreCompilerTestAction() abort |
| 300 | call spotbugs#DefaultPreCompilerAction() |
| 301 | endfunction |
| 302 | |
| 303 | function! spotbugs#DefaultProperties() abort |
| 304 | return {} |
| 305 | endfunction |
| 306 | |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 307 | " XXX: Keep "s:compiler" around for "spotbugs#DefaultPreCompilerAction()", |
| 308 | " "s:DefaultPostCompilerCommand" -- "spotbugs#DefaultPostCompilerAction()". |
| 309 | unlet s:readable g:SpotBugsPreCompilerCommand g:SpotBugsPreCompilerTestCommand |
| 310 | delfunction! s:DefaultPreCompilerCommand |
| 311 | delfunction! s:DefaultPreCompilerTestCommand |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 312 | endif |
| 313 | |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 314 | function! s:DefineBufferAutocmd(event, ...) abort |
| 315 | if !exists('#java_spotbugs#User') |
| 316 | return 1 |
| 317 | endif |
| 318 | |
| 319 | for l:event in insert(copy(a:000), a:event) |
| 320 | if l:event != 'User' |
| 321 | execute printf('silent! autocmd! java_spotbugs %s <buffer>', l:event) |
| 322 | execute printf('autocmd java_spotbugs %s <buffer> doautocmd User', l:event) |
| 323 | endif |
| 324 | endfor |
| 325 | |
| 326 | return 0 |
| 327 | endfunction |
| 328 | |
| 329 | function! s:RemoveBufferAutocmd(event, ...) abort |
| 330 | if !exists('#java_spotbugs') |
| 331 | return 1 |
| 332 | endif |
| 333 | |
| 334 | for l:event in insert(copy(a:000), a:event) |
| 335 | if l:event != 'User' |
| 336 | execute printf('silent! autocmd! java_spotbugs %s <buffer>', l:event) |
| 337 | endif |
| 338 | endfor |
| 339 | |
| 340 | return 0 |
| 341 | endfunction |
| 342 | |
| 343 | " Documented in ":help compiler-spotbugs". |
| 344 | command! -bar -nargs=+ -complete=event SpotBugsDefineBufferAutocmd |
| 345 | \ call s:DefineBufferAutocmd(<f-args>) |
| 346 | command! -bar -nargs=+ -complete=event SpotBugsRemoveBufferAutocmd |
| 347 | \ call s:RemoveBufferAutocmd(<f-args>) |
| 348 | |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 349 | let &cpo = s:save_cpo |
Aliaksei Budavei | 368ef5a | 2024-12-16 21:37:54 +0100 | [diff] [blame] | 350 | unlet s:commands s:state s:save_cpo |
Konfekt | 65311c6 | 2024-11-28 21:06:09 +0100 | [diff] [blame] | 351 | |
| 352 | " vim: set foldmethod=syntax shiftwidth=2 expandtab: |