Add support for parsing compile_commands.json files for C compilers

This commit is contained in:
w0rp 2018-07-29 19:24:19 +01:00
parent a7b8cb4fe3
commit ac4bac8ea4
No known key found for this signature in database
GPG Key ID: 0FC1ECAA8C81CD83
19 changed files with 345 additions and 239 deletions

View File

@ -14,10 +14,10 @@ function! ale_linters#c#clang#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return ale#Escape(ale_linters#c#clang#GetExecutable(a:buffer))
\ . ' -S -x c -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . l:cflags
\ . ale#Var(a:buffer, 'c_clang_options') . ' -'
\ . ' -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -'
endfunction
call ale#linter#Define('c', {

View File

@ -35,7 +35,7 @@ function! s:GetBuildDirectory(buffer) abort
return l:build_dir
endif
return ale#c#FindCompileCommands(a:buffer)
return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endfunction
function! ale_linters#c#clangtidy#GetCommand(buffer) abort

View File

@ -14,10 +14,10 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return ale#Escape(ale_linters#c#gcc#GetExecutable(a:buffer))
\ . ' -S -x c -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . l:cflags
\ . ale#Var(a:buffer, 'c_gcc_options') . ' -'
\ . ' -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'
endfunction
call ale#linter#Define('c', {

View File

@ -14,10 +14,10 @@ function! ale_linters#cpp#clang#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return ale#Escape(ale_linters#cpp#clang#GetExecutable(a:buffer))
\ . ' -S -x c++ -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . l:cflags
\ . ale#Var(a:buffer, 'cpp_clang_options') . ' -'
\ . ' -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {

View File

@ -16,7 +16,7 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:build_dir)
let l:build_dir = ale#c#FindCompileCommands(a:buffer)
let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endif
" The extra arguments in the command are used to prevent .plist files from

View File

@ -29,7 +29,7 @@ function! s:GetBuildDirectory(buffer) abort
return l:build_dir
endif
return ale#c#FindCompileCommands(a:buffer)
return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endfunction
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort

View File

@ -14,10 +14,10 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return ale#Escape(ale_linters#cpp#gcc#GetExecutable(a:buffer))
\ . ' -S -x c++ -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
\ . l:cflags
\ . ale#Var(a:buffer, 'cpp_gcc_options') . ' -'
\ . ' -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {

View File

