YouCompleteMe/cpp/ycm/ClangCompleter.h
Strahinja Val Markovic f88c9feb4f Refactored the clang completer; many bugs fixed
This change should fix the random hangs and segfaults when using the clang
completer. Also, assertion errors printed to the console on vim exit should go
away too, same thing with segfaults on vim exit. These "on exit" errors were
caused by not cleanly shutting down the background threads; both the identifier
completer and the clang one now join the threads on destruction. This results in
a clean shutdown.

The new clang completer architecture now uses only one clang thread (again)
instead of a completion and parsing thread. Since the parsing task needs to wait
on the completion task if it was started first (and vice-versa) there's no point
to using two threads. The desired "simplicity" of using two threads for these
two tasks actually created needless complexity (and bugs). Sigh. Such is life.

A TranslationUnit abstraction was also created and this in turn also reduces the
complexity of the clang completer.

The clang completer now also has some (very) basic tests.
2012-08-11 19:37:08 -07:00

167 lines
5.1 KiB
C++

// 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 CLANGCOMPLETE_H_WLKDU0ZV
#define CLANGCOMPLETE_H_WLKDU0ZV
#include "ConcurrentLatestValue.h"
#include "Future.h"
#include "UnsavedFile.h"
#include "Diagnostic.h"
#include <boost/utility.hpp>
#include <boost/unordered_map.hpp>
#include <string>
typedef void *CXIndex;
typedef struct CXTranslationUnitImpl *CXTranslationUnit;
namespace YouCompleteMe
{
class CandidateRepository;
class TranslationUnit;
struct CompletionData;
typedef boost::shared_ptr< std::vector< CompletionData > > AsyncCompletions;
typedef boost::unordered_map< std::string,
boost::shared_ptr<
std::vector< std::string > > > FlagsForFile;
typedef boost::unordered_map< std::string,
boost::shared_ptr< TranslationUnit > > TranslationUnitForFilename;
// TODO: document that all filename parameters must be absolute paths
class ClangCompleter : boost::noncopyable
{
public:
ClangCompleter();
~ClangCompleter();
void EnableThreading();
std::vector< Diagnostic > DiagnosticsForFile( const std::string &filename );
bool UpdatingTranslationUnit( const std::string &filename );
// Public because of unit tests (gtest is not very thread-friendly)
void UpdateTranslationUnit(
const std::string &filename,
const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags );
// NOTE: params are taken by value on purpose! With a C++11 compiler we can
// avoid internal copies if params are taken by value (move ctors FTW)
void UpdateTranslationUnitAsync(
std::string filename,
std::vector< UnsavedFile > unsaved_files,
std::vector< std::string > flags );
// Public because of unit tests (gtest is not very thread-friendly)
std::vector< CompletionData > CandidatesForLocationInFile(
const std::string &filename,
int line,
int column,
const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags );
// NOTE: params are taken by value on purpose! With a C++11 compiler we can
// avoid internal copies if params are taken by value (move ctors FTW)
Future< AsyncCompletions > CandidatesForQueryAndLocationInFileAsync(
std::string query,
std::string filename,
int line,
int column,
std::vector< UnsavedFile > unsaved_files,
std::vector< std::string > flags );
private:
// This is basically a union. Only one of the two tasks is set to something
// valid, the other task is invalid. Which one is valid depends on the caller.
struct ClangPackagedTask
{
boost::packaged_task< AsyncCompletions > completions_task_;
boost::packaged_task< void > parsing_task_;
};
typedef ConcurrentLatestValue<
boost::shared_ptr<
boost::packaged_task< AsyncCompletions > > > LatestSortingTask;
typedef ConcurrentLatestValue<
boost::shared_ptr< ClangPackagedTask > > LatestClangTask;
boost::shared_ptr< TranslationUnit > GetTranslationUnitForFile(
const std::string &filename,
const std::vector< UnsavedFile > &unsaved_files,
const std::vector< std::string > &flags );
std::vector< CompletionData > SortCandidatesForQuery(
const std::string &query,
const std::vector< CompletionData > &completion_datas );
void InitThreads();
void ClangThreadMain();
void SortingThreadMain();
/////////////////////////////
// PRIVATE MEMBER VARIABLES
/////////////////////////////
CXIndex clang_index_;
TranslationUnitForFilename filename_to_translation_unit_;
boost::mutex filename_to_translation_unit_mutex_;
CandidateRepository &candidate_repository_;
bool threading_enabled_;
bool time_to_die_;
boost::shared_mutex time_to_die_mutex_;
// TODO: use boost.atomic for clang_data_ready_
bool clang_data_ready_;
boost::mutex clang_data_ready_mutex_;
boost::condition_variable clang_data_ready_condition_variable_;
std::vector< CompletionData > latest_clang_results_;
boost::shared_mutex latest_clang_results_shared_mutex_;
// Unfortunately clang is not thread-safe so we need to be careful when we
// access it. Only one thread at a time is allowed to access any single
// translation unit.
boost::thread clang_thread_;
boost::thread_group sorting_threads_;
mutable LatestClangTask clang_task_;
mutable LatestSortingTask sorting_task_;
};
} // namespace YouCompleteMe
#endif /* end of include guard: CLANGCOMPLETE_H_WLKDU0ZV */