ccls/src/clang_complete.hh

178 lines
6.0 KiB
C++
Raw Normal View History

2018-08-21 05:27:52 +00:00
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
2018-05-28 00:50:02 +00:00
#include "clang_tu.h"
2018-03-20 02:51:42 +00:00
#include "lru_cache.h"
#include "lsp_completion.h"
#include "lsp_diagnostic.h"
#include "project.h"
#include "threaded_queue.h"
#include "working_files.h"
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
2018-08-29 05:49:53 +00:00
namespace ccls {
struct DiagBase {
Range range;
std::string message;
std::string file;
clang::DiagnosticsEngine::Level level = clang::DiagnosticsEngine::Note;
unsigned category;
bool inside_main = false;
};
struct Note : DiagBase {};
struct Diag : DiagBase {
std::vector<Note> notes;
std::vector<lsTextEdit> edits;
};
struct PreambleData {
2018-08-29 05:49:53 +00:00
PreambleData(clang::PrecompiledPreamble P, std::vector<Diag> diags)
: Preamble(std::move(P)), diags(std::move(diags)) {}
clang::PrecompiledPreamble Preamble;
2018-08-29 05:49:53 +00:00
std::vector<Diag> diags;
};
2017-09-22 01:14:57 +00:00
struct CompletionSession
: public std::enable_shared_from_this<CompletionSession> {
2018-08-29 05:49:53 +00:00
std::mutex mutex;
std::shared_ptr<PreambleData> preamble;
std::vector<Diag> diags;
2017-04-20 05:01:36 +00:00
Project::Entry file;
WorkingFiles *wfiles;
// TODO share
llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> FS =
clang::vfs::getRealFileSystem();
std::shared_ptr<clang::PCHContainerOperations> PCH;
CompletionSession(const Project::Entry &file, WorkingFiles *wfiles,
std::shared_ptr<clang::PCHContainerOperations> PCH)
: file(file), wfiles(wfiles), PCH(PCH) {}
std::shared_ptr<PreambleData> GetPreamble();
void BuildPreamble(clang::CompilerInvocation &CI);
};
2018-08-29 05:49:53 +00:00
}
struct CompletionManager {
2018-08-09 17:08:14 +00:00
using OnDiagnostic = std::function<void(
std::string path, std::vector<lsDiagnostic> diagnostics)>;
using OnComplete = std::function<void(
const std::vector<lsCompletionItem> &results, bool is_cached_result)>;
using OnDropped = std::function<void(lsRequestId request_id)>;
2018-04-14 16:52:17 +00:00
struct PreloadRequest {
2018-08-09 17:08:14 +00:00
PreloadRequest(const std::string &path)
2018-04-14 16:52:17 +00:00
: request_time(std::chrono::high_resolution_clock::now()), path(path) {}
std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
std::string path;
};
struct CompletionRequest {
2018-08-09 17:08:14 +00:00
CompletionRequest(const lsRequestId &id,
const lsTextDocumentIdentifier &document,
const lsPosition &position, const OnComplete &on_complete)
: id(id), document(document), position(position),
2018-04-14 16:52:17 +00:00
on_complete(on_complete) {}
lsRequestId id;
lsTextDocumentIdentifier document;
2018-04-14 16:52:17 +00:00
lsPosition position;
OnComplete on_complete;
};
struct DiagnosticRequest {
lsTextDocumentIdentifier document;
};
CompletionManager(Project *project, WorkingFiles *working_files,
OnDiagnostic on_diagnostic, OnDropped on_dropped);
// Start a code completion at the given location. |on_complete| will run when
// completion results are available. |on_complete| may run on any thread.
2018-08-09 17:08:14 +00:00
void CodeComplete(const lsRequestId &request_id,
const lsTextDocumentPositionParams &completion_location,
const OnComplete &on_complete);
// Request a diagnostics update.
2018-08-09 17:08:14 +00:00
void DiagnosticsUpdate(const lsTextDocumentIdentifier &document);
// Notify the completion manager that |filename| has been viewed and we
// should begin preloading completion data.
void NotifyView(const std::string &path);
// Notify the completion manager that |filename| has been saved. This
// triggers a reparse.
void NotifySave(const std::string &path);
// Notify the completion manager that |filename| has been closed. Any existing
// completion session will be dropped.
void NotifyClose(const std::string &path);
// Ensures there is a completion or preloaded session. Returns true if a new
// session was created.
bool EnsureCompletionOrCreatePreloadSession(const std::string &path);
// Tries to find an edit session for |filename|. This will move the session
// from view to edit.
2018-08-29 05:49:53 +00:00
std::shared_ptr<ccls::CompletionSession>
TryGetSession(const std::string &path, bool mark_as_completion,
2018-08-29 05:49:53 +00:00
bool create_if_needed);
// Flushes all saved sessions with the supplied filename
void FlushSession(const std::string &path);
// Flushes all saved sessions
void FlushAllSessions(void);
// TODO: make these configurable.
const int kMaxPreloadedSessions = 10;
const int kMaxCompletionSessions = 5;
// Global state.
2018-08-09 17:08:14 +00:00
Project *project_;
WorkingFiles *working_files_;
OnDiagnostic on_diagnostic_;
OnDropped on_dropped_;
2018-08-29 05:49:53 +00:00
using LruSessionCache = LruCache<std::string, ccls::CompletionSession>;
// CompletionSession instances which are preloaded, ie, files which the user
// has viewed but not requested code completion for.
LruSessionCache preloaded_sessions_;
// CompletionSession instances which the user has actually performed
// completion on. This is more rare so these instances tend to stay alive
// much longer than the ones in |preloaded_sessions_|.
LruSessionCache completion_sessions_;
// Mutex which protects |view_sessions_| and |edit_sessions_|.
std::mutex sessions_lock_;
// Request a code completion at the given location.
ThreadedQueue<std::unique_ptr<CompletionRequest>> completion_request_;
2018-04-14 16:52:17 +00:00
ThreadedQueue<DiagnosticRequest> diagnostic_request_;
// Parse requests. The path may already be parsed, in which case it should be
// reparsed.
2018-04-14 16:52:17 +00:00
ThreadedQueue<PreloadRequest> preload_requests_;
std::shared_ptr<clang::PCHContainerOperations> PCH;
};
2018-03-31 08:01:32 +00:00
// Cached completion information, so we can give fast completion results when
// the user erases a character. vscode will resend the completion request if
// that happens.
struct CodeCompleteCache {
// NOTE: Make sure to access these variables under |WithLock|.
std::optional<std::string> cached_path_;
std::optional<lsPosition> cached_completion_position_;
std::vector<lsCompletionItem> cached_results_;
std::mutex mutex_;
void WithLock(std::function<void()> action);
bool IsCacheValid(lsTextDocumentPositionParams position);
};