@ -2,6 +2,7 @@
" Description: Functions for integrating with C-family linters.
call ale#Set('c_parse_makefile', 0)
call ale#Set('c_parse_compile_commands', 0)
let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it.
@ -26,11 +27,11 @@ function! ale#c#FindProjectRoot(buffer) abort
return ''
endfunction
function! ale#c#ParseCFlagsToList(path_prefix, cflags) abort
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
let l:cflags_list = []
let l:previous_options = []
for l:option in a:cflags
for l:option in split(a:cflag_line, '-')
call add(l:previous_options, l:option)
" Check if cflag contained a '-' and should not have been splitted
let l:option_list = split(l:option, '\zs')
@ -62,32 +63,122 @@ function! ale#c#ParseCFlagsToList(path_prefix, cflags) abort
endif
endfor
return l:cflags_list
return join(l:cflags_list, ' ')
endfunction
function! ale#c#ParseCFlags(buffer, stdout_make) abort
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile
return []
return ''
endif
let l:buffer_filename = expand('#' . a:buffer . ':t')
let l:cflags = []
for l:lines in split(a:stdout_make, '\\n')
if stridx(l:lines, l:buffer_filename) >= 0
let l:cflags = split(l:lines, '-')
let l:cflag_line = ''
" Find a line matching this buffer's filename in the make output.
for l:line in a:make_output
if stridx(l:line, l:buffer_filename) >= 0
let l:cflag_line = l:line
break
endif
endfor
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
return ale#c#ParseCFlagsToList(fnamemodify(l:makefile_path, ':p:h'), l:cflags)
let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h')
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
endfunction
" Given a buffer number, find the build subdirectory with compile commands
" The subdirectory is returned without the trailing /
function! ale#c#FindCompileCommands(buffer) abort
" Look above the current source file to find compile_commands.json
let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
if !empty(l:json_file)
return l:json_file
endif
" Search in build directories if we can't find it in the project.
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
for l:dirname in ale#Var(a:buffer, 'c_build_dir_names')
let l:c_build_dir = l:path . s:sep . l:dirname
let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
if filereadable(l:json_file)
return l:json_file
endif
endfor
endfor
return ''
endfunction
" Cache compile_commands.json data in a Dictionary, so we don't need to read
" the same files over and over again. The key in the dictionary will include
" the last modified time of the file.
if !exists('s:compile_commands_cache')
let s:compile_commands_cache = {}
endif
function! s:GetListFromCompileCommandsFile(compile_commands_file) abort
if empty(a:compile_commands_file)
return []
endif
let l:time = getftime(a:compile_commands_file)
if l:time < 0
return []
endif
let l:key = a:compile_commands_file . ':' . l:time
if has_key(s:compile_commands_cache, l:key)
return s:compile_commands_cache[l:key]
endif
let l:data = []
silent! let l:data = json_decode(join(readfile(a:compile_commands_file), ''))
if !empty(l:data)
let s:compile_commands_cache[l:key] = l:data
return l:data
endif
return []
endfunction
function! ale#c#ParseCompileCommandsFlags(buffer, dir, json_list) abort
for l:item in a:json_list
if bufnr(l:item.file) is a:buffer
return ale#c#ParseCFlags(a:dir, l:item.command)
endif
endfor
return ''
endfunction
function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort
let l:dir = ale#path#Dirname(a:compile_commands_file)
let l:json_list = s:GetListFromCompileCommandsFile(a:compile_commands_file)
return ale#c#ParseCompileCommandsFlags(a:buffer, l:dir, l:json_list)
endfunction
function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = ' '
if g:ale_c_parse_makefile && !empty(a:output)
let l:cflags = join(ale#c#ParseCFlags(a:buffer, join(a:output, '\n')), ' ') . ' '
if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif
if ale#Var(a:buffer, 'c_parse_compile_commands')
let l:json_file = ale#c#FindCompileCommands(a:buffer)
if !empty(l:json_file)
let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file)
endif
endif
if l:cflags is# ' '
@ -98,8 +189,9 @@ function! ale#c#GetCFlags(buffer, output) abort
endfunction
function! ale#c#GetMakeCommand(buffer) abort
if g:ale_c_parse_makefile
if ale#Var(a:buffer, 'c_parse_makefile')
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if !empty(l:makefile_path)
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n'
endif
@ -161,19 +253,3 @@ let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])
" Given a buffer number, find the build subdirectory with compile commands
" The subdirectory is returned without the trailing /
function! ale#c#FindCompileCommands(buffer) abort
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
for l:dirname in ale#Var(a:buffer, 'c_build_dir_names')
let l:c_build_dir = l:path . s:sep . l:dirname
if filereadable(l:c_build_dir . '/compile_commands.json')
return l:c_build_dir
endif
endfor
endfor
return ''
endfunction

View File

@ -105,6 +105,21 @@ function! ale#path#GetAbsPath(base_directory, filename) abort
return ale#path#Simplify(a:base_directory . l:sep . a:filename)
endfunction
" Given a path, return the directory name for that path, with no trailing
" slashes. If the argument is empty(), return an empty string.
function! ale#path#Dirname(path) abort
if empty(a:path)
return ''
endif
" For /foo/bar/ we need :h:h to get /foo
if a:path[-1:] is# '/'
return fnamemodify(a:path, ':h:h')
endif
return fnamemodify(a:path, ':h')
endfunction
" Given a buffer number and a relative or absolute path, return 1 if the
" two paths represent the same file on disk.
function! ale#path#IsBufferPath(buffer, complex_filename) abort

