Fix #3318 - Escape macros when parsing C flags

This commit is contained in:
w0rp 2020-08-27 21:17:24 +01:00
parent 6d843715f3
commit 7545b18ba1
No known key found for this signature in database
GPG Key ID: 0FC1ECAA8C81CD83
2 changed files with 128 additions and 23 deletions

View File

@ -120,10 +120,23 @@ function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort
return l:out_lines
endfunction
" Quote C/C++ a compiler argument, if needed.
"
" Quoting arguments might cause issues with some systems/compilers, so we only
" quote them if we need to.
function! ale#c#QuoteArg(arg) abort
if a:arg !~# '\v[#$&*()\\|[\]{};''"<>/?! ^%]'
return a:arg
endif
return ale#Escape(a:arg)
endfunction
function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
" Expand @file arguments now before parsing
let l:arguments = ale#c#ExpandAtArgs(a:path_prefix, a:raw_arguments)
let l:arguments_to_use = []
" A list of [already_quoted, argument]
let l:items = []
let l:option_index = 0
while l:option_index < len(l:arguments)
@ -149,26 +162,25 @@ function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
if !ale#path#IsAbsolute(l:arg)
let l:rel_path = substitute(l:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:arg = ale#Escape(
\ ale#path#GetAbsPath(a:path_prefix, l:rel_path)
\)
let l:arg = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif
call add(l:arguments_to_use, l:option)
call add(l:arguments_to_use, l:arg)
call add(l:items, [1, l:option])
call add(l:items, [1, ale#Escape(l:arg)])
" Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0
call add(l:arguments_to_use, l:option)
if l:option is# '-D' || l:option is# '-B'
call add(l:arguments_to_use, l:arguments[l:option_index])
call add(l:items, [1, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1
else
call add(l:items, [0, l:option])
endif
" Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:arguments_to_use, l:option)
call add(l:arguments_to_use, l:arguments[l:option_index])
call add(l:items, [0, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1
" Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
@ -180,11 +192,19 @@ function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
\ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0
call add(l:arguments_to_use, l:option)
call add(l:items, [0, l:option])
endif
endwhile
return join(l:arguments_to_use, ' ')
if a:should_quote
" Quote C arguments that haven't already been quoted above.
" If and only if we've been asked to quote them.
call map(l:items, 'v:val[0] ? v:val[1] : ale#c#QuoteArg(v:val[1])')
else
call map(l:items, 'v:val[1]')
endif
return join(l:items, ' ')
endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort

View File

@ -26,7 +26,7 @@ Execute(The CFlags parser should be able to parse include directives):
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c'])
AssertEqual
\ '-isystem ' . '/usr/include/dir',
\ '-isystem ' . ale#Escape('/usr/include/dir'),
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -isystem /usr/include/dir -c file.c'])
Execute(ParseCFlags should ignore -c and -o):
@ -161,7 +161,7 @@ Execute(ParseCompileCommandsFlags should parse some basic flags):
" We should read the absolute path filename entry, not the other ones.
AssertEqual
\ '-I ' . ale#path#Simplify('/usr/include/xmms2'),
\ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@ -211,7 +211,7 @@ Execute(ParseCompileCommandsFlags should fall back to files with the same name):
" We should prefer the basename file flags, not the base dirname flags.
AssertEqual
\ '-I ' . ale#path#Simplify('/usr/include/xmms2'),
\ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@ -243,7 +243,7 @@ Execute(ParseCompileCommandsFlags should parse flags for exact directory matches
" We should ues the exact directory flags, not the file basename flags.
AssertEqual
\ '-I ' . ale#path#Simplify('/usr/include/xmms2'),
\ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@ -283,7 +283,7 @@ Execute(ParseCompileCommandsFlags should fall back to files in the same director
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
AssertEqual
\ '-I ' . ale#path#Simplify('/usr/include/xmms2'),
\ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {},
@ -322,7 +322,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .c files fo
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h'))
AssertEqual
\ '-I /usr/include/xmms2',
\ '-I ' . ale#Escape('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@ -343,7 +343,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .cpp files
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.hpp'))
AssertEqual
\ '-I /usr/include/xmms2',
\ '-I ' . ale#Escape('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@ -365,7 +365,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .cpp files
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h'))
AssertEqual
\ '-I /usr/include/xmms2',
\ '-I ' . ale#Escape('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@ -462,9 +462,10 @@ Execute(We should include several important flags):
\ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
\ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework'))
\ . ' -include ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/foo bar'))
\ . ' -Dmacro=value'
\ . ' -Dmacro="value"'
\ . ' -DGoal=9'
\ . ' -D macro2'
\ . ' -D macro3="value"'
\ . ' -Bbdir'
\ . ' -B bdir2'
\ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3'
@ -490,10 +491,12 @@ Execute(We should include several important flags):
\ 'incframework',
\ '-include',
\ '''foo bar''',
\ '-Dmacro=value',
\ '-Dmacro="value"',
\ '-DGoal=9',
\ '-D',
\ 'macro2',
\ '-D',
\ 'macro3="value"',
\ '-Bbdir',
\ '-B',
\ 'bdir2',
@ -527,6 +530,88 @@ Execute(We should include several important flags):
\ ],
\ )
Execute(We should quote the flags we need to quote):
AssertEqual
\ '-I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/inc'))
\ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include'))
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incquote'))
\ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incsystem'))
\ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
\ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework'))
\ . ' -include ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/foo bar'))
\ . ' ' . ale#Escape('-Dmacro="value"')
\ . ' -DGoal=9'
\ . ' -D macro2'
\ . ' -D ' . ale#Escape('macro3="value"')
\ . ' -Bbdir'
\ . ' -B bdir2'
\ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3'
\ . ' -isysroot sysroot --sysroot=test'
\ . ' ' . ale#Escape('--sysroot="quoted"')
\ . ' ' . ale#Escape('--sysroot=foo bar')
\ . ' --no-sysroot-suffix -imultilib multidir'
\ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi'
\ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++'
\ . ' -iplugindir=dir -march=native -w',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 1,
\ [
\ 'gcc',
\ '-Iinc',
\ '-I',
\ 'include',
\ '-iquote',
\ 'incquote',
\ '-isystem',
\ 'incsystem',
\ '-idirafter',
\ 'incafter',
\ '-iframework',
\ 'incframework',
\ '-include',
\ '''foo bar''',
\ '-Dmacro="value"',
\ '-DGoal=9',
\ '-D',
\ 'macro2',
\ '-D',
\ 'macro3="value"',
\ '-Bbdir',
\ '-B',
\ 'bdir2',
\ '-iprefix',
\ 'prefix',
\ '-iwithprefix',
\ 'prefix2',
\ '-iwithprefixbefore',
\ 'prefix3',
\ '-isysroot',
\ 'sysroot',
\ '--sysroot=test',
\ '--sysroot="quoted"',
\ '--sysroot=foo bar',
\ '--no-sysroot-suffix',
\ '-imultilib',
\ 'multidir',
\ '-Wsome-warning',
\ '-std=c89',
\ '-pedantic',
\ '-pedantic-errors',
\ '-ansi',
\ '-foption',
\ '-O2',
\ '-C',
\ '-CC',
\ '-trigraphs',
\ '-nostdinc',
\ '-nostdinc++',
\ '-iplugindir=dir',
\ '-march=native',
\ '-w',
\ ],
\ )
Execute(We should exclude other flags that cause problems):
AssertEqual
\ '',