All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 " Author: farenjihn <farenjihn@gmail.com>, w0rp <devw0rp@gmail.com>
2 " Description: Lints java files using javac
4 let s:classpath_sep = has('unix') ? ':' : ';'
6 call ale#Set('java_javac_executable', 'javac')
7 call ale#Set('java_javac_options', '')
8 call ale#Set('java_javac_classpath', '')
9 call ale#Set('java_javac_sourcepath', '')
11 function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
12 let [l:cwd, l:command] = ale#maven#BuildClasspathCommand(a:buffer)
14 " Try to use Gradle if Maven isn't available.
16 let [l:cwd, l:command] = ale#gradle#BuildClasspathCommand(a:buffer)
19 " Try to use Ant if Gradle and Maven aren't available
21 let [l:cwd, l:command] = ale#ant#BuildClasspathCommand(a:buffer)
25 return ale_linters#java#javac#GetCommand(a:buffer, [], {})
28 return ale#command#Run(
31 \ function('ale_linters#java#javac#GetCommand'),
36 function! s:BuildClassPathOption(buffer, import_paths) abort
37 " Filter out lines like [INFO], etc.
38 let l:class_paths = filter(a:import_paths[:], 'v:val !~# ''[''')
39 let l:cls_path = ale#Var(a:buffer, 'java_javac_classpath')
41 if !empty(l:cls_path) && type(l:cls_path) is v:t_string
42 call extend(l:class_paths, split(l:cls_path, s:classpath_sep))
45 if !empty(l:cls_path) && type(l:cls_path) is v:t_list
46 call extend(l:class_paths, l:cls_path)
49 return !empty(l:class_paths)
50 \ ? '-cp ' . ale#Escape(join(l:class_paths, s:classpath_sep))
54 function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort
55 let l:cp_option = s:BuildClassPathOption(a:buffer, a:import_paths)
58 " Find the src directory, for files in this project.
59 let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java')
63 call add(l:sp_dirs, l:src_dir)
65 " Automatically include the jaxb directory too, if it's there.
66 let l:jaxb_dir = fnamemodify(l:src_dir, ':h:h')
67 \ . (has('win32') ? '\jaxb\' : '/jaxb/')
69 if isdirectory(l:jaxb_dir)
70 call add(l:sp_dirs, l:jaxb_dir)
74 " Automatically include the test directory, but only for test code.
75 if expand('#' . a:buffer . ':p') =~? '\vsrc[/\\]test[/\\]java'
76 let l:test_dir = ale#path#FindNearestDirectory(a:buffer, 'src/test/java')
78 if isdirectory(l:test_dir)
79 call add(l:sp_dirs, l:test_dir)
83 let l:source_paths = []
84 let l:source_path = ale#Var(a:buffer, 'java_javac_sourcepath')
86 if !empty(l:source_path) && type(l:source_path) is v:t_string
87 let l:source_paths = split(l:source_path, s:classpath_sep)
90 if !empty(l:source_path) && type(l:source_path) is v:t_list
91 let l:source_paths = l:source_path
94 if !empty(l:source_paths)
95 for l:path in l:source_paths
96 let l:sp_path = ale#path#FindNearestDirectory(a:buffer, l:path)
99 call add(l:sp_dirs, l:sp_path)
105 let l:sp_option = '-sourcepath '
106 \ . ale#Escape(join(l:sp_dirs, s:classpath_sep))
109 " Create .class files in a temporary directory, which we will delete later.
110 let l:class_file_directory = ale#command#CreateDirectory(a:buffer)
112 " Always run javac from the directory the file is in, so we can resolve
113 " relative paths correctly.
115 \ . ale#Pad(l:cp_option)
116 \ . ale#Pad(l:sp_option)
117 \ . ' -d ' . ale#Escape(l:class_file_directory)
118 \ . ale#Pad(ale#Var(a:buffer, 'java_javac_options'))
122 function! ale_linters#java#javac#Handle(buffer, lines) abort
123 " Look for lines like the following.
125 " Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
126 " Main.java:16: error: ';' expected
127 let l:directory = expand('#' . a:buffer . ':p:h')
128 let l:pattern = '\v^(.*):(\d+): (.{-1,}):(.+)$'
129 let l:col_pattern = '\v^(\s*\^)$'
130 let l:symbol_pattern = '\v^ +symbol: *(class|method) +([^ ]+)'
133 for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:col_pattern, l:symbol_pattern])
134 if empty(l:match[2]) && empty(l:match[3])
135 if !empty(l:match[1]) && !empty(l:output)
136 let l:output[-1].col = len(l:match[1])
138 elseif empty(l:match[3])
139 " Add symbols to 'cannot find symbol' errors.
140 if l:output[-1].text is# 'error: cannot find symbol'
141 let l:output[-1].text .= ': ' . l:match[2]
145 \ 'filename': ale#path#GetAbsPath(l:directory, l:match[1]),
146 \ 'lnum': l:match[2] + 0,
147 \ 'text': l:match[3] . ':' . l:match[4],
148 \ 'type': l:match[3] is# 'error' ? 'E' : 'W',
156 call ale#linter#Define('java', {
158 \ 'executable': {b -> ale#Var(b, 'java_javac_executable')},
160 \ 'command': function('ale_linters#java#javac#RunWithImportPaths'),
161 \ 'output_stream': 'stderr',
162 \ 'callback': 'ale_linters#java#javac#Handle',