View File

@ -25,13 +25,28 @@ g:ale_c_build_dir *g:ale_c_build_dir*
Type: |String|
Default: `''`
A path to the directory containing the `compile_commands.json` file to use
with c-family linters. Usually setting this option to a non-empty string
will override the |g:ale_c_build_dir_names| option to impose a compilation
database (it can be useful if multiple builds are in multiple build
subdirectories in the project tree).
This feature is also most useful for the clang tools linters, wrapped
around LibTooling (namely clang-tidy here)
For programs that can read `compile_commands.json` files, this option can be
set to the directory containing the file for the project. ALE will try to
determine the location of `compile_commands.json` automatically, but if your
file exists in some other directory, you can set this option so ALE will
know where it is.
This directory will be searched instead of |g:ale_c_build_dir_names|.
g:ale_c_parse_compile_commands *g:ale_c_parse_compile_commands*
*b:ale_c_parse_compile_commands*
Type: |Number|
Default: `0`
If set to `1`, ALE will parse `compile_commands.json` files to automatically
determine flags for C or C++ compilers. ALE will first search for the
nearest `compile_commands.json` file, and then look for
`compile_commands.json` files in the directories for
|g:ale_c_build_dir_names|.
If |g:ale_c_parse_makefile| or |b:ale_c_parse_makefile| is set to `1`, the
output of `make -n` will be preferred over `compile_commands.json` files.
g:ale_c_parse_makefile *g:ale_c_parse_makefile*

View File

@ -10,6 +10,7 @@ The following C options also apply to some C++ linters too.
* |g:ale_c_build_dir_names|
* |g:ale_c_build_dir|
* |g:ale_c_parse_makefile|
* |g:ale_c_parse_compile_commands|
===============================================================================

View File

@ -1,4 +1,7 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('c', 'clang')
let b:command_tail = ' -S -x c -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())

View File

@ -1,4 +1,7 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('c', 'gcc')
let b:command_tail = ' -S -x c -fsyntax-only -iquote'

View File

@ -1,4 +1,7 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('cpp', 'clang')
let b:command_tail = ' -S -x c++ -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())

View File

@ -1,4 +1,7 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('cpp', 'gcc')
let b:command_tail = ' -S -x c++ -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())

View File

@ -0,0 +1,161 @@
Before:
Save g:ale_c_parse_makefile
call ale#test#SetDirectory('/testplugin/test')
let g:ale_c_parse_makefile = 1
After:
Restore
call ale#test#RestoreDirectory()
Execute(The CFlags parser should be able to parse include directives):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c'])
Execute(The CFlags parser should be able to parse macro directives):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -DTEST=1',
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=1 -c file.c'])
Execute(The CFlags parser should be able to parse macro directives with spaces):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -DTEST=$(( 2 * 4 ))',
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=$(( 2 * 4 )) -c file.c'])
Execute(The CFlags parser should be able to parse shell directives with spaces):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=`date +%s` -c file.c'])
Execute(ParseCFlags should be able to parse flags with relative paths):
AssertEqual
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Isubdir '
\ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should be able to parse -Dgoal):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Isubdir '
\ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should ignore -T and other arguments):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should handle paths with spaces in double quotes):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should handle paths with spaces in single quotes):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should handle paths with minuses):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I''dir with spaces''' . ' -Idir-with-dash'
\ . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should handle -D with minuses):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -Dmacro-with-dash'
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
\ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-Dmacro-with-dash '
\ . '-I''dir with spaces''' . ' -Idir-with-dash'
\ . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(FlagsFromCompileCommands should tolerate empty values):
AssertEqual '', ale#c#FlagsFromCompileCommands(bufnr(''), '')
Execute(ParseCompileCommandsFlags should tolerate empty values):
AssertEqual '', ale#c#ParseCompileCommandsFlags(bufnr(''), '', [])
Execute(ParseCompileCommandsFlags should parse some basic flags):
noautocmd execute 'file! ' . fnameescape('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')
AssertEqual
\ '-I/usr/include/xmms2',
\ ale#c#ParseCompileCommandsFlags(bufnr(''), '/foo/bar/xmms2-mpris', [
\ {
\ 'directory': '/foo/bar/xmms2-mpris',
\ 'command': '/usr/bin/cc -I/usr/include/xmms2 -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o -c /foo/bar/xmms2-mpris/src/xmms2-mpris.c',
\ 'file': '/foo/bar/xmms2-mpris/src/xmms2-mpris.c'
\ },
\ ])

