Port SelectionTree from clangd to clice (#166)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -134,6 +134,10 @@ auto CompilationUnit::expansion_location(clang::SourceLocation location) -> clan
|
||||
return impl->src_mgr.getExpansionLoc(location);
|
||||
}
|
||||
|
||||
auto CompilationUnit::file_location(clang::SourceLocation location) -> clang::SourceLocation {
|
||||
return impl->src_mgr.getFileLoc(location);
|
||||
}
|
||||
|
||||
auto CompilationUnit::include_location(clang::FileID fid) -> clang::SourceLocation {
|
||||
return impl->src_mgr.getIncludeLoc(fid);
|
||||
}
|
||||
@@ -142,15 +146,34 @@ auto CompilationUnit::presumed_location(clang::SourceLocation location) -> clang
|
||||
return impl->src_mgr.getPresumedLoc(location, false);
|
||||
}
|
||||
|
||||
auto CompilationUnit::create_location(clang::FileID fid, std::uint32_t offset)
|
||||
-> clang::SourceLocation {
|
||||
return impl->src_mgr.getComposedLoc(fid, offset);
|
||||
}
|
||||
|
||||
auto CompilationUnit::spelled_tokens(clang::FileID fid) -> llvm::ArrayRef<clang::syntax::Token> {
|
||||
return impl->buffer->spelledTokens(fid);
|
||||
}
|
||||
|
||||
auto CompilationUnit::spelled_tokens_touch(clang::SourceLocation location)
|
||||
-> llvm::ArrayRef<clang::syntax::Token> {
|
||||
return clang::syntax::spelledTokensTouching(location, *impl->buffer);
|
||||
}
|
||||
|
||||
auto CompilationUnit::expanded_tokens() -> llvm::ArrayRef<clang::syntax::Token> {
|
||||
return impl->buffer->expandedTokens();
|
||||
}
|
||||
|
||||
auto CompilationUnit::expanded_tokens(clang::SourceRange range)
|
||||
-> llvm::ArrayRef<clang::syntax::Token> {
|
||||
return impl->buffer->expandedTokens(range);
|
||||
}
|
||||
|
||||
auto CompilationUnit::expansions_overlapping(llvm::ArrayRef<clang::syntax::Token> spelled_tokens)
|
||||
-> std::vector<clang::syntax::TokenBuffer::Expansion> {
|
||||
return impl->buffer->expansionsOverlapping(spelled_tokens);
|
||||
}
|
||||
|
||||
auto CompilationUnit::token_length(clang::SourceLocation location) -> std::uint32_t {
|
||||
return clang::Lexer::MeasureTokenLength(location, impl->src_mgr, impl->instance->getLangOpts());
|
||||
}
|
||||
@@ -273,4 +296,8 @@ clang::ASTContext& CompilationUnit::context() {
|
||||
return impl->instance->getASTContext();
|
||||
}
|
||||
|
||||
clang::syntax::TokenBuffer& CompilationUnit::token_buffer() {
|
||||
return *impl->buffer;
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -60,80 +60,6 @@ std::string getSourceCode(CompilationUnit& unit, const clang::NamedDecl* decl) {
|
||||
return "";
|
||||
}
|
||||
|
||||
struct HoversStorage : Hovers {
|
||||
llvm::DenseMap<const void*, uint32_t> cache;
|
||||
|
||||
void add(CompilationUnit& unit, const clang::NamedDecl* decl, LocalSourceRange range) {
|
||||
auto [iter, success] = cache.try_emplace(decl, hovers.size());
|
||||
if(success) {
|
||||
hovers.emplace_back(hover(unit, decl));
|
||||
}
|
||||
occurrences.emplace_back(range, iter->second);
|
||||
}
|
||||
|
||||
void sort() {
|
||||
std::vector<uint32_t> hoverMap(hovers.size());
|
||||
|
||||
{
|
||||
std::vector<uint32_t> new2old(hovers.size());
|
||||
for(uint32_t i = 0; i < hovers.size(); ++i) {
|
||||
new2old[i] = i;
|
||||
}
|
||||
|
||||
ranges::sort(views::zip(hovers, new2old), refl::less, [](const auto& element) {
|
||||
return std::get<0>(element);
|
||||
});
|
||||
|
||||
for(uint32_t i = 0; i < hovers.size(); ++i) {
|
||||
hoverMap[new2old[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& occurrence: occurrences) {
|
||||
occurrence.index = hoverMap[occurrence.index];
|
||||
}
|
||||
|
||||
ranges::sort(occurrences, refl::less, [](const auto& item) { return item.range; });
|
||||
}
|
||||
};
|
||||
|
||||
/// For index all hover information in the given unit.
|
||||
class HoverCollector : public SemanticVisitor<HoverCollector> {
|
||||
public:
|
||||
HoverCollector(CompilationUnit& unit) : SemanticVisitor<HoverCollector>(unit, false) {}
|
||||
|
||||
void handleDeclOccurrence(const clang::NamedDecl* decl,
|
||||
RelationKind kind,
|
||||
clang::SourceLocation location) {
|
||||
/// FIXME: Currently we only handle file location.
|
||||
if(location.isMacroID()) {
|
||||
return;
|
||||
}
|
||||
|
||||
decl = normalize(decl);
|
||||
|
||||
auto [fid, range] = unit.decompose_range(location);
|
||||
auto& file = files[fid];
|
||||
file.add(unit, decl, range);
|
||||
}
|
||||
|
||||
auto build() {
|
||||
index::Shared<Hovers> hovers;
|
||||
|
||||
run();
|
||||
|
||||
for(auto& [fid, storage]: files) {
|
||||
storage.sort();
|
||||
hovers[fid] = std::move(static_cast<Hovers&>(storage));
|
||||
}
|
||||
|
||||
return hovers;
|
||||
}
|
||||
|
||||
private:
|
||||
index::Shared<HoversStorage> files;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Hover hover(CompilationUnit& unit, const clang::NamedDecl* decl) {
|
||||
@@ -147,9 +73,21 @@ Hover hover(CompilationUnit& unit, const clang::NamedDecl* decl) {
|
||||
};
|
||||
}
|
||||
|
||||
index::Shared<Hovers> indexHover(CompilationUnit& unit) {
|
||||
HoverCollector collector(unit);
|
||||
return collector.build();
|
||||
Hover hover(CompilationUnit& unit, std::uint32_t offset) {
|
||||
Hover info;
|
||||
|
||||
auto tree = SelectionTree::create_right(unit, {offset, offset});
|
||||
if(auto node = tree.common_ancestor()) {
|
||||
if(auto decl = node->get<clang::NamedDecl>()) {
|
||||
return hover(unit, decl);
|
||||
} else if(auto ref = node->get<clang::DeclRefExpr>()) {
|
||||
return hover(unit, ref->getDecl());
|
||||
}
|
||||
|
||||
/// TODO: add ....
|
||||
}
|
||||
|
||||
return Hover{};
|
||||
}
|
||||
|
||||
} // namespace clice::feature
|
||||
|
||||
@@ -1,20 +1,47 @@
|
||||
#include "Server/Server.h"
|
||||
#include "Server/Convert.h"
|
||||
#include "Compiler/Compilation.h"
|
||||
#include "Feature/Hover.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
async::Task<json::Value> Server::on_hover(proto::HoverParams params) {
|
||||
auto path = mapping.to_path(params.textDocument.uri);
|
||||
|
||||
auto opening_file = &opening_files[path];
|
||||
auto guard = co_await opening_file->ast_built_lock.try_lock();
|
||||
|
||||
auto offset = to_offset(kind, opening_file->content, params.position);
|
||||
|
||||
opening_file = &opening_files[path];
|
||||
auto content = opening_file->content;
|
||||
auto ast = opening_file->ast;
|
||||
if(!ast) {
|
||||
co_return json::Value(nullptr);
|
||||
}
|
||||
|
||||
co_return co_await async::submit([kind = this->kind, offset, &ast] {
|
||||
auto hover = feature::hover(*ast, offset);
|
||||
|
||||
proto::Hover result;
|
||||
result.contents.kind = "markdown";
|
||||
result.contents.value = std::format("{}: {}", hover.kind.name(), hover.name);
|
||||
|
||||
return json::serialize(result);
|
||||
});
|
||||
}
|
||||
|
||||
async::Task<json::Value> Server::on_semantic_token(proto::SemanticTokensParams params) {
|
||||
auto path = mapping.to_path(params.textDocument.uri);
|
||||
|
||||
auto openFile = &opening_files[path];
|
||||
auto guard = co_await openFile->ast_built_lock.try_lock();
|
||||
auto opening_file = &opening_files[path];
|
||||
auto guard = co_await opening_file->ast_built_lock.try_lock();
|
||||
|
||||
openFile = &opening_files[path];
|
||||
auto content = openFile->content;
|
||||
auto ast = openFile->ast;
|
||||
opening_file = &opening_files[path];
|
||||
auto content = opening_file->content;
|
||||
auto ast = opening_file->ast;
|
||||
if(!ast) {
|
||||
co_return "";
|
||||
co_return json::Value(nullptr);
|
||||
}
|
||||
|
||||
co_return co_await async::submit([kind = this->kind, &ast] {
|
||||
|
||||
@@ -39,6 +39,9 @@ async::Task<json::Value> Server::on_initialize(proto::InitializeParams params) {
|
||||
capabilities.textDocumentSync.change = proto::TextDocumentSyncKind::Full;
|
||||
capabilities.textDocumentSync.save = true;
|
||||
|
||||
/// Hover
|
||||
capabilities.hoverProvider = true;
|
||||
|
||||
/// Completion
|
||||
capabilities.completionProvider.triggerCharacters = {".", "<", ">", ":", "\"", "/", "*"};
|
||||
capabilities.completionProvider.resolveProvider = false;
|
||||
|
||||
@@ -63,6 +63,7 @@ Server::Server() {
|
||||
register_callback<&Server::on_did_save>("textDocument/didSave");
|
||||
register_callback<&Server::on_did_close>("textDocument/didClose");
|
||||
|
||||
register_callback<&Server::on_hover>("textDocument/hover");
|
||||
register_callback<&Server::on_completion>("textDocument/completion");
|
||||
register_callback<&Server::on_semantic_token>("textDocument/semanticTokens/full");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user