From fc6677d40565f4c84730a7cfb0af186f183be031 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Tue, 17 Mar 2020 18:00:47 -0400 Subject: [PATCH] Avoid overriding parsed C/C++ -std=* flag ALE appends flags from {c,cpp}_{clang,gcc}_options after those found by parsing compile_commands.json or Makefile output. If -std=* flags are present in both the ALE flags and parsed flags, the last one present (i.e., ALE's -std=* flag) will determine the mode the compiler works in. This can result in errors showing up in vim but not in the actual build or vice-versa. For example, say you have foo.cpp: #include int main() { return std::is_same_v; } If cpp_clang_options contains -std=c++17 and -std=c++14 is parsed from compile_commands.json, then ALE would end up running something like: clang++ -S -x c++ -fsyntax-only -std=c++14 -std=c++17 - < foo.cpp This would result in no errors showing up in Vim, but the actual build would fail with: :3:14: error: no template named 'is_same_v' in namespace 'std'; did you mean 'is_same'? return std::is_same_v; ~~~~~^~~~~~~~~ is_same /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/type_traits:872:61: note: 'is_same' declared here template struct _LIBCPP_TEMPLATE_VIS is_same : public false_type {}; ^ :3:35: error: expected '(' for function-style cast or type construction return std::is_same_v; ~~~~~~~~~~~~~~~~~~~~~~~~~~^ 2 errors generated. as the actual build would not have the -std=c++17 flag added by ALE. If cpp_clang_options contains -std=c++14 and -std=c++17 is parsed from compile_commands.json, then the opposite problem would occur. ALE would end up running something like: clang++ -S -x c++ -fsyntax-only -std=c++17 -std=c++14 - < foo.cpp and would show an error on line 3 of foo.cpp: [clang] No template named 'is_same_v' in namespace 'std'; did you mean 'is_same'? (fix available) The actual build, on the other hand, would succeed without any complaints. Removing -std=* from ALE's flags if it is already present in the parsed flags ensures that the wrong -std=* flag is not used. An alternative would have been to switch the order in which parsed flags and ALE flags were concatenated when producing the command to execute, but that could prevent a user from intentionally using ALE's flags to override some other flags, e.g. -W* flags to enable/disable warnings in a project whose flags are not under the developer's control. -std=* flags are also present in cuda/nvcc.vim, objc/clang.vim, objcpp/clang.vim, and vhdl/ghdl.vim, but none of those linters appear to parse compile_commands.json or `make` output. --- ale_linters/c/clang.vim | 11 ++++++++++- ale_linters/c/gcc.vim | 11 ++++++++++- ale_linters/cpp/clang.vim | 11 ++++++++++- ale_linters/cpp/gcc.vim | 11 ++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ale_linters/c/clang.vim b/ale_linters/c/clang.vim index 681101fc..84c105de 100644 --- a/ale_linters/c/clang.vim +++ b/ale_linters/c/clang.vim @@ -6,13 +6,22 @@ call ale#Set('c_clang_options', '-std=c11 -Wall') function! ale_linters#c#clang#GetCommand(buffer, output) abort let l:cflags = ale#c#GetCFlags(a:buffer, a:output) + let l:ale_flags = ale#Var(a:buffer, 'c_clang_options') + + if l:cflags =~# '-std=' + let l:ale_flags = substitute( + \ l:ale_flags, + \ '-std=\(c\|gnu\)[0-9]\{2\}', + \ '', + \ 'g') + endif " -iquote with the directory the file is in makes #include work for " headers in the same directory. return '%e -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')) . ' -' + \ . ale#Pad(l:ale_flags) . ' -' endfunction call ale#linter#Define('c', { diff --git a/ale_linters/c/gcc.vim b/ale_linters/c/gcc.vim index 1df1018e..252285a3 100644 --- a/ale_linters/c/gcc.vim +++ b/ale_linters/c/gcc.vim @@ -6,6 +6,15 @@ call ale#Set('c_gcc_options', '-std=c11 -Wall') function! ale_linters#c#gcc#GetCommand(buffer, output) abort let l:cflags = ale#c#GetCFlags(a:buffer, a:output) + let l:ale_flags = ale#Var(a:buffer, 'c_gcc_options') + + if l:cflags =~# '-std=' + let l:ale_flags = substitute( + \ l:ale_flags, + \ '-std=\(c\|gnu\)[0-9]\{2\}', + \ '', + \ 'g') + endif " -iquote with the directory the file is in makes #include work for " headers in the same directory. @@ -16,7 +25,7 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ale#Pad(l:cflags) - \ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -' + \ . ale#Pad(l:ale_flags) . ' -' endfunction call ale#linter#Define('c', { diff --git a/ale_linters/cpp/clang.vim b/ale_linters/cpp/clang.vim index e48291eb..d93638ec 100644 --- a/ale_linters/cpp/clang.vim +++ b/ale_linters/cpp/clang.vim @@ -6,13 +6,22 @@ call ale#Set('cpp_clang_options', '-std=c++14 -Wall') function! ale_linters#cpp#clang#GetCommand(buffer, output) abort let l:cflags = ale#c#GetCFlags(a:buffer, a:output) + let l:ale_flags = ale#Var(a:buffer, 'cpp_clang_options') + + if l:cflags =~# '-std=' + let l:ale_flags = substitute( + \ l:ale_flags, + \ '-std=\(c\|gnu\)++[0-9]\{2\}', + \ '', + \ 'g') + endif " -iquote with the directory the file is in makes #include work for " headers in the same directory. return '%e -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')) . ' -' + \ . ale#Pad(l:ale_flags) . ' -' endfunction call ale#linter#Define('cpp', { diff --git a/ale_linters/cpp/gcc.vim b/ale_linters/cpp/gcc.vim index 108d6d70..89c2d358 100644 --- a/ale_linters/cpp/gcc.vim +++ b/ale_linters/cpp/gcc.vim @@ -6,6 +6,15 @@ call ale#Set('cpp_gcc_options', '-std=c++14 -Wall') function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort let l:cflags = ale#c#GetCFlags(a:buffer, a:output) + let l:ale_flags = ale#Var(a:buffer, 'cpp_gcc_options') + + if l:cflags =~# '-std=' + let l:ale_flags = substitute( + \ l:ale_flags, + \ '-std=\(c\|gnu\)++[0-9]\{2\}', + \ '', + \ 'g') + endif " -iquote with the directory the file is in makes #include work for " headers in the same directory. @@ -16,7 +25,7 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ale#Pad(l:cflags) - \ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -' + \ . ale#Pad(l:ale_flags) . ' -' endfunction call ale#linter#Define('cpp', {