View File

@ -2,6 +2,7 @@ Before:
" Make sure the c.vim file is loaded first.
call ale#c#FindProjectRoot(bufnr(''))
Save g:ale_c_parse_makefile
Save g:ale_c_gcc_options
Save g:ale_c_clang_options
Save g:ale_cpp_gcc_options
@ -19,6 +20,7 @@ Before:
call ale#test#SetDirectory('/testplugin/test')
let g:ale_c_parse_makefile = 0
let g:ale_c_gcc_options = ''
let g:ale_c_clang_options = ''
let g:ale_cpp_gcc_options = ''

View File

@ -1,184 +0,0 @@
Before:
Save g:ale_c_parse_makefile
Save g:ale_c_gcc_options
Save g:ale_c_clang_options
Save g:ale_cpp_gcc_options
Save g:ale_cpp_clang_options
call ale#test#SetDirectory('/testplugin/test')
let g:ale_c_parse_makefile=1
let g:ale_c_gcc_options = ''
let g:ale_c_clang_options = ''
let g:ale_cpp_gcc_options = ''
let g:ale_cpp_clang_options = ''
After:
Restore
call ale#test#RestoreDirectory()
call ale#linter#Reset()
Execute(The CFlags parser should be able to parse include directives):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))]
\ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -c file.c')
Execute(The CFlags parser should be able to parse macro directives):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ '-DTEST=1']
\ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=1 -c file.c')
Execute(The CFlags parser should be able to parse macro directives with spaces):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ '-DTEST=$(( 2 * 4 ))']
\ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=$(( 2 * 4 )) -c file.c')
Execute(The CFlags parser should be able to parse shell directives with spaces):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=`date +%s` -c file.c')
Execute(The CFlagsToList parser should be able to parse multiple cflags):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Isubdir -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #2):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Isubdir ' .
\ '-I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #3):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ['-Dgoal=9',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Dgoal=9 -Isubdir ' .
\ '-I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #4):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ['-Dgoal=9',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
\ '-I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #5):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ['-Dgoal=9',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
\ '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #6):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ['-Dgoal=9',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
\ '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #7):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ['-Dgoal=9',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
\ '-I''dir with spaces''' . ' -Idir-with-dash' .
\ ' -I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))
Execute(The CFlagsToList parser should be able to parse multiple cflags #8):
runtime! ale_linters/c/gcc.vim
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
\ ['-Dgoal=9',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ '-Dmacro-with-dash',
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')),
\ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ '-DTEST=`date +%s`']
\ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
\ '-Dmacro-with-dash ' .
\ '-I''dir with spaces''' . ' -Idir-with-dash' .
\ ' -I'. ale#path#Simplify('kernel/include') .
\ ' -DTEST=`date +%s` -c file.c', '-'))

View File

@ -0,0 +1,8 @@
Execute(ale#path#Dirname should return empty strings should be returned for empty values):
AssertEqual '', ale#path#Dirname('')
AssertEqual '', ale#path#Dirname(0)
AssertEqual '', ale#path#Dirname(v:null)
Execute(ale#path#Dirname should return the dirname of paths):
AssertEqual '/foo', ale#path#Dirname('/foo/bar')
AssertEqual '/foo', ale#path#Dirname('/foo/bar/')