mirror of
https://github.com/MaskRay/ccls.git
synced 2025-06-08 01:04:54 +00:00
184 lines
5.2 KiB
C++
184 lines
5.2 KiB
C++
// Copyright 2017-2018 ccls Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#pragma once
|
|
|
|
#include "clang_tu.hh"
|
|
#include "lsp.hh"
|
|
#include "project.hh"
|
|
#include "threaded_queue.hh"
|
|
#include "working_files.hh"
|
|
|
|
#include <clang/Frontend/CompilerInstance.h>
|
|
#include <clang/Frontend/FrontendActions.h>
|
|
#include <clang/Sema/CodeCompleteOptions.h>
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace ccls {
|
|
struct PreambleData;
|
|
|
|
struct DiagBase {
|
|
Range range;
|
|
std::string message;
|
|
std::string file;
|
|
clang::DiagnosticsEngine::Level level = clang::DiagnosticsEngine::Note;
|
|
unsigned category;
|
|
bool concerned = false;
|
|
};
|
|
struct Note : DiagBase {};
|
|
struct Diag : DiagBase {
|
|
std::vector<Note> notes;
|
|
std::vector<TextEdit> edits;
|
|
};
|
|
|
|
TextEdit toTextEdit(const clang::SourceManager &SM, const clang::LangOptions &L,
|
|
const clang::FixItHint &FixIt);
|
|
|
|
template <typename K, typename V> struct LruCache {
|
|
std::shared_ptr<V> get(const K &key) {
|
|
for (auto it = items.begin(); it != items.end(); ++it)
|
|
if (it->first == key) {
|
|
auto x = std::move(*it);
|
|
std::move_backward(items.begin(), it, it + 1);
|
|
items[0] = std::move(x);
|
|
return items[0].second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
std::shared_ptr<V> take(const K &key) {
|
|
for (auto it = items.begin(); it != items.end(); ++it)
|
|
if (it->first == key) {
|
|
auto x = std::move(it->second);
|
|
items.erase(it);
|
|
return x;
|
|
}
|
|
return nullptr;
|
|
}
|
|
void insert(const K &key, std::shared_ptr<V> value) {
|
|
if ((int)items.size() >= capacity)
|
|
items.pop_back();
|
|
items.emplace(items.begin(), key, std::move(value));
|
|
}
|
|
void clear() { items.clear(); }
|
|
void setCapacity(int cap) { capacity = cap; }
|
|
|
|
private:
|
|
std::vector<std::pair<K, std::shared_ptr<V>>> items;
|
|
int capacity = 1;
|
|
};
|
|
|
|
struct Session {
|
|
std::mutex mutex;
|
|
std::shared_ptr<PreambleData> preamble;
|
|
|
|
Project::Entry file;
|
|
WorkingFiles *wfiles;
|
|
bool inferred = false;
|
|
|
|
// TODO share
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
|
|
llvm::vfs::getRealFileSystem();
|
|
std::shared_ptr<clang::PCHContainerOperations> pch;
|
|
|
|
Session(const Project::Entry &file, WorkingFiles *wfiles,
|
|
std::shared_ptr<clang::PCHContainerOperations> pch)
|
|
: file(file), wfiles(wfiles), pch(pch) {}
|
|
|
|
std::shared_ptr<PreambleData> getPreamble();
|
|
};
|
|
|
|
struct SemaManager {
|
|
using OnDiagnostic = std::function<void(std::string path,
|
|
std::vector<Diagnostic> diagnostics)>;
|
|
// If OptConsumer is nullptr, the request has been cancelled.
|
|
using OnComplete =
|
|
std::function<void(clang::CodeCompleteConsumer *OptConsumer)>;
|
|
using OnDropped = std::function<void(RequestId request_id)>;
|
|
|
|
struct CompTask {
|
|
CompTask(const RequestId &id, const std::string &path,
|
|
const Position &position,
|
|
std::unique_ptr<clang::CodeCompleteConsumer> Consumer,
|
|
clang::CodeCompleteOptions CCOpts, const OnComplete &on_complete)
|
|
: id(id), path(path), position(position), consumer(std::move(Consumer)),
|
|
cc_opts(CCOpts), on_complete(on_complete) {}
|
|
|
|
RequestId id;
|
|
std::string path;
|
|
Position position;
|
|
std::unique_ptr<clang::CodeCompleteConsumer> consumer;
|
|
clang::CodeCompleteOptions cc_opts;
|
|
OnComplete on_complete;
|
|
};
|
|
struct DiagTask {
|
|
std::string path;
|
|
int64_t wait_until;
|
|
int64_t debounce;
|
|
};
|
|
struct PreambleTask {
|
|
std::string path;
|
|
std::unique_ptr<CompTask> comp_task;
|
|
bool from_diag = false;
|
|
};
|
|
|
|
SemaManager(Project *project, WorkingFiles *wfiles,
|
|
OnDiagnostic on_diagnostic, OnDropped on_dropped);
|
|
|
|
void scheduleDiag(const std::string &path, int debounce);
|
|
void onView(const std::string &path);
|
|
void onSave(const std::string &path);
|
|
void onClose(const std::string &path);
|
|
std::shared_ptr<ccls::Session> ensureSession(const std::string &path,
|
|
bool *created = nullptr);
|
|
void clear();
|
|
void quit();
|
|
|
|
// Global state.
|
|
Project *project_;
|
|
WorkingFiles *wfiles;
|
|
OnDiagnostic on_diagnostic_;
|
|
OnDropped on_dropped_;
|
|
|
|
std::mutex mutex;
|
|
LruCache<std::string, ccls::Session> sessions;
|
|
|
|
std::mutex diag_mutex;
|
|
std::unordered_map<std::string, int64_t> next_diag;
|
|
|
|
ThreadedQueue<std::unique_ptr<CompTask>> comp_tasks;
|
|
ThreadedQueue<DiagTask> diag_tasks;
|
|
ThreadedQueue<PreambleTask> preamble_tasks;
|
|
|
|
std::shared_ptr<clang::PCHContainerOperations> pch;
|
|
};
|
|
|
|
// 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.
|
|
template <typename T> struct CompleteConsumerCache {
|
|
std::mutex mutex;
|
|
std::string path;
|
|
std::string line;
|
|
Position position;
|
|
T result;
|
|
|
|
template <typename Fn> void withLock(Fn &&fn) {
|
|
std::lock_guard lock(mutex);
|
|
fn();
|
|
}
|
|
bool isCacheValid(const std::string &path, const std::string &line,
|
|
Position position) {
|
|
std::lock_guard lock(mutex);
|
|
return this->position == position && this->path == path &&
|
|
this->line.compare(0, position.character, line, 0,
|
|
position.character) == 0;
|
|
}
|
|
};
|
|
} // namespace ccls
|