Skip to content

Commit

Permalink
Auto merge of #276 - d0k:argv0, r=Valloric
Browse files Browse the repository at this point in the history
Pass full argv to libclang, including argv[0]

Pass full argv to libclang, including argv[0]. Fixes some long standing issues with finding the standard library on some configurations when using compilation databases.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/valloric/ycmd/276)
<!-- Reviewable:end -->
  • Loading branch information
homu committed Jan 15, 2016
2 parents 90305c7 + 7422bb3 commit f23e372
Show file tree
Hide file tree
Showing 82 changed files with 61 additions and 31 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
43 changes: 28 additions & 15 deletions cpp/ycm/ClangCompleter/TranslationUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace YouCompleteMe {

namespace {

unsigned editingOptions() {
unsigned EditingOptions() {
return CXTranslationUnit_DetailedPreprocessingRecord |
CXTranslationUnit_Incomplete |
CXTranslationUnit_IncludeBriefCommentsInCodeCompletion |
Expand All @@ -44,16 +44,23 @@ unsigned editingOptions() {
clang_defaultEditingTranslationUnitOptions();
}

unsigned reparseOptions( CXTranslationUnit translationUnit ) {
unsigned ReparseOptions( CXTranslationUnit translationUnit ) {
return clang_defaultReparseOptions( translationUnit );
}


unsigned completionOptions() {
unsigned CompletionOptions() {
return clang_defaultCodeCompleteOptions() |
CXCodeComplete_IncludeBriefComments;
}

void EnsureCompilerNamePresent( std::vector< const char * > &flags ) {
bool no_compiler_name_set = !flags.empty() && flags.front()[ 0 ] == '-';

if ( flags.empty() || no_compiler_name_set )
flags.insert( flags.begin(), "clang" );
}

} // unnamed namespace

typedef shared_ptr <
Expand All @@ -78,21 +85,27 @@ TranslationUnit::TranslationUnit(
pointer_flags.push_back( flag.c_str() );
}

EnsureCompilerNamePresent( pointer_flags );

std::vector< CXUnsavedFile > cxunsaved_files =
ToCXUnsavedFiles( unsaved_files );
const CXUnsavedFile *unsaved = cxunsaved_files.size() > 0
? &cxunsaved_files[ 0 ] : NULL;

clang_translation_unit_ = clang_parseTranslationUnit(
clang_index,
filename.c_str(),
&pointer_flags[ 0 ],
pointer_flags.size(),
const_cast<CXUnsavedFile *>( unsaved ),
cxunsaved_files.size(),
editingOptions() );

if ( !clang_translation_unit_ )
// Actually parse the translation unit.
// TODO: Stop stripping argv[0] here and use
// clang_parseTranslationUnit2FullArgv, which is available in libclang 3.8.
CXErrorCode result = clang_parseTranslationUnit2(
clang_index,
filename.c_str(),
&pointer_flags[ 1 ],
pointer_flags.size() - 1,
const_cast<CXUnsavedFile *>( unsaved ),
cxunsaved_files.size(),
EditingOptions(),
&clang_translation_unit_ );

if ( result != CXError_Success )
boost_throw( ClangParseError() );

// Only with a reparse is the preamble precompiled. This issue was fixed
Expand Down Expand Up @@ -179,7 +192,7 @@ std::vector< CompletionData > TranslationUnit::CandidatesForLocation(
column,
const_cast<CXUnsavedFile *>( unsaved ),
cxunsaved_files.size(),
completionOptions() ),
CompletionOptions() ),
clang_disposeCodeCompleteResults );

std::vector< CompletionData > candidates = ToCompletionDataVector(
Expand Down Expand Up @@ -337,7 +350,7 @@ std::string TranslationUnit::GetEnclosingFunctionAtLocation(
void TranslationUnit::Reparse(
std::vector< CXUnsavedFile > &unsaved_files ) {
unsigned options = ( clang_translation_unit_
? reparseOptions( clang_translation_unit_ )
? ReparseOptions( clang_translation_unit_ )
: static_cast<unsigned>( CXReparse_None ) );

Reparse( unsaved_files, options );
Expand Down
6 changes: 1 addition & 5 deletions ycmd/completers/cpp/clang_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.


# Provided for backwards compatibility with old ycm_extra_conf files.
def PrepareClangFlags( flags, filename ):
# When flags come from the compile_commands.json file, the first flag is
# usually the path to the compiler that should be invoked. We want to strip
# that.
if flags and not flags[ 0 ].startswith( '-' ):
return flags[ 1: ]
return flags
11 changes: 9 additions & 2 deletions ycmd/completers/cpp/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def _CompilerToLanguageFlag( flags ):
language = ( 'c++' if CPP_COMPILER_REGEX.search( flags[ 0 ] ) else
'c' )

return [ '-x', language ] + flags[ 1: ]
return flags[ :1 ] + [ '-x', language ] + flags[ 1: ]


def _RemoveUnusedFlags( flags, filename ):
Expand All @@ -242,6 +242,13 @@ def _RemoveUnusedFlags( flags, filename ):

new_flags = []

# When flags come from the compile_commands.json file, the first flag is
# usually the path to the compiler that should be invoked. Directly move it to
# the new_flags list so it doesn't get stripped of in the loop below.
if not flags[ 0 ].startswith( '-' ):
new_flags = flags[ :1 ]
flags = flags[ 1: ]

skip_next = False
previous_flag_is_include = False
previous_flag_starts_with_dash = False
Expand Down Expand Up @@ -300,6 +307,6 @@ def _ExtraClangFlags():
def _SpecialClangIncludes():
libclang_dir = os.path.dirname( ycm_core.__file__ )
path_to_includes = os.path.join( libclang_dir, 'clang_includes' )
return [ '-isystem', path_to_includes ]
return [ '-resource-dir=' + path_to_includes ]


32 changes: 23 additions & 9 deletions ycmd/completers/cpp/tests/flags_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.

from nose.tools import eq_
from nose.tools import ok_
from .. import flags


Expand Down Expand Up @@ -111,45 +112,48 @@ def RemoveUnusedFlags_RemoveMP_test():


def RemoveUnusedFlags_RemoveFilename_test():
expected = [ '-foo', '-bar' ]
expected = [ 'foo', '-bar' ]
to_remove = [ 'file' ]
filename = 'file'

eq_( expected,
flags._RemoveUnusedFlags( expected + to_remove, filename ) )

eq_( expected,
flags._RemoveUnusedFlags( to_remove + expected, filename ) )
flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ 1: ],
filename ) )

eq_( expected,
flags._RemoveUnusedFlags(
expected[ :1 ] + to_remove + expected[ -1: ], filename ) )


def RemoveUnusedFlags_RemoveFlagWithoutPrecedingDashFlag_test():
expected = [ '-foo', '-x', 'c++', '-bar', 'include_dir' ]
expected = [ 'g++', '-foo', '-x', 'c++', '-bar', 'include_dir' ]
to_remove = [ 'unrelated_file' ]
filename = 'file'

eq_( expected,
flags._RemoveUnusedFlags( expected + to_remove, filename ) )

eq_( expected,
flags._RemoveUnusedFlags( to_remove + expected, filename ) )
flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ 1: ],
filename ) )


