Loading .ycm_clang_options files now
These files can contain flags that are passed to clang.
This commit is contained in:
parent
b703138cac
commit
cdb8dfc86b
@ -21,10 +21,13 @@
|
|||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
#include "CandidateRepository.h"
|
#include "CandidateRepository.h"
|
||||||
#include "ConcurrentLatestValue.h"
|
#include "ConcurrentLatestValue.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "ClangUtils.h"
|
||||||
|
|
||||||
#include <clang-c/Index.h>
|
#include <clang-c/Index.h>
|
||||||
#include <boost/make_shared.hpp>
|
#include <boost/make_shared.hpp>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
using boost::packaged_task;
|
using boost::packaged_task;
|
||||||
using boost::bind;
|
using boost::bind;
|
||||||
using boost::unique_future;
|
using boost::unique_future;
|
||||||
@ -258,7 +261,8 @@ void ClangCompleter::SetFileCompileFlags(
|
|||||||
const std::string &filename,
|
const std::string &filename,
|
||||||
const std::vector< std::string > &flags )
|
const std::vector< std::string > &flags )
|
||||||
{
|
{
|
||||||
flags_for_file_[ filename ] = flags;
|
flags_for_file_[ filename ] =
|
||||||
|
make_shared< std::vector< std::string > >( flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -393,7 +397,14 @@ CXTranslationUnit ClangCompleter::CreateTranslationUnit(
|
|||||||
const std::string &filename,
|
const std::string &filename,
|
||||||
const std::vector< UnsavedFile > &unsaved_files )
|
const std::vector< UnsavedFile > &unsaved_files )
|
||||||
{
|
{
|
||||||
std::vector< const char* > flags = ClangFlagsForFilename( filename );
|
std::vector< const char* > flags = FlagsForFilename( filename );
|
||||||
|
flags.reserve( flags.size() + global_flags_.size() );
|
||||||
|
|
||||||
|
foreach ( const std::string &flag, global_flags_ )
|
||||||
|
{
|
||||||
|
flags.push_back( flag.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
std::vector< CXUnsavedFile > cxunsaved_files = ToCXUnsavedFiles(
|
std::vector< CXUnsavedFile > cxunsaved_files = ToCXUnsavedFiles(
|
||||||
unsaved_files );
|
unsaved_files );
|
||||||
|
|
||||||
@ -408,20 +419,30 @@ CXTranslationUnit ClangCompleter::CreateTranslationUnit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector< const char* > ClangCompleter::ClangFlagsForFilename(
|
// The implementation of this function is somewhat non-obvious because we need
|
||||||
const std::string &filename )
|
// to make sure that the data pointed to by the const char* pointers returned
|
||||||
|
// outlives this function. We want to make sure that we are calling c_str on the
|
||||||
|
// string objects that are actually stored in flags_for_file_
|
||||||
|
std::vector< const char* > ClangCompleter::FlagsForFilename(
|
||||||
|
const std::string &filename)
|
||||||
{
|
{
|
||||||
std::vector< const char* > flags;
|
FlagsForFile::iterator it =
|
||||||
|
flags_for_file_.find( filename );
|
||||||
|
|
||||||
std::vector< std::string > file_flags = flags_for_file_[ filename ];
|
if ( it == flags_for_file_.end() )
|
||||||
flags.reserve( file_flags.size() + global_flags_.size() );
|
|
||||||
|
|
||||||
foreach ( const std::string &flag, global_flags_ )
|
|
||||||
{
|
{
|
||||||
flags.push_back( flag.c_str() );
|
flags_for_file_[ filename ] = make_shared< std::vector< std::string > >(
|
||||||
|
SanitizeClangFlags(
|
||||||
|
SplitFlags(
|
||||||
|
GetNearestClangOptions( filename ) ) ) );
|
||||||
|
|
||||||
|
it = flags_for_file_.find( filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( const std::string &flag, file_flags )
|
// TODO: assert it != end
|
||||||
|
|
||||||
|
std::vector< const char* > flags;
|
||||||
|
foreach ( const std::string &flag, *it->second )
|
||||||
{
|
{
|
||||||
flags.push_back( flag.c_str() );
|
flags.push_back( flag.c_str() );
|
||||||
}
|
}
|
||||||
|
@ -38,13 +38,15 @@ struct CompletionData;
|
|||||||
|
|
||||||
typedef boost::shared_ptr< std::vector< CompletionData > > AsyncCompletions;
|
typedef boost::shared_ptr< std::vector< CompletionData > > AsyncCompletions;
|
||||||
|
|
||||||
typedef boost::unordered_map< std::string, std::vector< std::string > >
|
typedef boost::unordered_map< std::string,
|
||||||
FlagsForFile;
|
boost::shared_ptr<
|
||||||
|
std::vector< std::string > > > FlagsForFile;
|
||||||
|
|
||||||
typedef boost::unordered_map< std::string, CXTranslationUnit >
|
typedef boost::unordered_map< std::string, CXTranslationUnit >
|
||||||
TranslationUnitForFilename;
|
TranslationUnitForFilename;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: document that all filename parameters must be absolute paths
|
||||||
class ClangCompleter : boost::noncopyable
|
class ClangCompleter : boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -84,8 +86,7 @@ private:
|
|||||||
const std::string &filename,
|
const std::string &filename,
|
||||||
const std::vector< UnsavedFile > &unsaved_files );
|
const std::vector< UnsavedFile > &unsaved_files );
|
||||||
|
|
||||||
std::vector< const char* > ClangFlagsForFilename(
|
std::vector< const char* > FlagsForFilename( const std::string &filename );
|
||||||
const std::string &filename );
|
|
||||||
|
|
||||||
CXTranslationUnit GetTranslationUnitForFile(
|
CXTranslationUnit GetTranslationUnitForFile(
|
||||||
const std::string &filename,
|
const std::string &filename,
|
||||||
|
118
cpp/ycm/ClangUtils.cpp
Normal file
118
cpp/ycm/ClangUtils.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
|
||||||
|
//
|
||||||
|
// This file is part of YouCompleteMe.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "ClangUtils.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace YouCompleteMe
|
||||||
|
{
|
||||||
|
|
||||||
|
const char *CLANG_OPTIONS_FILENAME = ".ycm_clang_options";
|
||||||
|
|
||||||
|
std::vector< std::string > SanitizeClangFlags(
|
||||||
|
const std::vector< std::string > &flags )
|
||||||
|
{
|
||||||
|
std::vector< std::string > sanitized_flags = flags;
|
||||||
|
std::vector< std::string >::iterator it = sanitized_flags.begin();
|
||||||
|
|
||||||
|
while ( it != sanitized_flags.end() )
|
||||||
|
{
|
||||||
|
if ( *it == "-arch" )
|
||||||
|
{
|
||||||
|
if ( it + 1 != sanitized_flags.end() )
|
||||||
|
sanitized_flags.erase( it, it + 2 );
|
||||||
|
else
|
||||||
|
sanitized_flags.erase( it, it + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitized_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector< std::string > SplitFlags( const std::string &flags_string )
|
||||||
|
{
|
||||||
|
std::vector< std::string > flags;
|
||||||
|
|
||||||
|
bool in_quotes = false;
|
||||||
|
uint flag_start = 0;
|
||||||
|
uint flag_length = 0;
|
||||||
|
for ( uint i = 0; i < flags_string.size(); ++i )
|
||||||
|
{
|
||||||
|
char current_char = flags_string[ i ];
|
||||||
|
if ( isspace( current_char ) and !in_quotes )
|
||||||
|
{
|
||||||
|
if ( flag_length != 0 )
|
||||||
|
{
|
||||||
|
flags.push_back( flags_string.substr( flag_start, flag_length ) );
|
||||||
|
flag_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag_start = i + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( current_char == '\'' || current_char == '\"' )
|
||||||
|
{
|
||||||
|
in_quotes = !in_quotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
++flag_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( flag_length != 0 )
|
||||||
|
flags.push_back( flags_string.substr( flag_start, flag_length ) );
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string GetNearestClangOptions( const std::string &filename )
|
||||||
|
{
|
||||||
|
fs::path parent_folder = fs::path( filename ).parent_path();
|
||||||
|
fs::path clang_options_filename( CLANG_OPTIONS_FILENAME );
|
||||||
|
|
||||||
|
std::string options_file_contents;
|
||||||
|
fs::path old_parent_folder = parent_folder;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
fs::path current_file = parent_folder / clang_options_filename;
|
||||||
|
if ( fs::exists( current_file ) )
|
||||||
|
{
|
||||||
|
options_file_contents = ReadUtf8File( current_file );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_parent_folder = parent_folder;
|
||||||
|
parent_folder = parent_folder.parent_path();
|
||||||
|
}
|
||||||
|
while ( old_parent_folder != parent_folder );
|
||||||
|
|
||||||
|
return options_file_contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace YouCompleteMe
|
40
cpp/ycm/ClangUtils.h
Normal file
40
cpp/ycm/ClangUtils.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
|
||||||
|
//
|
||||||
|
// This file is part of YouCompleteMe.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CLANGUTILS_H_9MVHQLJS
|
||||||
|
#define CLANGUTILS_H_9MVHQLJS
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace YouCompleteMe
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: move most of the anon funcs in ClangCompleter.cpp to here
|
||||||
|
|
||||||
|
// Removes flags that are either unnecessary or cause clang to crash
|
||||||
|
std::vector< std::string > SanitizeClangFlags(
|
||||||
|
const std::vector< std::string > &flags );
|
||||||
|
|
||||||
|
std::vector< std::string > SplitFlags( const std::string &flags_string );
|
||||||
|
|
||||||
|
std::string GetNearestClangOptions( const std::string &filename );
|
||||||
|
|
||||||
|
} // namespace YouCompleteMe
|
||||||
|
|
||||||
|
#endif /* end of include guard: CLANGUTILS_H_9MVHQLJS */
|
||||||
|
|
@ -18,6 +18,10 @@
|
|||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
namespace YouCompleteMe
|
namespace YouCompleteMe
|
||||||
{
|
{
|
||||||
@ -29,4 +33,26 @@ bool AlmostEqual( double a, double b )
|
|||||||
std::max( std::abs( a ), std::abs( b ) ) );
|
std::max( std::abs( a ), std::abs( b ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string ReadUtf8File( const fs::path &filepath )
|
||||||
|
{
|
||||||
|
fs::ifstream file( filepath, std::ios::in | std::ios::binary );
|
||||||
|
std::vector< char > contents( (std::istreambuf_iterator< char >( file )),
|
||||||
|
std::istreambuf_iterator< char >() );
|
||||||
|
|
||||||
|
if ( contents.size() == 0 )
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
return std::string( contents.begin(), contents.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WriteUtf8File( const fs::path &filepath, const std::string &contents )
|
||||||
|
{
|
||||||
|
fs::ofstream file;
|
||||||
|
file.open( filepath );
|
||||||
|
file << contents;
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace YouCompleteMe
|
} // namespace YouCompleteMe
|
||||||
|
@ -18,15 +18,23 @@
|
|||||||
#ifndef UTILS_H_KEPMRPBH
|
#ifndef UTILS_H_KEPMRPBH
|
||||||
#define UTILS_H_KEPMRPBH
|
#define UTILS_H_KEPMRPBH
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
namespace YouCompleteMe
|
namespace YouCompleteMe
|
||||||
{
|
{
|
||||||
|
|
||||||
bool AlmostEqual( double a, double b );
|
bool AlmostEqual( double a, double b );
|
||||||
|
|
||||||
|
// Reads the entire contents of the specified file. If the file does not exist,
|
||||||
|
// an exception is thrown.
|
||||||
|
std::string ReadUtf8File( const fs::path &filepath );
|
||||||
|
|
||||||
|
// Writes the entire contents of the specified file. If the file does not exist,
|
||||||
|
// an exception is thrown.
|
||||||
|
void WriteUtf8File( const fs::path &filepath, const std::string &contents );
|
||||||
|
|
||||||
template <class Container, class Key>
|
template <class Container, class Key>
|
||||||
typename Container::mapped_type &
|
typename Container::mapped_type &
|
||||||
|
104
cpp/ycm/tests/ClangUtils_test.cpp
Normal file
104
cpp/ycm/tests/ClangUtils_test.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
|
||||||
|
//
|
||||||
|
// This file is part of YouCompleteMe.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "ClangUtils.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::WhenSorted;
|
||||||
|
|
||||||
|
namespace YouCompleteMe
|
||||||
|
{
|
||||||
|
|
||||||
|
extern const char *CLANG_OPTIONS_FILENAME;
|
||||||
|
|
||||||
|
TEST( ClangUtilsTest, SanitizeClangFlagsWorks )
|
||||||
|
{
|
||||||
|
EXPECT_THAT( SanitizeClangFlags( StringVector(
|
||||||
|
"foo",
|
||||||
|
"-arch",
|
||||||
|
"die",
|
||||||
|
"-arch",
|
||||||
|
"die2",
|
||||||
|
"bar" ) ),
|
||||||
|
ElementsAre( "foo",
|
||||||
|
"bar" ) );
|
||||||
|
|
||||||
|
EXPECT_THAT( SanitizeClangFlags( StringVector(
|
||||||
|
"foo",
|
||||||
|
"-arch",
|
||||||
|
"die" ) ),
|
||||||
|
ElementsAre( "foo" ) );
|
||||||
|
|
||||||
|
EXPECT_THAT( SanitizeClangFlags( StringVector(
|
||||||
|
"-arch",
|
||||||
|
"die" ) ),
|
||||||
|
ElementsAre() );
|
||||||
|
|
||||||
|
EXPECT_THAT( SanitizeClangFlags( StringVector(
|
||||||
|
"-arch" ) ),
|
||||||
|
ElementsAre() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST( ClangUtilsTest, SplitFlagsWorks )
|
||||||
|
{
|
||||||
|
EXPECT_THAT( SplitFlags( "-f --bar=qux" ),
|
||||||
|
ElementsAre( "-f",
|
||||||
|
"--bar=qux" ) );
|
||||||
|
|
||||||
|
EXPECT_THAT( SplitFlags( "foo" ),
|
||||||
|
ElementsAre( "foo" ) );
|
||||||
|
|
||||||
|
EXPECT_THAT( SplitFlags( "foo \n\n\t\v bar" ),
|
||||||
|
ElementsAre( "foo",
|
||||||
|
"bar" ) );
|
||||||
|
|
||||||
|
EXPECT_THAT( SplitFlags( " a ' a b c ' q " ),
|
||||||
|
ElementsAre( "a",
|
||||||
|
"' a b c '",
|
||||||
|
"q" ) );
|
||||||
|
|
||||||
|
EXPECT_THAT( SplitFlags( "-I../a/b/c -I\"foo/b/c\" -I\"a c\" -I'a/b/c'" ),
|
||||||
|
ElementsAre( "-I../a/b/c",
|
||||||
|
"-I\"foo/b/c\"",
|
||||||
|
"-I\"a c\"",
|
||||||
|
"-I'a/b/c'" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST( ClangUtilsTest, GetNearestClangOptionsWorks )
|
||||||
|
{
|
||||||
|
fs::path temp_root = fs::temp_directory_path() / fs::unique_path();
|
||||||
|
fs::create_directories( temp_root );
|
||||||
|
|
||||||
|
std::string contents = "foo bar";
|
||||||
|
WriteUtf8File( temp_root / fs::path( CLANG_OPTIONS_FILENAME ), contents );
|
||||||
|
|
||||||
|
fs::path parent = temp_root / fs::unique_path();
|
||||||
|
fs::create_directories( parent );
|
||||||
|
|
||||||
|
EXPECT_STREQ( contents.c_str(),
|
||||||
|
GetNearestClangOptions(
|
||||||
|
( parent / fs::unique_path() ).string() ).c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace YouCompleteMe
|
||||||
|
|
@ -19,6 +19,7 @@
|
|||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include "IdentifierCompleter.h"
|
#include "IdentifierCompleter.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
|
||||||
using ::testing::ElementsAre;
|
using ::testing::ElementsAre;
|
||||||
using ::testing::WhenSorted;
|
using ::testing::WhenSorted;
|
||||||
@ -26,56 +27,19 @@ using ::testing::WhenSorted;
|
|||||||
namespace YouCompleteMe
|
namespace YouCompleteMe
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
std::vector< std::string > Candidates( const std::string &a,
|
|
||||||
const std::string &b = std::string(),
|
|
||||||
const std::string &c = std::string(),
|
|
||||||
const std::string &d = std::string(),
|
|
||||||
const std::string &e = std::string(),
|
|
||||||
const std::string &f = std::string(),
|
|
||||||
const std::string &g = std::string(),
|
|
||||||
const std::string &h = std::string(),
|
|
||||||
const std::string &i = std::string() )
|
|
||||||
{
|
|
||||||
std::vector< std::string > candidates;
|
|
||||||
candidates.push_back( a );
|
|
||||||
if ( !b.empty() )
|
|
||||||
candidates.push_back( b );
|
|
||||||
if ( !c.empty() )
|
|
||||||
candidates.push_back( c );
|
|
||||||
if ( !d.empty() )
|
|
||||||
candidates.push_back( d );
|
|
||||||
if ( !e.empty() )
|
|
||||||
candidates.push_back( e );
|
|
||||||
if ( !f.empty() )
|
|
||||||
candidates.push_back( f );
|
|
||||||
if ( !g.empty() )
|
|
||||||
candidates.push_back( g );
|
|
||||||
if ( !h.empty() )
|
|
||||||
candidates.push_back( h );
|
|
||||||
if ( !i.empty() )
|
|
||||||
candidates.push_back( i );
|
|
||||||
|
|
||||||
return candidates;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // unnamed namespace
|
|
||||||
|
|
||||||
|
|
||||||
// This differs from what we expect from the ClangCompleter. That one should
|
// This differs from what we expect from the ClangCompleter. That one should
|
||||||
// return results for an empty query.
|
// return results for an empty query.
|
||||||
TEST( IdentifierCompleterTest, EmptyQueryNoResults )
|
TEST( IdentifierCompleterTest, EmptyQueryNoResults )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar" ) ).CandidatesForQuery( "" ),
|
"foobar" ) ).CandidatesForQuery( "" ),
|
||||||
ElementsAre() );
|
ElementsAre() );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST( IdentifierCompleterTest, NoDuplicatesReturned )
|
TEST( IdentifierCompleterTest, NoDuplicatesReturned )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar",
|
"foobar",
|
||||||
"foobar",
|
"foobar",
|
||||||
"foobar" ) ).CandidatesForQuery( "foo" ),
|
"foobar" ) ).CandidatesForQuery( "foo" ),
|
||||||
@ -85,14 +49,14 @@ TEST( IdentifierCompleterTest, NoDuplicatesReturned )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, OneCandidate )
|
TEST( IdentifierCompleterTest, OneCandidate )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar" ) ).CandidatesForQuery( "fbr" ),
|
"foobar" ) ).CandidatesForQuery( "fbr" ),
|
||||||
ElementsAre( "foobar" ) );
|
ElementsAre( "foobar" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST( IdentifierCompleterTest, ManyCandidateSimple )
|
TEST( IdentifierCompleterTest, ManyCandidateSimple )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar",
|
"foobar",
|
||||||
"foobartest",
|
"foobartest",
|
||||||
"Foobartest" ) ).CandidatesForQuery( "fbr" ),
|
"Foobartest" ) ).CandidatesForQuery( "fbr" ),
|
||||||
@ -103,7 +67,7 @@ TEST( IdentifierCompleterTest, ManyCandidateSimple )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, FirstCharSameAsQueryWins )
|
TEST( IdentifierCompleterTest, FirstCharSameAsQueryWins )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar",
|
"foobar",
|
||||||
"afoobar" ) ).CandidatesForQuery( "fbr" ),
|
"afoobar" ) ).CandidatesForQuery( "fbr" ),
|
||||||
ElementsAre( "foobar",
|
ElementsAre( "foobar",
|
||||||
@ -112,20 +76,20 @@ TEST( IdentifierCompleterTest, FirstCharSameAsQueryWins )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, CompleteMatchForWordBoundaryCharsWins )
|
TEST( IdentifierCompleterTest, CompleteMatchForWordBoundaryCharsWins )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"FooBarQux",
|
"FooBarQux",
|
||||||
"FBaqux" ) ).CandidatesForQuery( "fbq" ),
|
"FBaqux" ) ).CandidatesForQuery( "fbq" ),
|
||||||
ElementsAre( "FooBarQux",
|
ElementsAre( "FooBarQux",
|
||||||
"FBaqux" ) );
|
"FBaqux" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"CompleterTest",
|
"CompleterTest",
|
||||||
"CompleteMatchForWordBoundaryCharsWins" ) )
|
"CompleteMatchForWordBoundaryCharsWins" ) )
|
||||||
.CandidatesForQuery( "ct" ),
|
.CandidatesForQuery( "ct" ),
|
||||||
ElementsAre( "CompleterTest",
|
ElementsAre( "CompleterTest",
|
||||||
"CompleteMatchForWordBoundaryCharsWins" ) );
|
"CompleteMatchForWordBoundaryCharsWins" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"FooBar",
|
"FooBar",
|
||||||
"FooBarRux" ) ).CandidatesForQuery( "fbr" ),
|
"FooBarRux" ) ).CandidatesForQuery( "fbr" ),
|
||||||
ElementsAre( "FooBarRux",
|
ElementsAre( "FooBarRux",
|
||||||
@ -134,37 +98,37 @@ TEST( IdentifierCompleterTest, CompleteMatchForWordBoundaryCharsWins )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, RatioUtilizationTieBreak )
|
TEST( IdentifierCompleterTest, RatioUtilizationTieBreak )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"aGaaFooBarQux",
|
"aGaaFooBarQux",
|
||||||
"aBaafbq" ) ).CandidatesForQuery( "fbq" ),
|
"aBaafbq" ) ).CandidatesForQuery( "fbq" ),
|
||||||
ElementsAre( "aGaaFooBarQux",
|
ElementsAre( "aGaaFooBarQux",
|
||||||
"aBaafbq" ) );
|
"aBaafbq" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"aFooBarQux",
|
"aFooBarQux",
|
||||||
"afbq" ) ).CandidatesForQuery( "fbq" ),
|
"afbq" ) ).CandidatesForQuery( "fbq" ),
|
||||||
ElementsAre( "aFooBarQux",
|
ElementsAre( "aFooBarQux",
|
||||||
"afbq" ) );
|
"afbq" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"acaaCaaFooGxx",
|
"acaaCaaFooGxx",
|
||||||
"aCaafoog" ) ).CandidatesForQuery( "caafoo" ),
|
"aCaafoog" ) ).CandidatesForQuery( "caafoo" ),
|
||||||
ElementsAre( "acaaCaaFooGxx",
|
ElementsAre( "acaaCaaFooGxx",
|
||||||
"aCaafoog" ) );
|
"aCaafoog" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"acaaCaaFooGxx",
|
"acaaCaaFooGxx",
|
||||||
"aCaafoog" ) ).CandidatesForQuery( "caaFoo" ),
|
"aCaafoog" ) ).CandidatesForQuery( "caaFoo" ),
|
||||||
ElementsAre( "acaaCaaFooGxx",
|
ElementsAre( "acaaCaaFooGxx",
|
||||||
"aCaafoog" ) );
|
"aCaafoog" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"FooBarQux",
|
"FooBarQux",
|
||||||
"FooBarQuxZaa" ) ).CandidatesForQuery( "fbq" ),
|
"FooBarQuxZaa" ) ).CandidatesForQuery( "fbq" ),
|
||||||
ElementsAre( "FooBarQux",
|
ElementsAre( "FooBarQux",
|
||||||
"FooBarQuxZaa" ) );
|
"FooBarQuxZaa" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"FooBar",
|
"FooBar",
|
||||||
"FooBarRux" ) ).CandidatesForQuery( "fba" ),
|
"FooBarRux" ) ).CandidatesForQuery( "fba" ),
|
||||||
ElementsAre( "FooBar",
|
ElementsAre( "FooBar",
|
||||||
@ -173,7 +137,7 @@ TEST( IdentifierCompleterTest, RatioUtilizationTieBreak )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, QueryPrefixOfCandidateWins )
|
TEST( IdentifierCompleterTest, QueryPrefixOfCandidateWins )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar",
|
"foobar",
|
||||||
"fbaroo" ) ).CandidatesForQuery( "foo" ),
|
"fbaroo" ) ).CandidatesForQuery( "foo" ),
|
||||||
ElementsAre( "foobar",
|
ElementsAre( "foobar",
|
||||||
@ -182,26 +146,26 @@ TEST( IdentifierCompleterTest, QueryPrefixOfCandidateWins )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, LowerMatchCharIndexSumWins )
|
TEST( IdentifierCompleterTest, LowerMatchCharIndexSumWins )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"ratio_of_word_boundary_chars_in_query_",
|
"ratio_of_word_boundary_chars_in_query_",
|
||||||
"first_char_same_in_query_and_text_") )
|
"first_char_same_in_query_and_text_") )
|
||||||
.CandidatesForQuery( "charinq" ),
|
.CandidatesForQuery( "charinq" ),
|
||||||
ElementsAre( "first_char_same_in_query_and_text_",
|
ElementsAre( "first_char_same_in_query_and_text_",
|
||||||
"ratio_of_word_boundary_chars_in_query_") );
|
"ratio_of_word_boundary_chars_in_query_") );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"barfooq",
|
"barfooq",
|
||||||
"barquxfoo" ) ).CandidatesForQuery( "foo" ),
|
"barquxfoo" ) ).CandidatesForQuery( "foo" ),
|
||||||
ElementsAre( "barfooq",
|
ElementsAre( "barfooq",
|
||||||
"barquxfoo") );
|
"barquxfoo") );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"xxxxxxabc",
|
"xxxxxxabc",
|
||||||
"xxabcxxxx" ) ).CandidatesForQuery( "abc" ),
|
"xxabcxxxx" ) ).CandidatesForQuery( "abc" ),
|
||||||
ElementsAre( "xxabcxxxx",
|
ElementsAre( "xxabcxxxx",
|
||||||
"xxxxxxabc") );
|
"xxxxxxabc") );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"FooBarQux",
|
"FooBarQux",
|
||||||
"FaBarQux" ) ).CandidatesForQuery( "fbq" ),
|
"FaBarQux" ) ).CandidatesForQuery( "fbq" ),
|
||||||
ElementsAre( "FaBarQux",
|
ElementsAre( "FaBarQux",
|
||||||
@ -210,13 +174,13 @@ TEST( IdentifierCompleterTest, LowerMatchCharIndexSumWins )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, ShorterCandidateWins )
|
TEST( IdentifierCompleterTest, ShorterCandidateWins )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"CompleterT",
|
"CompleterT",
|
||||||
"CompleterTest" ) ).CandidatesForQuery( "co" ),
|
"CompleterTest" ) ).CandidatesForQuery( "co" ),
|
||||||
ElementsAre( "CompleterT",
|
ElementsAre( "CompleterT",
|
||||||
"CompleterTest" ) );
|
"CompleterTest" ) );
|
||||||
|
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"CompleterT",
|
"CompleterT",
|
||||||
"CompleterTest" ) ).CandidatesForQuery( "plet" ),
|
"CompleterTest" ) ).CandidatesForQuery( "plet" ),
|
||||||
ElementsAre( "CompleterT",
|
ElementsAre( "CompleterT",
|
||||||
@ -225,7 +189,7 @@ TEST( IdentifierCompleterTest, ShorterCandidateWins )
|
|||||||
|
|
||||||
TEST( IdentifierCompleterTest, SameLowercaseCandidateWins )
|
TEST( IdentifierCompleterTest, SameLowercaseCandidateWins )
|
||||||
{
|
{
|
||||||
EXPECT_THAT( IdentifierCompleter( Candidates(
|
EXPECT_THAT( IdentifierCompleter( StringVector(
|
||||||
"foobar",
|
"foobar",
|
||||||
"Foobar" ) ).CandidatesForQuery( "foo" ),
|
"Foobar" ) ).CandidatesForQuery( "foo" ),
|
||||||
ElementsAre( "foobar",
|
ElementsAre( "foobar",
|
||||||
|
56
cpp/ycm/tests/TestUtils.cpp
Normal file
56
cpp/ycm/tests/TestUtils.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
|
||||||
|
//
|
||||||
|
// This file is part of YouCompleteMe.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "TestUtils.h"
|
||||||
|
|
||||||
|
namespace YouCompleteMe
|
||||||
|
{
|
||||||
|
|
||||||
|
std::vector< std::string > StringVector( const std::string &a,
|
||||||
|
const std::string &b,
|
||||||
|
const std::string &c,
|
||||||
|
const std::string &d,
|
||||||
|
const std::string &e,
|
||||||
|
const std::string &f,
|
||||||
|
const std::string &g,
|
||||||
|
const std::string &h,
|
||||||
|
const std::string &i )
|
||||||
|
{
|
||||||
|
std::vector< std::string > string_vector;
|
||||||
|
string_vector.push_back( a );
|
||||||
|
if ( !b.empty() )
|
||||||
|
string_vector.push_back( b );
|
||||||
|
if ( !c.empty() )
|
||||||
|
string_vector.push_back( c );
|
||||||
|
if ( !d.empty() )
|
||||||
|
string_vector.push_back( d );
|
||||||
|
if ( !e.empty() )
|
||||||
|
string_vector.push_back( e );
|
||||||
|
if ( !f.empty() )
|
||||||
|
string_vector.push_back( f );
|
||||||
|
if ( !g.empty() )
|
||||||
|
string_vector.push_back( g );
|
||||||
|
if ( !h.empty() )
|
||||||
|
string_vector.push_back( h );
|
||||||
|
if ( !i.empty() )
|
||||||
|
string_vector.push_back( i );
|
||||||
|
|
||||||
|
return string_vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace YouCompleteMe
|
||||||
|
|
40
cpp/ycm/tests/TestUtils.h
Normal file
40
cpp/ycm/tests/TestUtils.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
|
||||||
|
//
|
||||||
|
// This file is part of YouCompleteMe.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// YouCompleteMe is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef TESTUTILS_H_G4RKMGUD
|
||||||
|
#define TESTUTILS_H_G4RKMGUD
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace YouCompleteMe
|
||||||
|
{
|
||||||
|
|
||||||
|
std::vector< std::string > StringVector( const std::string &a,
|
||||||
|
const std::string &b = std::string(),
|
||||||
|
const std::string &c = std::string(),
|
||||||
|
const std::string &d = std::string(),
|
||||||
|
const std::string &e = std::string(),
|
||||||
|
const std::string &f = std::string(),
|
||||||
|
const std::string &g = std::string(),
|
||||||
|
const std::string &h = std::string(),
|
||||||
|
const std::string &i = std::string() );
|
||||||
|
|
||||||
|
} // namespace YouCompleteMe
|
||||||
|
|
||||||
|
#endif /* end of include guard: TESTUTILS_H_G4RKMGUD */
|
||||||
|
|
@ -121,6 +121,7 @@ class ClangCompleter( Completer ):
|
|||||||
self.contents_holder = []
|
self.contents_holder = []
|
||||||
self.filename_holder = []
|
self.filename_holder = []
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsync( self, query ):
|
def CandidatesForQueryAsync( self, query ):
|
||||||
# TODO: sanitize query
|
# TODO: sanitize query
|
||||||
files = indexer.UnsavedFileVec()
|
files = indexer.UnsavedFileVec()
|
||||||
@ -164,6 +165,11 @@ class ClangCompleter( Completer ):
|
|||||||
return [ CompletionDataToDict( x ) for x in self.future.GetResults() ]
|
return [ CompletionDataToDict( x ) for x in self.future.GetResults() ]
|
||||||
|
|
||||||
|
|
||||||
|
def OnFileEnter( self ):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def GetUnsavedBuffers():
|
def GetUnsavedBuffers():
|
||||||
def BufferModified( buffer_number ):
|
def BufferModified( buffer_number ):
|
||||||
to_eval = 'getbufvar({0}, "&mod")'.format( buffer_number )
|
to_eval = 'getbufvar({0}, "&mod")'.format( buffer_number )
|
||||||
|
Loading…
Reference in New Issue
Block a user