def RemoveUnusedFlags_RemoveFilenameWithoutPrecedingInclude_test():
def tester( flag ):
expected = [ flag, '/foo/bar', '-isystem/zoo/goo' ]
expected = [ 'clang', flag, '/foo/bar', '-isystem/zoo/goo' ]

eq_( expected,
flags._RemoveUnusedFlags( expected + to_remove, filename ) )

eq_( expected,
flags._RemoveUnusedFlags( to_remove + expected, filename ) )
flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ 1: ],
filename ) )

eq_( expected + expected,
flags._RemoveUnusedFlags( expected + to_remove + expected,
eq_( expected + expected[ 1: ],
flags._RemoveUnusedFlags( expected + to_remove + expected[ 1: ],
filename ) )

include_flags = [ '-isystem', '-I', '-iquote', '--sysroot=', '-isysroot',
Expand Down Expand Up @@ -191,7 +195,7 @@ def _ReplaceCompilerTester( compiler, language ):
expected = [ '-foo', '-bar' ]

for to_remove in to_removes:
eq_( [ '-x', language ] + expected,
eq_( [ compiler, '-x', language ] + expected,
flags._CompilerToLanguageFlag( to_remove + [ compiler ] + expected ) )


Expand All @@ -213,3 +217,13 @@ def CompilerToLanguageFlag_ReplaceCppCompiler_test():

for compiler in compilers:
yield _ReplaceCompilerTester, compiler, 'c++'

def ExtraClangFlags_test():
flags_object = flags.Flags()
num_found = 0
for flag in flags_object.extra_clang_flags:
if flag.startswith( '-resource-dir=' ):
ok_( flag.endswith( 'clang_includes' ) )
num_found += 1

eq_( 1, num_found )

0 comments on commit f23e372

Please sign in to comment.