clang-format

DEF CON 26 CTF
This commit is contained in:
Fangrui Song 2018-08-09 10:08:14 -07:00
parent 344ade0420
commit 8cbb317dc2
87 changed files with 2058 additions and 2372 deletions

View File

@ -20,7 +20,7 @@ using namespace llvm;
namespace { namespace {
std::string StripFileType(const std::string& path) { std::string StripFileType(const std::string &path) {
SmallString<128> Ret; SmallString<128> Ret;
sys::path::append(Ret, sys::path::parent_path(path), sys::path::stem(path)); sys::path::append(Ret, sys::path::parent_path(path), sys::path::stem(path));
return Ret.str(); return Ret.str();
@ -41,93 +41,93 @@ unsigned GetCompletionPriority(const CodeCompletionString &CCS,
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) { lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
switch (cursor_kind) { switch (cursor_kind) {
case CXCursor_UnexposedDecl: case CXCursor_UnexposedDecl:
return lsCompletionItemKind::Text; return lsCompletionItemKind::Text;
case CXCursor_StructDecl: case CXCursor_StructDecl:
case CXCursor_UnionDecl: case CXCursor_UnionDecl:
return lsCompletionItemKind::Struct; return lsCompletionItemKind::Struct;
case CXCursor_ClassDecl: case CXCursor_ClassDecl:
return lsCompletionItemKind::Class; return lsCompletionItemKind::Class;
case CXCursor_EnumDecl: case CXCursor_EnumDecl:
return lsCompletionItemKind::Enum; return lsCompletionItemKind::Enum;
case CXCursor_FieldDecl: case CXCursor_FieldDecl:
return lsCompletionItemKind::Field; return lsCompletionItemKind::Field;
case CXCursor_EnumConstantDecl: case CXCursor_EnumConstantDecl:
return lsCompletionItemKind::EnumMember; return lsCompletionItemKind::EnumMember;
case CXCursor_FunctionDecl: case CXCursor_FunctionDecl:
return lsCompletionItemKind::Function; return lsCompletionItemKind::Function;
case CXCursor_VarDecl: case CXCursor_VarDecl:
case CXCursor_ParmDecl: case CXCursor_ParmDecl:
return lsCompletionItemKind::Variable; return lsCompletionItemKind::Variable;
case CXCursor_ObjCInterfaceDecl: case CXCursor_ObjCInterfaceDecl:
return lsCompletionItemKind::Interface; return lsCompletionItemKind::Interface;
case CXCursor_ObjCInstanceMethodDecl: case CXCursor_ObjCInstanceMethodDecl:
case CXCursor_CXXMethod: case CXCursor_CXXMethod:
case CXCursor_ObjCClassMethodDecl: case CXCursor_ObjCClassMethodDecl:
return lsCompletionItemKind::Method; return lsCompletionItemKind::Method;
case CXCursor_FunctionTemplate: case CXCursor_FunctionTemplate:
return lsCompletionItemKind::Function; return lsCompletionItemKind::Function;
case CXCursor_Constructor: case CXCursor_Constructor:
case CXCursor_Destructor: case CXCursor_Destructor:
case CXCursor_ConversionFunction: case CXCursor_ConversionFunction:
return lsCompletionItemKind::Constructor; return lsCompletionItemKind::Constructor;
case CXCursor_ObjCIvarDecl: case CXCursor_ObjCIvarDecl:
return lsCompletionItemKind::Variable; return lsCompletionItemKind::Variable;
case CXCursor_ClassTemplate: case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization: case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_UsingDeclaration: case CXCursor_UsingDeclaration:
case CXCursor_TypedefDecl: case CXCursor_TypedefDecl:
case CXCursor_TypeAliasDecl: case CXCursor_TypeAliasDecl:
case CXCursor_TypeAliasTemplateDecl: case CXCursor_TypeAliasTemplateDecl:
case CXCursor_ObjCCategoryDecl: case CXCursor_ObjCCategoryDecl:
case CXCursor_ObjCProtocolDecl: case CXCursor_ObjCProtocolDecl:
case CXCursor_ObjCImplementationDecl: case CXCursor_ObjCImplementationDecl:
case CXCursor_ObjCCategoryImplDecl: case CXCursor_ObjCCategoryImplDecl:
return lsCompletionItemKind::Class; return lsCompletionItemKind::Class;
case CXCursor_ObjCPropertyDecl: case CXCursor_ObjCPropertyDecl:
return lsCompletionItemKind::Property; return lsCompletionItemKind::Property;
case CXCursor_MacroInstantiation: case CXCursor_MacroInstantiation:
case CXCursor_MacroDefinition: case CXCursor_MacroDefinition:
return lsCompletionItemKind::Interface; return lsCompletionItemKind::Interface;
case CXCursor_Namespace: case CXCursor_Namespace:
case CXCursor_NamespaceAlias: case CXCursor_NamespaceAlias:
case CXCursor_NamespaceRef: case CXCursor_NamespaceRef:
return lsCompletionItemKind::Module; return lsCompletionItemKind::Module;
case CXCursor_MemberRef: case CXCursor_MemberRef:
case CXCursor_TypeRef: case CXCursor_TypeRef:
case CXCursor_ObjCSuperClassRef: case CXCursor_ObjCSuperClassRef:
case CXCursor_ObjCProtocolRef: case CXCursor_ObjCProtocolRef:
case CXCursor_ObjCClassRef: case CXCursor_ObjCClassRef:
return lsCompletionItemKind::Reference; return lsCompletionItemKind::Reference;
// return lsCompletionItemKind::Unit; // return lsCompletionItemKind::Unit;
// return lsCompletionItemKind::Value; // return lsCompletionItemKind::Value;
// return lsCompletionItemKind::Keyword; // return lsCompletionItemKind::Keyword;
// return lsCompletionItemKind::Snippet; // return lsCompletionItemKind::Snippet;
// return lsCompletionItemKind::Color; // return lsCompletionItemKind::Color;
// return lsCompletionItemKind::File; // return lsCompletionItemKind::File;
case CXCursor_NotImplemented: case CXCursor_NotImplemented:
case CXCursor_OverloadCandidate: case CXCursor_OverloadCandidate:
return lsCompletionItemKind::Text; return lsCompletionItemKind::Text;
case CXCursor_TemplateTypeParameter: case CXCursor_TemplateTypeParameter:
case CXCursor_TemplateTemplateParameter: case CXCursor_TemplateTemplateParameter:
return lsCompletionItemKind::TypeParameter; return lsCompletionItemKind::TypeParameter;
default: default:
LOG_S(WARNING) << "Unhandled completion kind " << cursor_kind; LOG_S(WARNING) << "Unhandled completion kind " << cursor_kind;
return lsCompletionItemKind::Text; return lsCompletionItemKind::Text;
} }
} }
@ -144,50 +144,50 @@ void BuildCompletionItemTexts(std::vector<lsCompletionItem> &out,
CodeCompletionString::ChunkKind Kind = Chunk.Kind; CodeCompletionString::ChunkKind Kind = Chunk.Kind;
std::string text; std::string text;
switch (Kind) { switch (Kind) {
case CodeCompletionString::CK_TypedText: case CodeCompletionString::CK_TypedText:
case CodeCompletionString::CK_Text: case CodeCompletionString::CK_Text:
case CodeCompletionString::CK_Placeholder: case CodeCompletionString::CK_Placeholder:
case CodeCompletionString::CK_Informative: case CodeCompletionString::CK_Informative:
if (Chunk.Text) if (Chunk.Text)
text = Chunk.Text; text = Chunk.Text;
for (auto i = out_first; i < out.size(); i++) { for (auto i = out_first; i < out.size(); i++) {
// first TypedText is used for filtering // first TypedText is used for filtering
if (Kind == CodeCompletionString::CK_TypedText && !out[i].filterText) if (Kind == CodeCompletionString::CK_TypedText && !out[i].filterText)
out[i].filterText = text; out[i].filterText = text;
if (Kind == CodeCompletionString::CK_Placeholder) if (Kind == CodeCompletionString::CK_Placeholder)
out[i].parameters_.push_back(text); out[i].parameters_.push_back(text);
}
break;
case CodeCompletionString::CK_ResultType:
if (Chunk.Text)
result_type = Chunk.Text;
continue;
case CodeCompletionString::CK_CurrentParameter:
// We have our own parsing logic for active parameter. This doesn't seem
// to be very reliable.
continue;
case CodeCompletionString::CK_Optional: {
// duplicate last element, the recursive call will complete it
out.push_back(out.back());
BuildCompletionItemTexts(out, *Chunk.Optional, include_snippets);
continue;
} }
// clang-format off break;
case CodeCompletionString::CK_LeftParen: text = '('; break; case CodeCompletionString::CK_ResultType:
case CodeCompletionString::CK_RightParen: text = ')'; break; if (Chunk.Text)
case CodeCompletionString::CK_LeftBracket: text = '['; break; result_type = Chunk.Text;
case CodeCompletionString::CK_RightBracket: text = ']'; break; continue;
case CodeCompletionString::CK_LeftBrace: text = '{'; break; case CodeCompletionString::CK_CurrentParameter:
case CodeCompletionString::CK_RightBrace: text = '}'; break; // We have our own parsing logic for active parameter. This doesn't seem
case CodeCompletionString::CK_LeftAngle: text = '<'; break; // to be very reliable.
case CodeCompletionString::CK_RightAngle: text = '>'; break; continue;
case CodeCompletionString::CK_Comma: text = ", "; break; case CodeCompletionString::CK_Optional: {
case CodeCompletionString::CK_Colon: text = ':'; break; // duplicate last element, the recursive call will complete it
case CodeCompletionString::CK_SemiColon: text = ';'; break; out.push_back(out.back());
case CodeCompletionString::CK_Equal: text = '='; break; BuildCompletionItemTexts(out, *Chunk.Optional, include_snippets);
case CodeCompletionString::CK_HorizontalSpace: text = ' '; break; continue;
case CodeCompletionString::CK_VerticalSpace: text = ' '; break; }
// clang-format on // clang-format off
case CodeCompletionString::CK_LeftParen: text = '('; break;
case CodeCompletionString::CK_RightParen: text = ')'; break;
case CodeCompletionString::CK_LeftBracket: text = '['; break;
case CodeCompletionString::CK_RightBracket: text = ']'; break;
case CodeCompletionString::CK_LeftBrace: text = '{'; break;
case CodeCompletionString::CK_RightBrace: text = '}'; break;
case CodeCompletionString::CK_LeftAngle: text = '<'; break;
case CodeCompletionString::CK_RightAngle: text = '>'; break;
case CodeCompletionString::CK_Comma: text = ", "; break;
case CodeCompletionString::CK_Colon: text = ':'; break;
case CodeCompletionString::CK_SemiColon: text = ';'; break;
case CodeCompletionString::CK_Equal: text = '='; break;
case CodeCompletionString::CK_HorizontalSpace: text = ' '; break;
case CodeCompletionString::CK_VerticalSpace: text = ' '; break;
// clang-format on
} }
if (Kind != CodeCompletionString::CK_Informative) if (Kind != CodeCompletionString::CK_Informative)
@ -197,8 +197,9 @@ void BuildCompletionItemTexts(std::vector<lsCompletionItem> &out,
continue; continue;
if (Kind == CodeCompletionString::CK_Placeholder) { if (Kind == CodeCompletionString::CK_Placeholder) {
out[i].insertText += out[i].insertText += "${" +
"${" + std::to_string(out[i].parameters_.size()) + ":" + text + "}"; std::to_string(out[i].parameters_.size()) + ":" +
text + "}";
out[i].insertTextFormat = lsInsertTextFormat::Snippet; out[i].insertTextFormat = lsInsertTextFormat::Snippet;
} else { } else {
out[i].insertText += text; out[i].insertText += text;
@ -223,7 +224,7 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
for (unsigned i = 0, num_chunks = CCS.size(); i < num_chunks; ++i) { for (unsigned i = 0, num_chunks = CCS.size(); i < num_chunks; ++i) {
const CodeCompletionString::Chunk &Chunk = CCS[i]; const CodeCompletionString::Chunk &Chunk = CCS[i];
CodeCompletionString::ChunkKind Kind = Chunk.Kind; CodeCompletionString::ChunkKind Kind = Chunk.Kind;
const char* text = nullptr; const char *text = nullptr;
switch (Kind) { switch (Kind) {
case CodeCompletionString::CK_TypedText: case CodeCompletionString::CK_TypedText:
item.label = Chunk.Text; item.label = Chunk.Text;
@ -238,7 +239,8 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
item.detail += Chunk.Text; item.detail += Chunk.Text;
// Add parameter declarations as snippets if enabled // Add parameter declarations as snippets if enabled
if (include_snippets) { if (include_snippets) {
item.insertText += "${" + std::to_string(parameters->size()) + ":" + Chunk.Text + "}"; item.insertText +=
"${" + std::to_string(parameters->size()) + ":" + Chunk.Text + "}";
item.insertTextFormat = lsInsertTextFormat::Snippet; item.insertTextFormat = lsInsertTextFormat::Snippet;
} else } else
do_insert = false; do_insert = false;
@ -250,8 +252,8 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
case CodeCompletionString::CK_Optional: { case CodeCompletionString::CK_Optional: {
// Do not add text to insert string if we're in angle brackets. // Do not add text to insert string if we're in angle brackets.
bool should_insert = do_insert && angle_stack == 0; bool should_insert = do_insert && angle_stack == 0;
BuildDetailString(*Chunk.Optional, item, should_insert, BuildDetailString(*Chunk.Optional, item, should_insert, parameters,
parameters, include_snippets, angle_stack); include_snippets, angle_stack);
break; break;
} }
case CodeCompletionString::CK_ResultType: case CodeCompletionString::CK_ResultType:
@ -298,10 +300,9 @@ public:
Alloc(std::make_shared<clang::GlobalCodeCompletionAllocator>()), Alloc(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
CCTUInfo(Alloc) {} CCTUInfo(Alloc) {}
void ProcessCodeCompleteResults(Sema &S, void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
CodeCompletionContext Context, CodeCompletionResult *Results,
CodeCompletionResult *Results, unsigned NumResults) override {
unsigned NumResults) override {
ls_items.reserve(NumResults); ls_items.reserve(NumResults);
for (unsigned i = 0; i != NumResults; i++) { for (unsigned i = 0; i != NumResults; i++) {
CodeCompletionString *CCS = Results[i].CreateCodeCompletionString( CodeCompletionString *CCS = Results[i].CreateCodeCompletionString(
@ -312,7 +313,7 @@ public:
lsCompletionItem ls_item; lsCompletionItem ls_item;
ls_item.kind = GetCompletionKind(Results[i].CursorKind); ls_item.kind = GetCompletionKind(Results[i].CursorKind);
if (const char* brief = CCS->getBriefComment()) if (const char *brief = CCS->getBriefComment())
ls_item.documentation = brief; ls_item.documentation = brief;
// label/detail/filterText/insertText/priority // label/detail/filterText/insertText/priority
@ -334,8 +335,7 @@ public:
} else { } else {
bool do_insert = true; bool do_insert = true;
int angle_stack = 0; int angle_stack = 0;
BuildDetailString(*CCS, ls_item, do_insert, BuildDetailString(*CCS, ls_item, do_insert, &ls_item.parameters_,
&ls_item.parameters_,
g_config->client.snippetSupport, angle_stack); g_config->client.snippetSupport, angle_stack);
if (g_config->client.snippetSupport && if (g_config->client.snippetSupport &&
ls_item.insertTextFormat == lsInsertTextFormat::Snippet) ls_item.insertTextFormat == lsInsertTextFormat::Snippet)
@ -353,7 +353,7 @@ public:
CodeCompletionAllocator &getAllocator() override { return *Alloc; } CodeCompletionAllocator &getAllocator() override { return *Alloc; }
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo;} CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
}; };
void TryEnsureDocumentParsed(ClangCompleteManager *manager, void TryEnsureDocumentParsed(ClangCompleteManager *manager,
@ -374,7 +374,7 @@ void TryEnsureDocumentParsed(ClangCompleteManager *manager,
diagnostic); diagnostic);
} }
void CompletionPreloadMain(ClangCompleteManager* completion_manager) { void CompletionPreloadMain(ClangCompleteManager *completion_manager) {
while (true) { while (true) {
// Fetching the completion request blocks until we have a request. // Fetching the completion request blocks until we have a request.
auto request = completion_manager->preload_requests_.Dequeue(); auto request = completion_manager->preload_requests_.Dequeue();
@ -390,7 +390,7 @@ void CompletionPreloadMain(ClangCompleteManager* completion_manager) {
// Note: we only preload completion. We emit diagnostics for the // Note: we only preload completion. We emit diagnostics for the
// completion preload though. // completion preload though.
CompletionSession::Tu* tu = &session->completion; CompletionSession::Tu *tu = &session->completion;
// If we've parsed it more recently than the request time, don't bother // If we've parsed it more recently than the request time, don't bother
// reparsing. // reparsing.
@ -407,7 +407,7 @@ void CompletionPreloadMain(ClangCompleteManager* completion_manager) {
} }
} }
void CompletionQueryMain(ClangCompleteManager* completion_manager) { void CompletionQueryMain(ClangCompleteManager *completion_manager) {
while (true) { while (true) {
// Fetching the completion request blocks until we have a request. // Fetching the completion request blocks until we have a request.
std::unique_ptr<ClangCompleteManager::CompletionRequest> request = std::unique_ptr<ClangCompleteManager::CompletionRequest> request =
@ -427,11 +427,12 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
true /*create_if_needed*/); true /*create_if_needed*/);
std::lock_guard<std::mutex> lock(session->completion.lock); std::lock_guard<std::mutex> lock(session->completion.lock);
TryEnsureDocumentParsed(completion_manager, session, &session->completion.tu, false); TryEnsureDocumentParsed(completion_manager, session,
&session->completion.tu, false);
// It is possible we failed to create the document despite // It is possible we failed to create the document despite
// |TryEnsureDocumentParsed|. // |TryEnsureDocumentParsed|.
if (ClangTranslationUnit* tu = session->completion.tu.get()) { if (ClangTranslationUnit *tu = session->completion.tu.get()) {
WorkingFiles::Snapshot snapshot = WorkingFiles::Snapshot snapshot =
completion_manager->working_files_->AsSnapshot({StripFileType(path)}); completion_manager->working_files_->AsSnapshot({StripFileType(path)});
IntrusiveRefCntPtr<FileManager> FileMgr(&tu->Unit->getFileManager()); IntrusiveRefCntPtr<FileManager> FileMgr(&tu->Unit->getFileManager());
@ -464,7 +465,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
capture, tu->PCHCO, *Diag, LangOpts, *SrcMgr, capture, tu->PCHCO, *Diag, LangOpts, *SrcMgr,
*FileMgr, Diagnostics, TemporaryBuffers); *FileMgr, Diagnostics, TemporaryBuffers);
request->on_complete(capture.ls_items, false /*is_cached_result*/); request->on_complete(capture.ls_items, false /*is_cached_result*/);
// completion_manager->on_diagnostic_(session->file.filename, Diags.take()); // completion_manager->on_diagnostic_(session->file.filename,
// Diags.take());
} }
} }
} }
@ -487,7 +489,7 @@ void DiagnosticQueryMain(ClangCompleteManager *manager) {
// It is possible we failed to create the document despite // It is possible we failed to create the document despite
// |TryEnsureDocumentParsed|. // |TryEnsureDocumentParsed|.
ClangTranslationUnit* tu = session->diagnostics.tu.get(); ClangTranslationUnit *tu = session->diagnostics.tu.get();
if (!tu) if (!tu)
continue; continue;
@ -509,7 +511,8 @@ void DiagnosticQueryMain(ClangCompleteManager *manager) {
if (!FLoc.isValid()) // why? if (!FLoc.isValid()) // why?
continue; continue;
const FileEntry *FE = FLoc.getFileEntry(); const FileEntry *FE = FLoc.getFileEntry();
if (!FE || FileName(*FE) != path) continue; if (!FE || FileName(*FE) != path)
continue;
const auto &SM = FLoc.getManager(); const auto &SM = FLoc.getManager();
SourceRange R; SourceRange R;
for (const auto &CR : I->getRanges()) { for (const auto &CR : I->getRanges()) {
@ -553,45 +556,46 @@ void DiagnosticQueryMain(ClangCompleteManager *manager) {
} }
} }
} // namespace } // namespace
ClangCompleteManager::ClangCompleteManager(Project* project, ClangCompleteManager::ClangCompleteManager(Project *project,
WorkingFiles* working_files, WorkingFiles *working_files,
OnDiagnostic on_diagnostic, OnDiagnostic on_diagnostic,
OnDropped on_dropped) OnDropped on_dropped)
: project_(project), : project_(project), working_files_(working_files),
working_files_(working_files), on_diagnostic_(on_diagnostic), on_dropped_(on_dropped),
on_diagnostic_(on_diagnostic),
on_dropped_(on_dropped),
preloaded_sessions_(kMaxPreloadedSessions), preloaded_sessions_(kMaxPreloadedSessions),
completion_sessions_(kMaxCompletionSessions) { completion_sessions_(kMaxCompletionSessions) {
std::thread([&]() { std::thread([&]() {
set_thread_name("comp-query"); set_thread_name("comp-query");
CompletionQueryMain(this); CompletionQueryMain(this);
}).detach(); })
.detach();
std::thread([&]() { std::thread([&]() {
set_thread_name("comp-preload"); set_thread_name("comp-preload");
CompletionPreloadMain(this); CompletionPreloadMain(this);
}).detach(); })
.detach();
std::thread([&]() { std::thread([&]() {
set_thread_name("diag-query"); set_thread_name("diag-query");
DiagnosticQueryMain(this); DiagnosticQueryMain(this);
}).detach(); })
.detach();
} }
void ClangCompleteManager::CodeComplete( void ClangCompleteManager::CodeComplete(
const lsRequestId& id, const lsRequestId &id,
const lsTextDocumentPositionParams& completion_location, const lsTextDocumentPositionParams &completion_location,
const OnComplete& on_complete) { const OnComplete &on_complete) {
completion_request_.PushBack(std::make_unique<CompletionRequest>( completion_request_.PushBack(std::make_unique<CompletionRequest>(
id, completion_location.textDocument, completion_location.position, id, completion_location.textDocument, completion_location.position,
on_complete)); on_complete));
} }
void ClangCompleteManager::DiagnosticsUpdate( void ClangCompleteManager::DiagnosticsUpdate(
const lsTextDocumentIdentifier& document) { const lsTextDocumentIdentifier &document) {
bool has = false; bool has = false;
diagnostic_request_.Iterate([&](const DiagnosticRequest& request) { diagnostic_request_.Iterate([&](const DiagnosticRequest &request) {
if (request.document.uri == document.uri) if (request.document.uri == document.uri)
has = true; has = true;
}); });
@ -600,7 +604,7 @@ void ClangCompleteManager::DiagnosticsUpdate(
true /*priority*/); true /*priority*/);
} }
void ClangCompleteManager::NotifyView(const std::string& filename) { void ClangCompleteManager::NotifyView(const std::string &filename) {
// //
// On view, we reparse only if the file has not been parsed. The existence of // On view, we reparse only if the file has not been parsed. The existence of
// a CompletionSession instance implies the file is already parsed or will be // a CompletionSession instance implies the file is already parsed or will be
@ -612,7 +616,7 @@ void ClangCompleteManager::NotifyView(const std::string& filename) {
preload_requests_.PushBack(PreloadRequest(filename), true); preload_requests_.PushBack(PreloadRequest(filename), true);
} }
void ClangCompleteManager::NotifyEdit(const std::string& filename) { void ClangCompleteManager::NotifyEdit(const std::string &filename) {
// //
// We treat an edit like a view, because the completion logic will handle // We treat an edit like a view, because the completion logic will handle
// moving the CompletionSession instance from preloaded to completion // moving the CompletionSession instance from preloaded to completion
@ -622,7 +626,7 @@ void ClangCompleteManager::NotifyEdit(const std::string& filename) {
NotifyView(filename); NotifyView(filename);
} }
void ClangCompleteManager::NotifySave(const std::string& filename) { void ClangCompleteManager::NotifySave(const std::string &filename) {
// //
// On save, always reparse. // On save, always reparse.
// //
@ -631,7 +635,7 @@ void ClangCompleteManager::NotifySave(const std::string& filename) {
preload_requests_.PushBack(PreloadRequest(filename), true); preload_requests_.PushBack(PreloadRequest(filename), true);
} }
void ClangCompleteManager::NotifyClose(const std::string& filename) { void ClangCompleteManager::NotifyClose(const std::string &filename) {
// //
// On close, we clear any existing CompletionSession instance. // On close, we clear any existing CompletionSession instance.
// //
@ -652,7 +656,7 @@ void ClangCompleteManager::NotifyClose(const std::string& filename) {
} }
bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession( bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
const std::string& filename) { const std::string &filename) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
// Check for an existing CompletionSession. // Check for an existing CompletionSession.
@ -668,10 +672,10 @@ bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
return true; return true;
} }
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession( std::shared_ptr<CompletionSession>
const std::string& filename, ClangCompleteManager::TryGetSession(const std::string &filename,
bool mark_as_completion, bool mark_as_completion,
bool create_if_needed) { bool create_if_needed) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
// Try to find a preloaded session. // Try to find a preloaded session.
@ -701,11 +705,11 @@ std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
return completion_session; return completion_session;
} }
void ClangCompleteManager::FlushSession(const std::string& filename) { void ClangCompleteManager::FlushSession(const std::string &filename) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
preloaded_sessions_.TryTake(filename); preloaded_sessions_.TryTake(filename);
completion_sessions_.TryTake(filename); completion_sessions_.TryTake(filename);
} }
void ClangCompleteManager::FlushAllSessions() { void ClangCompleteManager::FlushAllSessions() {

View File

@ -26,39 +26,34 @@ struct CompletionSession
}; };
Project::Entry file; Project::Entry file;
WorkingFiles* working_files; WorkingFiles *working_files;
Tu completion; Tu completion;
Tu diagnostics; Tu diagnostics;
CompletionSession(const Project::Entry& file, WorkingFiles* wfiles) CompletionSession(const Project::Entry &file, WorkingFiles *wfiles)
: file(file), working_files(wfiles) {} : file(file), working_files(wfiles) {}
}; };
struct ClangCompleteManager { struct ClangCompleteManager {
using OnDiagnostic = using OnDiagnostic = std::function<void(
std::function<void(std::string path, std::string path, std::vector<lsDiagnostic> diagnostics)>;
std::vector<lsDiagnostic> diagnostics)>; using OnComplete = std::function<void(
using OnComplete = const std::vector<lsCompletionItem> &results, bool is_cached_result)>;
std::function<void(const std::vector<lsCompletionItem>& results,
bool is_cached_result)>;
using OnDropped = std::function<void(lsRequestId request_id)>; using OnDropped = std::function<void(lsRequestId request_id)>;
struct PreloadRequest { struct PreloadRequest {
PreloadRequest(const std::string& path) PreloadRequest(const std::string &path)
: request_time(std::chrono::high_resolution_clock::now()), path(path) {} : request_time(std::chrono::high_resolution_clock::now()), path(path) {}
std::chrono::time_point<std::chrono::high_resolution_clock> request_time; std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
std::string path; std::string path;
}; };
struct CompletionRequest { struct CompletionRequest {
CompletionRequest(const lsRequestId& id, CompletionRequest(const lsRequestId &id,
const lsTextDocumentIdentifier& document, const lsTextDocumentIdentifier &document,
const lsPosition& position, const lsPosition &position, const OnComplete &on_complete)
const OnComplete& on_complete) : id(id), document(document), position(position),
: id(id),
document(document),
position(position),
on_complete(on_complete) {} on_complete(on_complete) {}
lsRequestId id; lsRequestId id;
@ -70,42 +65,40 @@ struct ClangCompleteManager {
lsTextDocumentIdentifier document; lsTextDocumentIdentifier document;
}; };
ClangCompleteManager(Project* project, ClangCompleteManager(Project *project, WorkingFiles *working_files,
WorkingFiles* working_files, OnDiagnostic on_diagnostic, OnDropped on_dropped);
OnDiagnostic on_diagnostic,
OnDropped on_dropped);
// Start a code completion at the given location. |on_complete| will run when // Start a code completion at the given location. |on_complete| will run when
// completion results are available. |on_complete| may run on any thread. // completion results are available. |on_complete| may run on any thread.
void CodeComplete(const lsRequestId& request_id, void CodeComplete(const lsRequestId &request_id,
const lsTextDocumentPositionParams& completion_location, const lsTextDocumentPositionParams &completion_location,
const OnComplete& on_complete); const OnComplete &on_complete);
// Request a diagnostics update. // Request a diagnostics update.
void DiagnosticsUpdate(const lsTextDocumentIdentifier& document); void DiagnosticsUpdate(const lsTextDocumentIdentifier &document);
// Notify the completion manager that |filename| has been viewed and we // Notify the completion manager that |filename| has been viewed and we
// should begin preloading completion data. // should begin preloading completion data.
void NotifyView(const std::string& filename); void NotifyView(const std::string &filename);
// Notify the completion manager that |filename| has been edited. // Notify the completion manager that |filename| has been edited.
void NotifyEdit(const std::string& filename); void NotifyEdit(const std::string &filename);
// Notify the completion manager that |filename| has been saved. This // Notify the completion manager that |filename| has been saved. This
// triggers a reparse. // triggers a reparse.
void NotifySave(const std::string& filename); void NotifySave(const std::string &filename);
// Notify the completion manager that |filename| has been closed. Any existing // Notify the completion manager that |filename| has been closed. Any existing
// completion session will be dropped. // completion session will be dropped.
void NotifyClose(const std::string& filename); void NotifyClose(const std::string &filename);
// Ensures there is a completion or preloaded session. Returns true if a new // Ensures there is a completion or preloaded session. Returns true if a new
// session was created. // session was created.
bool EnsureCompletionOrCreatePreloadSession(const std::string& filename); bool EnsureCompletionOrCreatePreloadSession(const std::string &filename);
// Tries to find an edit session for |filename|. This will move the session // Tries to find an edit session for |filename|. This will move the session
// from view to edit. // from view to edit.
std::shared_ptr<CompletionSession> TryGetSession(const std::string& filename, std::shared_ptr<CompletionSession> TryGetSession(const std::string &filename,
bool mark_as_completion, bool mark_as_completion,
bool create_if_needed); bool create_if_needed);
// Flushes all saved sessions with the supplied filename // Flushes all saved sessions with the supplied filename
void FlushSession(const std::string& filename); void FlushSession(const std::string &filename);
// Flushes all saved sessions // Flushes all saved sessions
void FlushAllSessions(void); void FlushAllSessions(void);
@ -114,8 +107,8 @@ struct ClangCompleteManager {
const int kMaxCompletionSessions = 5; const int kMaxCompletionSessions = 5;
// Global state. // Global state.
Project* project_; Project *project_;
WorkingFiles* working_files_; WorkingFiles *working_files_;
OnDiagnostic on_diagnostic_; OnDiagnostic on_diagnostic_;
OnDropped on_dropped_; OnDropped on_dropped_;

View File

@ -68,7 +68,7 @@ std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
const std::string &filepath, const std::vector<std::string> &args, const std::string &filepath, const std::vector<std::string> &args,
const WorkingFiles::Snapshot &snapshot, bool diagnostic) { const WorkingFiles::Snapshot &snapshot, bool diagnostic) {
std::vector<const char *> Args; std::vector<const char *> Args;
for (auto& arg : args) for (auto &arg : args)
Args.push_back(arg.c_str()); Args.push_back(arg.c_str());
Args.push_back("-fallow-editor-placeholders"); Args.push_back("-fallow-editor-placeholders");
if (!diagnostic) if (!diagnostic)
@ -103,9 +103,8 @@ std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
ret->PCHCO->getRawReader().getFormat(), &ErrUnit)); ret->PCHCO->getRawReader().getFormat(), &ErrUnit));
}; };
if (!CRC.RunSafely(parse)) { if (!CRC.RunSafely(parse)) {
LOG_S(ERROR) LOG_S(ERROR) << "clang crashed for " << filepath << "\n"
<< "clang crashed for " << filepath << "\n" << StringJoin(args, " ") + " -fsyntax-only";
<< StringJoin(args, " ") + " -fsyntax-only";
return {}; return {};
} }
if (!Unit && !ErrUnit) if (!Unit && !ErrUnit)

View File

@ -7,9 +7,9 @@
#include <llvm/Support/CrashRecoveryContext.h> #include <llvm/Support/CrashRecoveryContext.h>
#include <memory> #include <memory>
#include <stdlib.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdlib.h>
std::vector<clang::ASTUnit::RemappedFile> std::vector<clang::ASTUnit::RemappedFile>
GetRemapped(const WorkingFiles::Snapshot &snapshot); GetRemapped(const WorkingFiles::Snapshot &snapshot);
@ -19,12 +19,12 @@ Range FromCharSourceRange(const clang::SourceManager &SM,
clang::CharSourceRange R, clang::CharSourceRange R,
llvm::sys::fs::UniqueID *UniqueID = nullptr); llvm::sys::fs::UniqueID *UniqueID = nullptr);
Range FromCharRange(const clang::SourceManager &SM, const clang::LangOptions &LangOpts, Range FromCharRange(const clang::SourceManager &SM,
clang::SourceRange R, const clang::LangOptions &LangOpts, clang::SourceRange R,
llvm::sys::fs::UniqueID *UniqueID = nullptr); llvm::sys::fs::UniqueID *UniqueID = nullptr);
Range FromTokenRange(const clang::SourceManager &SM, const clang::LangOptions &LangOpts, Range FromTokenRange(const clang::SourceManager &SM,
clang::SourceRange R, const clang::LangOptions &LangOpts, clang::SourceRange R,
llvm::sys::fs::UniqueID *UniqueID = nullptr); llvm::sys::fs::UniqueID *UniqueID = nullptr);
struct ClangTranslationUnit { struct ClangTranslationUnit {

View File

@ -10,7 +10,7 @@
using namespace clang; using namespace clang;
using namespace llvm; using namespace llvm;
std::string FileName(const FileEntry& file) { std::string FileName(const FileEntry &file) {
StringRef Name = file.tryGetRealPathName(); StringRef Name = file.tryGetRealPathName();
if (Name.empty()) if (Name.empty())
Name = file.getName(); Name = file.getName();
@ -25,7 +25,7 @@ std::string FileName(const FileEntry& file) {
} }
// clang::BuiltinType::getName without PrintingPolicy // clang::BuiltinType::getName without PrintingPolicy
const char* ClangBuiltinTypeName(int kind) { const char *ClangBuiltinTypeName(int kind) {
switch (BuiltinType::Kind(kind)) { switch (BuiltinType::Kind(kind)) {
case BuiltinType::Void: case BuiltinType::Void:
return "void"; return "void";

View File

@ -5,6 +5,6 @@
#include <string> #include <string>
// Returns the absolute path to |file|. // Returns the absolute path to |file|.
std::string FileName(const clang::FileEntry& file); std::string FileName(const clang::FileEntry &file);
const char* ClangBuiltinTypeName(int); const char *ClangBuiltinTypeName(int);

View File

@ -1,4 +1,4 @@
#include "config.h" #include "config.h"
Config* g_config; Config *g_config;
thread_local int g_thread_id; thread_local int g_thread_id;

View File

@ -218,49 +218,23 @@ struct Config {
MAKE_REFLECT_STRUCT(Config::Clang, extraArgs, resourceDir); MAKE_REFLECT_STRUCT(Config::Clang, extraArgs, resourceDir);
MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport); MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport);
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables); MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
MAKE_REFLECT_STRUCT(Config::Completion, MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, dropOldRequests,
caseSensitivity, detailedLabel, filterAndSort, includeBlacklist,
dropOldRequests, includeMaxPathSize, includeSuffixWhitelist,
detailedLabel,
filterAndSort,
includeBlacklist,
includeMaxPathSize,
includeSuffixWhitelist,
includeWhitelist); includeWhitelist);
MAKE_REFLECT_STRUCT(Config::Diagnostics, MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onParse,
blacklist, onType, whitelist)
frequencyMs,
onParse,
onType,
whitelist)
MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist) MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist)
MAKE_REFLECT_STRUCT(Config::Index, MAKE_REFLECT_STRUCT(Config::Index, attributeMakeCallsToCtor, blacklist,
attributeMakeCallsToCtor, comments, enabled, onDidChange, reparseForDependency,
blacklist, threads, whitelist);
comments,
enabled,
onDidChange,
reparseForDependency,
threads,
whitelist);
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort); MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum); MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
MAKE_REFLECT_STRUCT(Config, MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,
compilationDatabaseCommand, compilationDatabaseDirectory, cacheDirectory, cacheFormat,
compilationDatabaseDirectory,
cacheDirectory,
cacheFormat,
clang, clang, client, codeLens, completion, diagnostics, highlight,
client, index, largeFileSize, workspaceSymbol, xref);
codeLens,
completion,
diagnostics,
highlight,
index,
largeFileSize,
workspaceSymbol,
xref);
extern Config* g_config; extern Config *g_config;
thread_local extern int g_thread_id; thread_local extern int g_thread_id;

View File

@ -8,9 +8,9 @@
namespace { namespace {
std::optional<std::string> GetFileContents( std::optional<std::string>
const std::string& path, GetFileContents(const std::string &path,
std::unordered_map<std::string, FileContents>* file_contents) { std::unordered_map<std::string, FileContents> *file_contents) {
auto it = file_contents->find(path); auto it = file_contents->find(path);
if (it == file_contents->end()) { if (it == file_contents->end()) {
std::optional<std::string> content = ReadContent(path); std::optional<std::string> content = ReadContent(path);
@ -21,9 +21,9 @@ std::optional<std::string> GetFileContents(
return it->second.content; return it->second.content;
} }
} // namespace } // namespace
FileContents::FileContents(const std::string& path, const std::string& content) FileContents::FileContents(const std::string &path, const std::string &content)
: path(path), content(content) { : path(path), content(content) {
line_offsets_.push_back(0); line_offsets_.push_back(0);
for (size_t i = 0; i < content.size(); i++) { for (size_t i = 0; i < content.size(); i++) {
@ -43,13 +43,13 @@ std::optional<int> FileContents::ToOffset(Position p) const {
std::optional<std::string> FileContents::ContentsInRange(Range range) const { std::optional<std::string> FileContents::ContentsInRange(Range range) const {
std::optional<int> start_offset = ToOffset(range.start), std::optional<int> start_offset = ToOffset(range.start),
end_offset = ToOffset(range.end); end_offset = ToOffset(range.end);
if (start_offset && end_offset && *start_offset < *end_offset) if (start_offset && end_offset && *start_offset < *end_offset)
return content.substr(*start_offset, *end_offset - *start_offset); return content.substr(*start_offset, *end_offset - *start_offset);
return std::nullopt; return std::nullopt;
} }
VFS::State VFS::Get(const std::string& file) { VFS::State VFS::Get(const std::string &file) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
auto it = state.find(file); auto it = state.find(file);
if (it != state.end()) if (it != state.end())
@ -57,9 +57,9 @@ VFS::State VFS::Get(const std::string& file) {
return {0, 0, 0}; return {0, 0, 0};
} }
bool VFS::Mark(const std::string& file, int owner, int stage) { bool VFS::Mark(const std::string &file, int owner, int stage) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
State& st = state[file]; State &st = state[file];
if (st.stage < stage) { if (st.stage < stage) {
st.owner = owner; st.owner = owner;
st.stage = stage; st.stage = stage;
@ -68,9 +68,9 @@ bool VFS::Mark(const std::string& file, int owner, int stage) {
return false; return false;
} }
bool VFS::Stamp(const std::string& file, int64_t ts) { bool VFS::Stamp(const std::string &file, int64_t ts) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
State& st = state[file]; State &st = state[file];
if (st.timestamp < ts) { if (st.timestamp < ts) {
st.timestamp = ts; st.timestamp = ts;
return true; return true;
@ -78,23 +78,23 @@ bool VFS::Stamp(const std::string& file, int64_t ts) {
return false; return false;
} }
void VFS::ResetLocked(const std::string& file) { void VFS::ResetLocked(const std::string &file) {
State& st = state[file]; State &st = state[file];
if (st.owner == 0 || st.owner == g_thread_id) if (st.owner == 0 || st.owner == g_thread_id)
st.stage = 0; st.stage = 0;
} }
void VFS::Reset(const std::string& file) { void VFS::Reset(const std::string &file) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
ResetLocked(file); ResetLocked(file);
} }
FileConsumer::FileConsumer(VFS* vfs, const std::string& parse_file) FileConsumer::FileConsumer(VFS *vfs, const std::string &parse_file)
: vfs_(vfs), parse_file_(parse_file), thread_id_(g_thread_id) {} : vfs_(vfs), parse_file_(parse_file), thread_id_(g_thread_id) {}
IndexFile* FileConsumer::TryConsumeFile( IndexFile *FileConsumer::TryConsumeFile(
const clang::FileEntry& File, const clang::FileEntry &File,
std::unordered_map<std::string, FileContents>* file_contents_map) { std::unordered_map<std::string, FileContents> *file_contents_map) {
auto UniqueID = File.getUniqueID(); auto UniqueID = File.getUniqueID();
auto it = local_.find(UniqueID); auto it = local_.find(UniqueID);
if (it != local_.end()) if (it != local_.end())
@ -115,13 +115,14 @@ IndexFile* FileConsumer::TryConsumeFile(
return nullptr; return nullptr;
// Build IndexFile instance. // Build IndexFile instance.
local_[UniqueID] = std::make_unique<IndexFile>(UniqueID, file_name, *contents); local_[UniqueID] =
std::make_unique<IndexFile>(UniqueID, file_name, *contents);
return local_[UniqueID].get(); return local_[UniqueID].get();
} }
std::vector<std::unique_ptr<IndexFile>> FileConsumer::TakeLocalState() { std::vector<std::unique_ptr<IndexFile>> FileConsumer::TakeLocalState() {
std::vector<std::unique_ptr<IndexFile>> result; std::vector<std::unique_ptr<IndexFile>> result;
for (auto& entry : local_) { for (auto &entry : local_) {
if (entry.second) if (entry.second)
result.push_back(std::move(entry.second)); result.push_back(std::move(entry.second));
} }

View File

@ -14,7 +14,7 @@ struct IndexFile;
struct FileContents { struct FileContents {
FileContents() = default; FileContents() = default;
FileContents(const std::string& path, const std::string& content); FileContents(const std::string &path, const std::string &content);
std::optional<int> ToOffset(Position p) const; std::optional<int> ToOffset(Position p) const;
std::optional<std::string> ContentsInRange(Range range) const; std::optional<std::string> ContentsInRange(Range range) const;
@ -34,23 +34,22 @@ struct VFS {
mutable std::unordered_map<std::string, State> state; mutable std::unordered_map<std::string, State> state;
mutable std::mutex mutex; mutable std::mutex mutex;
State Get(const std::string& file); State Get(const std::string &file);
bool Mark(const std::string& file, int owner, int stage); bool Mark(const std::string &file, int owner, int stage);
bool Stamp(const std::string& file, int64_t ts); bool Stamp(const std::string &file, int64_t ts);
void ResetLocked(const std::string& file); void ResetLocked(const std::string &file);
void Reset(const std::string& file); void Reset(const std::string &file);
}; };
namespace std { namespace std {
template <> template <> struct hash<llvm::sys::fs::UniqueID> {
struct hash<llvm::sys::fs::UniqueID> {
std::size_t operator()(llvm::sys::fs::UniqueID ID) const { std::size_t operator()(llvm::sys::fs::UniqueID ID) const {
size_t ret = ID.getDevice(); size_t ret = ID.getDevice();
hash_combine(ret, ID.getFile()); hash_combine(ret, ID.getFile());
return ret; return ret;
} }
}; };
} } // namespace std
// FileConsumer is used by the indexer. When it encouters a file, it tries to // FileConsumer is used by the indexer. When it encouters a file, it tries to
// take ownership over it. If the indexer has ownership over a file, it will // take ownership over it. If the indexer has ownership over a file, it will
@ -60,7 +59,7 @@ struct hash<llvm::sys::fs::UniqueID> {
// The indexer does this because header files do not have their own translation // The indexer does this because header files do not have their own translation
// units but we still want to index them. // units but we still want to index them.
struct FileConsumer { struct FileConsumer {
FileConsumer(VFS* vfs, const std::string& parse_file); FileConsumer(VFS *vfs, const std::string &parse_file);
// Returns IndexFile for the file or nullptr. |is_first_ownership| is set // Returns IndexFile for the file or nullptr. |is_first_ownership| is set
// to true iff the function just took ownership over the file. Otherwise it // to true iff the function just took ownership over the file. Otherwise it
@ -68,15 +67,17 @@ struct FileConsumer {
// //
// note: file_contents is passed as a parameter instead of as a member // note: file_contents is passed as a parameter instead of as a member
// variable since it is large and we do not want to copy it. // variable since it is large and we do not want to copy it.
IndexFile* TryConsumeFile(const clang::FileEntry& file, IndexFile *
std::unordered_map<std::string, FileContents>* file_contents); TryConsumeFile(const clang::FileEntry &file,
std::unordered_map<std::string, FileContents> *file_contents);
// Returns and passes ownership of all local state. // Returns and passes ownership of all local state.
std::vector<std::unique_ptr<IndexFile>> TakeLocalState(); std::vector<std::unique_ptr<IndexFile>> TakeLocalState();
private: private:
std::unordered_map<llvm::sys::fs::UniqueID, std::unique_ptr<IndexFile>> local_; std::unordered_map<llvm::sys::fs::UniqueID, std::unique_ptr<IndexFile>>
VFS* vfs_; local_;
VFS *vfs_;
std::string parse_file_; std::string parse_file_;
int thread_id_; int thread_id_;
}; };

View File

@ -6,10 +6,8 @@ using namespace llvm;
#include <set> #include <set>
#include <vector> #include <vector>
void GetFilesInFolder(std::string folder, void GetFilesInFolder(std::string folder, bool recursive, bool dir_prefix,
bool recursive, const std::function<void(const std::string &)> &handler) {
bool dir_prefix,
const std::function<void(const std::string&)>& handler) {
EnsureEndsInSlash(folder); EnsureEndsInSlash(folder);
sys::fs::file_status Status; sys::fs::file_status Status;
if (sys::fs::status(folder, Status, true)) if (sys::fs::status(folder, Status, true))
@ -20,7 +18,7 @@ void GetFilesInFolder(std::string folder,
std::set<sys::fs::UniqueID> seen{Status.getUniqueID()}; std::set<sys::fs::UniqueID> seen{Status.getUniqueID()};
while (curr.size() || succ.size()) { while (curr.size() || succ.size()) {
if (curr.empty()) { if (curr.empty()) {
for (auto& it : succ) for (auto &it : succ)
if (!seen.count(it.second.getUniqueID())) if (!seen.count(it.second.getUniqueID()))
curr.push_back(std::move(it.first)); curr.push_back(std::move(it.first));
succ.clear(); succ.clear();

View File

@ -1,8 +1,8 @@
#include "fuzzy_match.h" #include "fuzzy_match.h"
#include <algorithm>
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <algorithm>
#include <vector> #include <vector>
enum CharClass { Other, Lower, Upper }; enum CharClass { Other, Lower, Upper };
@ -17,7 +17,7 @@ CharClass GetCharClass(int c) {
return Other; return Other;
} }
void CalculateRoles(std::string_view s, int roles[], int* class_set) { void CalculateRoles(std::string_view s, int roles[], int *class_set) {
if (s.empty()) { if (s.empty()) {
*class_set = 0; *class_set = 0;
return; return;
@ -41,7 +41,7 @@ void CalculateRoles(std::string_view s, int roles[], int* class_set) {
} }
roles[s.size() - 1] = fn(); roles[s.size() - 1] = fn();
} }
} // namespace } // namespace
int FuzzyMatcher::MissScore(int j, bool last) { int FuzzyMatcher::MissScore(int j, bool last) {
int s = -3; int s = -3;

View File

@ -5,7 +5,7 @@
#include <string_view> #include <string_view>
class FuzzyMatcher { class FuzzyMatcher {
public: public:
constexpr static int kMaxPat = 100; constexpr static int kMaxPat = 100;
constexpr static int kMaxText = 200; constexpr static int kMaxText = 200;
// Negative but far from INT_MIN so that intermediate results are hard to // Negative but far from INT_MIN so that intermediate results are hard to
@ -15,7 +15,7 @@ class FuzzyMatcher {
FuzzyMatcher(std::string_view pattern, int case_sensitivity); FuzzyMatcher(std::string_view pattern, int case_sensitivity);
int Match(std::string_view text); int Match(std::string_view text);
private: private:
int case_sensitivity; int case_sensitivity;
std::string pat; std::string pat;
std::string_view text; std::string_view text;

View File

@ -19,7 +19,7 @@ struct CompletionCandidate {
lsCompletionItem completion_item; lsCompletionItem completion_item;
}; };
std::string ElideLongPath(const std::string& path) { std::string ElideLongPath(const std::string &path) {
if (g_config->completion.includeMaxPathSize <= 0) if (g_config->completion.includeMaxPathSize <= 0)
return path; return path;
@ -30,8 +30,8 @@ std::string ElideLongPath(const std::string& path) {
return ".." + path.substr(start + 2); return ".." + path.substr(start + 2);
} }
size_t TrimCommonPathPrefix(const std::string& result, size_t TrimCommonPathPrefix(const std::string &result,
const std::string& trimmer) { const std::string &trimmer) {
#ifdef _WIN32 #ifdef _WIN32
std::string s = result, t = trimmer; std::string s = result, t = trimmer;
std::transform(s.begin(), s.end(), s.begin(), ::tolower); std::transform(s.begin(), s.end(), s.begin(), ::tolower);
@ -46,16 +46,15 @@ size_t TrimCommonPathPrefix(const std::string& result,
} }
// Returns true iff angle brackets should be used. // Returns true iff angle brackets should be used.
bool TrimPath(Project* project, bool TrimPath(Project *project, const std::string &project_root,
const std::string& project_root, std::string *insert_path) {
std::string* insert_path) {
size_t start = TrimCommonPathPrefix(*insert_path, project_root); size_t start = TrimCommonPathPrefix(*insert_path, project_root);
bool angle = false; bool angle = false;
for (auto& include_dir : project->quote_include_directories) for (auto &include_dir : project->quote_include_directories)
start = std::max(start, TrimCommonPathPrefix(*insert_path, include_dir)); start = std::max(start, TrimCommonPathPrefix(*insert_path, include_dir));
for (auto& include_dir : project->angle_include_directories) { for (auto &include_dir : project->angle_include_directories) {
auto len = TrimCommonPathPrefix(*insert_path, include_dir); auto len = TrimCommonPathPrefix(*insert_path, include_dir);
if (len > start) { if (len > start) {
start = len; start = len;
@ -67,12 +66,11 @@ bool TrimPath(Project* project,
return angle; return angle;
} }
lsCompletionItem BuildCompletionItem(const std::string& path, lsCompletionItem BuildCompletionItem(const std::string &path,
bool use_angle_brackets, bool use_angle_brackets, bool is_stl) {
bool is_stl) {
lsCompletionItem item; lsCompletionItem item;
item.label = ElideLongPath(path); item.label = ElideLongPath(path);
item.detail = path; // the include path, used in de-duplicating item.detail = path; // the include path, used in de-duplicating
item.textEdit = lsTextEdit(); item.textEdit = lsTextEdit();
item.textEdit->newText = path; item.textEdit->newText = path;
item.insertTextFormat = lsInsertTextFormat::PlainText; item.insertTextFormat = lsInsertTextFormat::PlainText;
@ -87,9 +85,9 @@ lsCompletionItem BuildCompletionItem(const std::string& path,
return item; return item;
} }
} // namespace } // namespace
IncludeComplete::IncludeComplete(Project* project) IncludeComplete::IncludeComplete(Project *project)
: is_scanning(false), project_(project) {} : is_scanning(false), project_(project) {}
void IncludeComplete::Rescan() { void IncludeComplete::Rescan() {
@ -102,8 +100,9 @@ void IncludeComplete::Rescan() {
if (!match_ && (g_config->completion.includeWhitelist.size() || if (!match_ && (g_config->completion.includeWhitelist.size() ||
g_config->completion.includeBlacklist.size())) g_config->completion.includeBlacklist.size()))
match_ = std::make_unique<GroupMatch>(g_config->completion.includeWhitelist, match_ =
g_config->completion.includeBlacklist); std::make_unique<GroupMatch>(g_config->completion.includeWhitelist,
g_config->completion.includeBlacklist);
is_scanning = true; is_scanning = true;
std::thread([this]() { std::thread([this]() {
@ -111,17 +110,18 @@ void IncludeComplete::Rescan() {
Timer timer("include", "scan include paths"); Timer timer("include", "scan include paths");
TimeRegion region(timer); TimeRegion region(timer);
for (const std::string& dir : project_->quote_include_directories) for (const std::string &dir : project_->quote_include_directories)
InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/); InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/);
for (const std::string& dir : project_->angle_include_directories) for (const std::string &dir : project_->angle_include_directories)
InsertIncludesFromDirectory(dir, true /*use_angle_brackets*/); InsertIncludesFromDirectory(dir, true /*use_angle_brackets*/);
is_scanning = false; is_scanning = false;
}).detach(); })
.detach();
} }
void IncludeComplete::InsertCompletionItem(const std::string& absolute_path, void IncludeComplete::InsertCompletionItem(const std::string &absolute_path,
lsCompletionItem&& item) { lsCompletionItem &&item) {
if (inserted_paths.insert({item.detail, inserted_paths.size()}).second) { if (inserted_paths.insert({item.detail, inserted_paths.size()}).second) {
completion_items.push_back(item); completion_items.push_back(item);
// insert if not found or with shorter include path // insert if not found or with shorter include path
@ -132,7 +132,7 @@ void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
completion_items.size() - 1; completion_items.size() - 1;
} }
} else { } else {
lsCompletionItem& inserted_item = lsCompletionItem &inserted_item =
completion_items[inserted_paths[item.detail]]; completion_items[inserted_paths[item.detail]];
// Update |use_angle_brackets_|, prefer quotes. // Update |use_angle_brackets_|, prefer quotes.
if (!item.use_angle_brackets_) if (!item.use_angle_brackets_)
@ -140,7 +140,7 @@ void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
} }
} }
void IncludeComplete::AddFile(const std::string& absolute_path) { void IncludeComplete::AddFile(const std::string &absolute_path) {
if (!EndsWithAny(absolute_path, g_config->completion.includeSuffixWhitelist)) if (!EndsWithAny(absolute_path, g_config->completion.includeSuffixWhitelist))
return; return;
if (match_ && !match_->IsMatch(absolute_path)) if (match_ && !match_->IsMatch(absolute_path))
@ -184,13 +184,14 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
}); });
std::lock_guard<std::mutex> lock(completion_items_mutex); std::lock_guard<std::mutex> lock(completion_items_mutex);
for (CompletionCandidate& result : results) for (CompletionCandidate &result : results)
InsertCompletionItem(result.absolute_path, InsertCompletionItem(result.absolute_path,
std::move(result.completion_item)); std::move(result.completion_item));
} }
std::optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath( std::optional<lsCompletionItem>
const std::string& absolute_path) { IncludeComplete::FindCompletionItemForAbsolutePath(
const std::string &absolute_path) {
std::lock_guard<std::mutex> lock(completion_items_mutex); std::lock_guard<std::mutex> lock(completion_items_mutex);
auto it = absolute_path_to_completion_item.find(absolute_path); auto it = absolute_path_to_completion_item.find(absolute_path);

View File

@ -10,26 +10,26 @@ struct GroupMatch;
struct Project; struct Project;
struct IncludeComplete { struct IncludeComplete {
IncludeComplete(Project* project); IncludeComplete(Project *project);
// Starts scanning directories. Clears existing cache. // Starts scanning directories. Clears existing cache.
void Rescan(); void Rescan();
// Ensures the one-off file is inside |completion_items|. // Ensures the one-off file is inside |completion_items|.
void AddFile(const std::string& absolute_path); void AddFile(const std::string &absolute_path);
// Scans the given directory and inserts all includes from this. This is a // Scans the given directory and inserts all includes from this. This is a
// blocking function and should be run off the querydb thread. // blocking function and should be run off the querydb thread.
void InsertIncludesFromDirectory(std::string directory, void InsertIncludesFromDirectory(std::string directory,
bool use_angle_brackets); bool use_angle_brackets);
std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath( std::optional<lsCompletionItem>
const std::string& absolute_path); FindCompletionItemForAbsolutePath(const std::string &absolute_path);
// Insert item to |completion_items|. // Insert item to |completion_items|.
// Update |absolute_path_to_completion_item| and |inserted_paths|. // Update |absolute_path_to_completion_item| and |inserted_paths|.
void InsertCompletionItem(const std::string& absolute_path, void InsertCompletionItem(const std::string &absolute_path,
lsCompletionItem&& item); lsCompletionItem &&item);
// Guards |completion_items| when |is_scanning| is true. // Guards |completion_items| when |is_scanning| is true.
std::mutex completion_items_mutex; std::mutex completion_items_mutex;
@ -44,6 +44,6 @@ struct IncludeComplete {
std::unordered_map<std::string, int> inserted_paths; std::unordered_map<std::string, int> inserted_paths;
// Cached references // Cached references
Project* project_; Project *project_;
std::unique_ptr<GroupMatch> match_; std::unique_ptr<GroupMatch> match_;
}; };

View File

@ -21,9 +21,9 @@ using ccls::Intern;
using namespace clang; using namespace clang;
using llvm::Timer; using llvm::Timer;
#include <algorithm>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <algorithm>
#include <map> #include <map>
#include <unordered_set> #include <unordered_set>
@ -40,14 +40,14 @@ struct IndexParam {
std::string short_name; std::string short_name;
std::string qualified; std::string qualified;
}; };
std::unordered_map<const Decl*, DeclInfo> Decl2Info; std::unordered_map<const Decl *, DeclInfo> Decl2Info;
ASTUnit& Unit; ASTUnit &Unit;
ASTContext* Ctx; ASTContext *Ctx;
FileConsumer* file_consumer = nullptr; FileConsumer *file_consumer = nullptr;
IndexParam(ASTUnit& Unit, FileConsumer* file_consumer) IndexParam(ASTUnit &Unit, FileConsumer *file_consumer)
: Unit(Unit), file_consumer(file_consumer) {} : Unit(Unit), file_consumer(file_consumer) {}
IndexFile *ConsumeFile(const FileEntry &File) { IndexFile *ConsumeFile(const FileEntry &File) {
@ -63,7 +63,7 @@ struct IndexParam {
// Set modification time. // Set modification time.
std::optional<int64_t> write_time = LastWriteTime(file_name); std::optional<int64_t> write_time = LastWriteTime(file_name);
LOG_IF_S(ERROR, !write_time) LOG_IF_S(ERROR, !write_time)
<< "failed to fetch write time for " << file_name; << "failed to fetch write time for " << file_name;
if (write_time) if (write_time)
file2write_time[file_name] = *write_time; file2write_time[file_name] = *write_time;
} }
@ -81,12 +81,13 @@ StringRef GetSourceInRange(const SourceManager &SM, const LangOptions &LangOpts,
StringRef Buf = SM.getBufferData(BInfo.first, &invalid); StringRef Buf = SM.getBufferData(BInfo.first, &invalid);
if (invalid) if (invalid)
return ""; return "";
return Buf.substr(BInfo.second, EInfo.second + Lexer::MeasureTokenLength( return Buf.substr(BInfo.second,
ELoc, SM, LangOpts) - EInfo.second +
BInfo.second); Lexer::MeasureTokenLength(ELoc, SM, LangOpts) -
BInfo.second);
} }
SymbolKind GetSymbolKind(const Decl* D) { SymbolKind GetSymbolKind(const Decl *D) {
switch (D->getKind()) { switch (D->getKind()) {
case Decl::TranslationUnit: case Decl::TranslationUnit:
return SymbolKind::File; return SymbolKind::File;
@ -136,46 +137,46 @@ SymbolKind GetSymbolKind(const Decl* D) {
LanguageId GetDeclLanguage(const Decl *D) { LanguageId GetDeclLanguage(const Decl *D) {
switch (D->getKind()) { switch (D->getKind()) {
default: default:
return LanguageId::C; return LanguageId::C;
case Decl::ImplicitParam: case Decl::ImplicitParam:
case Decl::ObjCAtDefsField: case Decl::ObjCAtDefsField:
case Decl::ObjCCategory: case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl: case Decl::ObjCCategoryImpl:
case Decl::ObjCCompatibleAlias: case Decl::ObjCCompatibleAlias:
case Decl::ObjCImplementation: case Decl::ObjCImplementation:
case Decl::ObjCInterface: case Decl::ObjCInterface:
case Decl::ObjCIvar: case Decl::ObjCIvar:
case Decl::ObjCMethod: case Decl::ObjCMethod:
case Decl::ObjCProperty: case Decl::ObjCProperty:
case Decl::ObjCPropertyImpl: case Decl::ObjCPropertyImpl:
case Decl::ObjCProtocol: case Decl::ObjCProtocol:
case Decl::ObjCTypeParam: case Decl::ObjCTypeParam:
return LanguageId::ObjC; return LanguageId::ObjC;
case Decl::CXXConstructor: case Decl::CXXConstructor:
case Decl::CXXConversion: case Decl::CXXConversion:
case Decl::CXXDestructor: case Decl::CXXDestructor:
case Decl::CXXMethod: case Decl::CXXMethod:
case Decl::CXXRecord: case Decl::CXXRecord:
case Decl::ClassTemplate: case Decl::ClassTemplate:
case Decl::ClassTemplatePartialSpecialization: case Decl::ClassTemplatePartialSpecialization:
case Decl::ClassTemplateSpecialization: case Decl::ClassTemplateSpecialization:
case Decl::Friend: case Decl::Friend:
case Decl::FriendTemplate: case Decl::FriendTemplate:
case Decl::FunctionTemplate: case Decl::FunctionTemplate:
case Decl::LinkageSpec: case Decl::LinkageSpec:
case Decl::Namespace: case Decl::Namespace:
case Decl::NamespaceAlias: case Decl::NamespaceAlias:
case Decl::NonTypeTemplateParm: case Decl::NonTypeTemplateParm:
case Decl::StaticAssert: case Decl::StaticAssert:
case Decl::TemplateTemplateParm: case Decl::TemplateTemplateParm:
case Decl::TemplateTypeParm: case Decl::TemplateTypeParm:
case Decl::UnresolvedUsingTypename: case Decl::UnresolvedUsingTypename:
case Decl::UnresolvedUsingValue: case Decl::UnresolvedUsingValue:
case Decl::Using: case Decl::Using:
case Decl::UsingDirective: case Decl::UsingDirective:
case Decl::UsingShadow: case Decl::UsingShadow:
return LanguageId::Cpp; return LanguageId::Cpp;
} }
} }
@ -187,7 +188,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
BaseType = PTy->getPointeeType(); BaseType = PTy->getPointeeType();
else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>()) else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
BaseType = BPy->getPointeeType(); BaseType = BPy->getPointeeType();
else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) else if (const ArrayType *ATy = dyn_cast<ArrayType>(BaseType))
BaseType = ATy->getElementType(); BaseType = ATy->getElementType();
else if (const VectorType *VTy = BaseType->getAs<VectorType>()) else if (const VectorType *VTy = BaseType->getAs<VectorType>())
BaseType = VTy->getElementType(); BaseType = VTy->getElementType();
@ -200,8 +201,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
BaseType = ATy->getDeducedType(); BaseType = ATy->getDeducedType();
else else
break; break;
} } else
else
break; break;
} }
return BaseType; return BaseType;
@ -210,7 +210,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
const Decl *GetTypeDecl(QualType T, bool *specialization = nullptr) { const Decl *GetTypeDecl(QualType T, bool *specialization = nullptr) {
Decl *D = nullptr; Decl *D = nullptr;
T = GetBaseType(T.getUnqualifiedType(), true); T = GetBaseType(T.getUnqualifiedType(), true);
const Type* TP = T.getTypePtrOrNull(); const Type *TP = T.getTypePtrOrNull();
if (!TP) if (!TP)
return nullptr; return nullptr;
@ -254,7 +254,7 @@ try_again:
D = cast<InjectedClassNameType>(TP)->getDecl(); D = cast<InjectedClassNameType>(TP)->getDecl();
break; break;
// FIXME: Template type parameters! // FIXME: Template type parameters!
case Type::Elaborated: case Type::Elaborated:
TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull(); TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull();
@ -266,19 +266,19 @@ try_again:
return D; return D;
} }
const Decl* GetSpecialized(const Decl* D) { const Decl *GetSpecialized(const Decl *D) {
if (!D) if (!D)
return D; return D;
Decl *Template = nullptr; Decl *Template = nullptr;
if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
if (const ClassTemplatePartialSpecializationDecl *PartialSpec if (const ClassTemplatePartialSpecializationDecl *PartialSpec =
= dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
Template = PartialSpec->getSpecializedTemplate(); Template = PartialSpec->getSpecializedTemplate();
else if (const ClassTemplateSpecializationDecl *ClassSpec else if (const ClassTemplateSpecializationDecl *ClassSpec =
= dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) { dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
llvm::PointerUnion<ClassTemplateDecl *, llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> Result ClassTemplatePartialSpecializationDecl *>
= ClassSpec->getSpecializedTemplateOrPartial(); Result = ClassSpec->getSpecializedTemplateOrPartial();
if (Result.is<ClassTemplateDecl *>()) if (Result.is<ClassTemplateDecl *>())
Template = Result.get<ClassTemplateDecl *>(); Template = Result.get<ClassTemplateDecl *>();
else else
@ -293,8 +293,8 @@ const Decl* GetSpecialized(const Decl* D) {
} else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
if (Var->isStaticDataMember()) if (Var->isStaticDataMember())
Template = Var->getInstantiatedFromStaticDataMember(); Template = Var->getInstantiatedFromStaticDataMember();
} else if (const RedeclarableTemplateDecl *Tmpl } else if (const RedeclarableTemplateDecl *Tmpl =
= dyn_cast<RedeclarableTemplateDecl>(D)) dyn_cast<RedeclarableTemplateDecl>(D))
Template = Tmpl->getInstantiatedFromMemberTemplate(); Template = Tmpl->getInstantiatedFromMemberTemplate();
else else
return nullptr; return nullptr;
@ -302,7 +302,7 @@ const Decl* GetSpecialized(const Decl* D) {
} }
bool ValidateRecord(const RecordDecl *RD) { bool ValidateRecord(const RecordDecl *RD) {
for (const auto *I : RD->fields()){ for (const auto *I : RD->fields()) {
QualType FQT = I->getType(); QualType FQT = I->getType();
if (FQT->isIncompleteType() || FQT->isDependentType()) if (FQT->isIncompleteType() || FQT->isDependentType())
return false; return false;
@ -317,12 +317,13 @@ bool ValidateRecord(const RecordDecl *RD) {
class IndexDataConsumer : public index::IndexDataConsumer { class IndexDataConsumer : public index::IndexDataConsumer {
public: public:
ASTContext *Ctx; ASTContext *Ctx;
IndexParam& param; IndexParam &param;
std::string GetComment(const Decl* D) { std::string GetComment(const Decl *D) {
SourceManager &SM = Ctx->getSourceManager(); SourceManager &SM = Ctx->getSourceManager();
const RawComment *RC = Ctx->getRawCommentForAnyRedecl(D); const RawComment *RC = Ctx->getRawCommentForAnyRedecl(D);
if (!RC) return ""; if (!RC)
return "";
StringRef Raw = RC->getRawText(Ctx->getSourceManager()); StringRef Raw = RC->getRawText(Ctx->getSourceManager());
SourceRange R = RC->getSourceRange(); SourceRange R = RC->getSourceRange();
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(R.getBegin()); std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(R.getBegin());
@ -425,7 +426,7 @@ public:
return PP; return PP;
} }
static void SimplifyAnonymous(std::string& name) { static void SimplifyAnonymous(std::string &name) {
for (std::string::size_type i = 0;;) { for (std::string::size_type i = 0;;) {
if ((i = name.find("(anonymous ", i)) == std::string::npos) if ((i = name.find("(anonymous ", i)) == std::string::npos)
break; break;
@ -479,7 +480,7 @@ public:
void SetVarName(const Decl *D, std::string_view short_name, void SetVarName(const Decl *D, std::string_view short_name,
std::string_view qualified, IndexVar::Def &def) { std::string_view qualified, IndexVar::Def &def) {
QualType T; QualType T;
const Expr* init = nullptr; const Expr *init = nullptr;
bool binding = false; bool binding = false;
if (auto *VD = dyn_cast<VarDecl>(D)) { if (auto *VD = dyn_cast<VarDecl>(D)) {
T = VD->getType(); T = VD->getType();
@ -499,7 +500,7 @@ public:
PrintingPolicy PP = GetDefaultPolicy(); PrintingPolicy PP = GetDefaultPolicy();
T.print(OS, PP); T.print(OS, PP);
if (Str.size() && if (Str.size() &&
(Str.back() != ' ' && Str.back() != '*' && Str.back() != '&')) (Str.back() != ' ' && Str.back() != '*' && Str.back() != '&'))
Str += ' '; Str += ' ';
def.qual_name_offset = Str.size(); def.qual_name_offset = Str.size();
def.short_name_offset = Str.size() + qualified.size() - short_name.size(); def.short_name_offset = Str.size() + qualified.size() - short_name.size();
@ -511,7 +512,7 @@ public:
} }
if (init) { if (init) {
SourceManager &SM = Ctx->getSourceManager(); SourceManager &SM = Ctx->getSourceManager();
const LangOptions& Lang = Ctx->getLangOpts(); const LangOptions &Lang = Ctx->getLangOpts();
SourceRange R = SM.getExpansionRange(init->getSourceRange()) SourceRange R = SM.getExpansionRange(init->getSourceRange())
#if LLVM_VERSION_MAJOR >= 7 #if LLVM_VERSION_MAJOR >= 7
.getAsRange() .getAsRange()
@ -536,7 +537,8 @@ public:
void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind, void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
SourceLocation Spell) const { SourceLocation Spell) const {
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell)); const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
if (!FE) return; if (!FE)
return;
auto UID = FE->getUniqueID(); auto UID = FE->getUniqueID();
auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID); auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID);
if (inserted) { if (inserted) {
@ -568,10 +570,8 @@ public:
} }
public: public:
IndexDataConsumer(IndexParam& param) : param(param) {} IndexDataConsumer(IndexParam &param) : param(param) {}
void initialize(ASTContext &Ctx) override { void initialize(ASTContext &Ctx) override { this->Ctx = param.Ctx = &Ctx; }
this->Ctx = param.Ctx = &Ctx;
}
bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles, bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
ArrayRef<index::SymbolRelation> Relations, ArrayRef<index::SymbolRelation> Relations,
#if LLVM_VERSION_MAJOR >= 7 #if LLVM_VERSION_MAJOR >= 7
@ -618,7 +618,7 @@ public:
if (!db) if (!db)
return true; return true;
const Decl* OrigD = ASTNode.OrigD; const Decl *OrigD = ASTNode.OrigD;
const DeclContext *SemDC = OrigD->getDeclContext(); const DeclContext *SemDC = OrigD->getDeclContext();
const DeclContext *LexDC = ASTNode.ContainerDC; const DeclContext *LexDC = ASTNode.ContainerDC;
Role role = static_cast<Role>(Roles); Role role = static_cast<Role>(Roles);
@ -632,7 +632,7 @@ public:
IndexType *type = nullptr; IndexType *type = nullptr;
IndexVar *var = nullptr; IndexVar *var = nullptr;
SymbolKind kind = GetSymbolKind(D); SymbolKind kind = GetSymbolKind(D);
IndexParam::DeclInfo* info; IndexParam::DeclInfo *info;
Usr usr = GetUsr(D, &info); Usr usr = GetUsr(D, &info);
auto do_def_decl = [&](auto *entity) { auto do_def_decl = [&](auto *entity) {
@ -690,7 +690,7 @@ public:
if (type->def.detailed_name[0] == '\0') if (type->def.detailed_name[0] == '\0')
SetName(OrigD, info->short_name, info->qualified, type->def); SetName(OrigD, info->short_name, info->qualified, type->def);
if (is_def || is_decl) { if (is_def || is_decl) {
const Decl* DC = cast<Decl>(SemDC); const Decl *DC = cast<Decl>(SemDC);
if (GetSymbolKind(DC) == SymbolKind::Type) if (GetSymbolKind(DC) == SymbolKind::Type)
db->ToType(GetUsr(DC)).def.types.push_back(usr); db->ToType(GetUsr(DC)).def.types.push_back(usr);
} }
@ -720,7 +720,7 @@ public:
db->ToType(usr1).instances.push_back(usr); db->ToType(usr1).instances.push_back(usr);
} else { } else {
for (const Decl *D1 = GetTypeDecl(T); D1; D1 = GetSpecialized(D1)) { for (const Decl *D1 = GetTypeDecl(T); D1; D1 = GetSpecialized(D1)) {
IndexParam::DeclInfo* info1; IndexParam::DeclInfo *info1;
Usr usr1 = GetUsr(D1, &info1); Usr usr1 = GetUsr(D1, &info1);
auto it = db->usr2type.find(usr1); auto it = db->usr2type.find(usr1);
if (it != db->usr2type.end()) { if (it != db->usr2type.end()) {
@ -728,10 +728,11 @@ public:
it->second.instances.push_back(usr); it->second.instances.push_back(usr);
break; break;
} }
// e.g. TemplateTypeParmDecl is not handled by handleDeclOccurence. // e.g. TemplateTypeParmDecl is not handled by
// handleDeclOccurence.
SourceRange R1 = D1->getSourceRange(); SourceRange R1 = D1->getSourceRange();
if (SM.getFileID(R1.getBegin()) == LocFID) { if (SM.getFileID(R1.getBegin()) == LocFID) {
IndexType& type1 = db->ToType(usr1); IndexType &type1 = db->ToType(usr1);
SourceLocation L1 = D1->getLocation(); SourceLocation L1 = D1->getLocation();
type1.def.spell = GetUse(db, FromTokenRange(SM, Lang, {L1, L1}), type1.def.spell = GetUse(db, FromTokenRange(SM, Lang, {L1, L1}),
SemDC, Role::Definition); SemDC, Role::Definition);
@ -935,7 +936,7 @@ public:
if (auto *ND = dyn_cast<NamedDecl>(D)) { if (auto *ND = dyn_cast<NamedDecl>(D)) {
SmallVector<const NamedDecl *, 8> OverDecls; SmallVector<const NamedDecl *, 8> OverDecls;
Ctx->getOverriddenMethods(ND, OverDecls); Ctx->getOverriddenMethods(ND, OverDecls);
for (const auto* ND1 : OverDecls) { for (const auto *ND1 : OverDecls) {
Usr usr1 = GetUsr(ND1); Usr usr1 = GetUsr(ND1);
func->def.bases.push_back(usr1); func->def.bases.push_back(usr1);
db->ToFunc(usr1).derived.push_back(usr); db->ToFunc(usr1).derived.push_back(usr);
@ -988,10 +989,10 @@ public:
}; };
class IndexPPCallbacks : public PPCallbacks { class IndexPPCallbacks : public PPCallbacks {
SourceManager& SM; SourceManager &SM;
IndexParam& param; IndexParam &param;
std::pair<StringRef, Usr> GetMacro(const Token& Tok) const { std::pair<StringRef, Usr> GetMacro(const Token &Tok) const {
StringRef Name = Tok.getIdentifierInfo()->getName(); StringRef Name = Tok.getIdentifierInfo()->getName();
SmallString<256> USR("@macro@"); SmallString<256> USR("@macro@");
USR += Name; USR += Name;
@ -1028,13 +1029,13 @@ public:
} }
void MacroDefined(const Token &Tok, const MacroDirective *MD) override { void MacroDefined(const Token &Tok, const MacroDirective *MD) override {
llvm::sys::fs::UniqueID UniqueID; llvm::sys::fs::UniqueID UniqueID;
const LangOptions& Lang = param.Ctx->getLangOpts(); const LangOptions &Lang = param.Ctx->getLangOpts();
SourceLocation L = MD->getLocation(); SourceLocation L = MD->getLocation();
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L)); const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
if (!FE) if (!FE)
return; return;
if (IndexFile *db = param.ConsumeFile(*FE)) { if (IndexFile *db = param.ConsumeFile(*FE)) {
auto[Name, usr] = GetMacro(Tok); auto [Name, usr] = GetMacro(Tok);
IndexVar &var = db->ToVar(usr); IndexVar &var = db->ToVar(usr);
auto range = FromTokenRange(SM, Lang, {L, L}, &UniqueID); auto range = FromTokenRange(SM, Lang, {L, L}, &UniqueID);
var.def.kind = lsSymbolKind::Macro; var.def.kind = lsSymbolKind::Macro;
@ -1056,15 +1057,15 @@ public:
} }
} }
} }
void MacroExpands(const Token &Tok, const MacroDefinition &MD, void MacroExpands(const Token &Tok, const MacroDefinition &MD, SourceRange R,
SourceRange R, const MacroArgs *Args) override { const MacroArgs *Args) override {
llvm::sys::fs::UniqueID UniqueID; llvm::sys::fs::UniqueID UniqueID;
SourceLocation L = SM.getSpellingLoc(R.getBegin()); SourceLocation L = SM.getSpellingLoc(R.getBegin());
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L)); const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
if (!FE) if (!FE)
return; return;
if (IndexFile *db = param.ConsumeFile(*FE)) { if (IndexFile *db = param.ConsumeFile(*FE)) {
auto[Name, usr] = GetMacro(Tok); auto [Name, usr] = GetMacro(Tok);
IndexVar &var = db->ToVar(usr); IndexVar &var = db->ToVar(usr);
var.uses.push_back( var.uses.push_back(
{{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0, {{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
@ -1088,17 +1089,19 @@ public:
}; };
class IndexFrontendAction : public ASTFrontendAction { class IndexFrontendAction : public ASTFrontendAction {
IndexParam& param; IndexParam &param;
public: public:
IndexFrontendAction(IndexParam& param) : param(param) {} IndexFrontendAction(IndexParam &param) : param(param) {}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override { StringRef InFile) override {
Preprocessor &PP = CI.getPreprocessor(); Preprocessor &PP = CI.getPreprocessor();
PP.addPPCallbacks(std::make_unique<IndexPPCallbacks>(PP.getSourceManager(), param)); PP.addPPCallbacks(
std::make_unique<IndexPPCallbacks>(PP.getSourceManager(), param));
return std::make_unique<ASTConsumer>(); return std::make_unique<ASTConsumer>();
} }
}; };
} } // namespace
const int IndexFile::kMajorVersion = 17; const int IndexFile::kMajorVersion = 17;
const int IndexFile::kMinorVersion = 1; const int IndexFile::kMinorVersion = 1;
@ -1107,21 +1110,21 @@ IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
const std::string &contents) const std::string &contents)
: UniqueID(UniqueID), path(path), file_contents(contents) {} : UniqueID(UniqueID), path(path), file_contents(contents) {}
IndexFunc& IndexFile::ToFunc(Usr usr) { IndexFunc &IndexFile::ToFunc(Usr usr) {
auto [it, inserted] = usr2func.try_emplace(usr); auto [it, inserted] = usr2func.try_emplace(usr);
if (inserted) if (inserted)
it->second.usr = usr; it->second.usr = usr;
return it->second; return it->second;
} }
IndexType& IndexFile::ToType(Usr usr) { IndexType &IndexFile::ToType(Usr usr) {
auto [it, inserted] = usr2type.try_emplace(usr); auto [it, inserted] = usr2type.try_emplace(usr);
if (inserted) if (inserted)
it->second.usr = usr; it->second.usr = usr;
return it->second; return it->second;
} }
IndexVar& IndexFile::ToVar(Usr usr) { IndexVar &IndexFile::ToVar(Usr usr) {
auto [it, inserted] = usr2var.try_emplace(usr); auto [it, inserted] = usr2var.try_emplace(usr);
if (inserted) if (inserted)
it->second.usr = usr; it->second.usr = usr;
@ -1132,8 +1135,7 @@ std::string IndexFile::ToString() {
return ccls::Serialize(SerializeFormat::Json, *this); return ccls::Serialize(SerializeFormat::Json, *this);
} }
template <typename T> template <typename T> void Uniquify(std::vector<T> &a) {
void Uniquify(std::vector<T>& a) {
std::unordered_set<T> seen; std::unordered_set<T> seen;
size_t n = 0; size_t n = 0;
for (size_t i = 0; i < a.size(); i++) for (size_t i = 0; i < a.size(); i++)
@ -1143,21 +1145,19 @@ void Uniquify(std::vector<T>& a) {
} }
namespace ccls::idx { namespace ccls::idx {
std::vector<std::unique_ptr<IndexFile>> Index( std::vector<std::unique_ptr<IndexFile>>
VFS* vfs, Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
const std::string& opt_wdir, const std::vector<std::string> &args,
const std::string& file, const std::vector<FileContents> &file_contents) {
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents) {
if (!g_config->index.enabled) if (!g_config->index.enabled)
return {}; return {};
std::vector<const char *> Args; std::vector<const char *> Args;
for (auto& arg: args) for (auto &arg : args)
Args.push_back(arg.c_str()); Args.push_back(arg.c_str());
auto PCHCO = std::make_shared<PCHContainerOperations>(); auto PCHCO = std::make_shared<PCHContainerOperations>();
IntrusiveRefCntPtr<DiagnosticsEngine> IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); CompilerInstance::createDiagnostics(new DiagnosticOptions));
std::shared_ptr<CompilerInvocation> CI = std::shared_ptr<CompilerInvocation> CI =
createInvocationFromCommandLine(Args, Diags); createInvocationFromCommandLine(Args, Diags);
if (!CI) if (!CI)
@ -1225,34 +1225,34 @@ std::vector<std::unique_ptr<IndexFile>> Index(
return {}; return {};
} }
const SourceManager& SM = Unit->getSourceManager(); const SourceManager &SM = Unit->getSourceManager();
const FileEntry* FE = SM.getFileEntryForID(SM.getMainFileID()); const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
IndexFile* main_file = param.ConsumeFile(*FE); IndexFile *main_file = param.ConsumeFile(*FE);
std::unordered_map<std::string, int> inc_to_line; std::unordered_map<std::string, int> inc_to_line;
if (main_file) if (main_file)
for (auto& inc : main_file->includes) for (auto &inc : main_file->includes)
inc_to_line[inc.resolved_path] = inc.line; inc_to_line[inc.resolved_path] = inc.line;
auto result = param.file_consumer->TakeLocalState(); auto result = param.file_consumer->TakeLocalState();
for (std::unique_ptr<IndexFile>& entry : result) { for (std::unique_ptr<IndexFile> &entry : result) {
entry->import_file = file; entry->import_file = file;
entry->args = args; entry->args = args;
for (auto &[_, it] : entry->uid2lid_and_path) for (auto &[_, it] : entry->uid2lid_and_path)
entry->lid2path.emplace_back(it.first, std::move(it.second)); entry->lid2path.emplace_back(it.first, std::move(it.second));
entry->uid2lid_and_path.clear(); entry->uid2lid_and_path.clear();
for (auto& it : entry->usr2func) { for (auto &it : entry->usr2func) {
// e.g. declaration + out-of-line definition // e.g. declaration + out-of-line definition
Uniquify(it.second.derived); Uniquify(it.second.derived);
Uniquify(it.second.uses); Uniquify(it.second.uses);
} }
for (auto& it : entry->usr2type) { for (auto &it : entry->usr2type) {
Uniquify(it.second.derived); Uniquify(it.second.derived);
Uniquify(it.second.uses); Uniquify(it.second.uses);
// e.g. declaration + out-of-line definition // e.g. declaration + out-of-line definition
Uniquify(it.second.def.bases); Uniquify(it.second.def.bases);
Uniquify(it.second.def.funcs); Uniquify(it.second.def.funcs);
} }
for (auto& it : entry->usr2var) for (auto &it : entry->usr2var)
Uniquify(it.second.uses); Uniquify(it.second.uses);
if (main_file) { if (main_file) {
@ -1283,7 +1283,7 @@ std::vector<std::unique_ptr<IndexFile>> Index(
return result; return result;
} }
} } // namespace ccls::idx
// |SymbolRef| is serialized this way. // |SymbolRef| is serialized this way.
// |Use| also uses this though it has an extra field |file|, // |Use| also uses this though it has an extra field |file|,
@ -1319,10 +1319,10 @@ void Reflect(Writer &vis, Reference &v) {
} }
} }
void Reflect(Reader& vis, Use& v) { void Reflect(Reader &vis, Use &v) {
if (vis.Format() == SerializeFormat::Json) { if (vis.Format() == SerializeFormat::Json) {
std::string t = vis.GetString(); std::string t = vis.GetString();
char* s = const_cast<char*>(t.c_str()); char *s = const_cast<char *>(t.c_str());
v.range = Range::FromString(s); v.range = Range::FromString(s);
s = strchr(s, '|'); s = strchr(s, '|');
v.usr = strtoull(s + 1, &s, 10); v.usr = strtoull(s + 1, &s, 10);
@ -1331,11 +1331,11 @@ void Reflect(Reader& vis, Use& v) {
if (*s == '|') if (*s == '|')
v.file_id = static_cast<int>(strtol(s + 1, &s, 10)); v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
} else { } else {
Reflect(vis, static_cast<Reference&>(v)); Reflect(vis, static_cast<Reference &>(v));
Reflect(vis, v.file_id); Reflect(vis, v.file_id);
} }
} }
void Reflect(Writer& vis, Use& v) { void Reflect(Writer &vis, Use &v) {
if (vis.Format() == SerializeFormat::Json) { if (vis.Format() == SerializeFormat::Json) {
char buf[99]; char buf[99];
if (v.file_id == -1) if (v.file_id == -1)
@ -1348,7 +1348,7 @@ void Reflect(Writer& vis, Use& v) {
std::string s(buf); std::string s(buf);
Reflect(vis, s); Reflect(vis, s);
} else { } else {
Reflect(vis, static_cast<Reference&>(v)); Reflect(vis, static_cast<Reference &>(v));
Reflect(vis, v.file_id); Reflect(vis, v.file_id);
} }
} }

View File

@ -14,9 +14,9 @@
#include <clang/Basic/Specifiers.h> #include <clang/Basic/Specifiers.h>
#include <llvm/ADT/StringMap.h> #include <llvm/ADT/StringMap.h>
#include <stdint.h>
#include <algorithm> #include <algorithm>
#include <optional> #include <optional>
#include <stdint.h>
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -27,10 +27,10 @@ struct SymbolIdx {
Usr usr; Usr usr;
SymbolKind kind; SymbolKind kind;
bool operator==(const SymbolIdx& o) const { bool operator==(const SymbolIdx &o) const {
return usr == o.usr && kind == o.kind; return usr == o.usr && kind == o.kind;
} }
bool operator<(const SymbolIdx& o) const { bool operator<(const SymbolIdx &o) const {
return usr != o.usr ? usr < o.usr : kind < o.kind; return usr != o.usr ? usr < o.usr : kind < o.kind;
} }
}; };
@ -47,8 +47,8 @@ struct Reference {
std::tuple<Range, Usr, SymbolKind, Role> ToTuple() const { std::tuple<Range, Usr, SymbolKind, Role> ToTuple() const {
return std::make_tuple(range, usr, kind, role); return std::make_tuple(range, usr, kind, role);
} }
bool operator==(const Reference& o) const { return ToTuple() == o.ToTuple(); } bool operator==(const Reference &o) const { return ToTuple() == o.ToTuple(); }
bool operator<(const Reference& o) const { return ToTuple() < o.ToTuple(); } bool operator<(const Reference &o) const { return ToTuple() < o.ToTuple(); }
}; };
// |id,kind| refer to the referenced entity. // |id,kind| refer to the referenced entity.
@ -60,22 +60,21 @@ MAKE_HASHABLE(SymbolRef, t.range, t.usr, t.kind, t.role);
struct Use : Reference { struct Use : Reference {
// |file| is used in Query* but not in Index* // |file| is used in Query* but not in Index*
int file_id = -1; int file_id = -1;
bool operator==(const Use& o) const { bool operator==(const Use &o) const {
// lexical container info is ignored. // lexical container info is ignored.
return range == o.range && file_id == o.file_id; return range == o.range && file_id == o.file_id;
} }
}; };
MAKE_HASHABLE(Use, t.range, t.file_id) MAKE_HASHABLE(Use, t.range, t.file_id)
void Reflect(Reader& visitor, Reference& value); void Reflect(Reader &visitor, Reference &value);
void Reflect(Writer& visitor, Reference& value); void Reflect(Writer &visitor, Reference &value);
void Reflect(Reader& visitor, Use& value); void Reflect(Reader &visitor, Use &value);
void Reflect(Writer& visitor, Use& value); void Reflect(Writer &visitor, Use &value);
template <typename D> template <typename D> struct NameMixin {
struct NameMixin {
std::string_view Name(bool qualified) const { std::string_view Name(bool qualified) const {
auto self = static_cast<const D*>(this); auto self = static_cast<const D *>(this);
return qualified return qualified
? std::string_view(self->detailed_name + self->qual_name_offset, ? std::string_view(self->detailed_name + self->qual_name_offset,
self->short_name_offset - self->short_name_offset -
@ -88,9 +87,9 @@ struct NameMixin {
struct FuncDef : NameMixin<FuncDef> { struct FuncDef : NameMixin<FuncDef> {
// General metadata. // General metadata.
const char* detailed_name = ""; const char *detailed_name = "";
const char* hover = ""; const char *hover = "";
const char* comments = ""; const char *comments = "";
Maybe<Use> spell; Maybe<Use> spell;
Maybe<Use> extent; Maybe<Use> extent;
@ -112,20 +111,9 @@ struct FuncDef : NameMixin<FuncDef> {
std::vector<Usr> GetBases() const { return bases; } std::vector<Usr> GetBases() const { return bases; }
}; };
MAKE_REFLECT_STRUCT(FuncDef, MAKE_REFLECT_STRUCT(FuncDef, detailed_name, qual_name_offset, short_name_offset,
detailed_name, short_name_size, kind, storage, hover, comments, spell,
qual_name_offset, extent, bases, vars, callees);
short_name_offset,
short_name_size,
kind,
storage,
hover,
comments,
spell,
extent,
bases,
vars,
callees);
struct IndexFunc : NameMixin<IndexFunc> { struct IndexFunc : NameMixin<IndexFunc> {
using Def = FuncDef; using Def = FuncDef;
@ -137,9 +125,9 @@ struct IndexFunc : NameMixin<IndexFunc> {
}; };
struct TypeDef : NameMixin<TypeDef> { struct TypeDef : NameMixin<TypeDef> {
const char* detailed_name = ""; const char *detailed_name = "";
const char* hover = ""; const char *hover = "";
const char* comments = ""; const char *comments = "";
Maybe<Use> spell; Maybe<Use> spell;
Maybe<Use> extent; Maybe<Use> extent;
@ -163,21 +151,9 @@ struct TypeDef : NameMixin<TypeDef> {
std::vector<Usr> GetBases() const { return bases; } std::vector<Usr> GetBases() const { return bases; }
}; };
MAKE_REFLECT_STRUCT(TypeDef, MAKE_REFLECT_STRUCT(TypeDef, detailed_name, qual_name_offset, short_name_offset,
detailed_name, short_name_size, kind, hover, comments, spell, extent,
qual_name_offset, alias_of, bases, types, funcs, vars);
short_name_offset,
short_name_size,
kind,
hover,
comments,
spell,
extent,
alias_of,
bases,
types,
funcs,
vars);
struct IndexType { struct IndexType {
using Def = TypeDef; using Def = TypeDef;
@ -191,9 +167,9 @@ struct IndexType {
struct VarDef : NameMixin<VarDef> { struct VarDef : NameMixin<VarDef> {
// General metadata. // General metadata.
const char* detailed_name = ""; const char *detailed_name = "";
const char* hover = ""; const char *hover = "";
const char* comments = ""; const char *comments = "";
Maybe<Use> spell; Maybe<Use> spell;
Maybe<Use> extent; Maybe<Use> extent;
@ -217,17 +193,8 @@ struct VarDef : NameMixin<VarDef> {
std::vector<Usr> GetBases() const { return {}; } std::vector<Usr> GetBases() const { return {}; }
}; };
MAKE_REFLECT_STRUCT(VarDef, MAKE_REFLECT_STRUCT(VarDef, detailed_name, qual_name_offset, short_name_offset,
detailed_name, short_name_size, hover, comments, spell, extent, type, kind,
qual_name_offset,
short_name_offset,
short_name_size,
hover,
comments,
spell,
extent,
type,
kind,
storage); storage);
struct IndexVar { struct IndexVar {
@ -289,9 +256,9 @@ struct IndexFile {
IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path, IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
const std::string &contents); const std::string &contents);
IndexFunc& ToFunc(Usr usr); IndexFunc &ToFunc(Usr usr);
IndexType& ToType(Usr usr); IndexType &ToType(Usr usr);
IndexVar& ToVar(Usr usr); IndexVar &ToVar(Usr usr);
std::string ToString(); std::string ToString();
}; };
@ -299,6 +266,6 @@ struct IndexFile {
namespace ccls::idx { namespace ccls::idx {
std::vector<std::unique_ptr<IndexFile>> std::vector<std::unique_ptr<IndexFile>>
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file, Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
const std::vector<std::string> &args, const std::vector<std::string> &args,
const std::vector<FileContents> &file_contents); const std::vector<FileContents> &file_contents);
} }

View File

@ -14,7 +14,7 @@ LanguageId SourceFileLanguage(std::string_view path) {
return LanguageId::Unknown; return LanguageId::Unknown;
} }
const char* LanguageIdentifier(LanguageId lang) { const char *LanguageIdentifier(LanguageId lang) {
switch (lang) { switch (lang) {
case LanguageId::C: case LanguageId::C:
return "c"; return "c";

View File

@ -11,4 +11,4 @@ enum class LanguageId { Unknown = 0, C = 1, Cpp = 2, ObjC = 3, ObjCpp = 4 };
MAKE_REFLECT_TYPE_PROXY(LanguageId); MAKE_REFLECT_TYPE_PROXY(LanguageId);
LanguageId SourceFileLanguage(std::string_view path); LanguageId SourceFileLanguage(std::string_view path);
const char* LanguageIdentifier(LanguageId lang); const char *LanguageIdentifier(LanguageId lang);

View File

@ -3,18 +3,18 @@
#include <llvm/ADT/SmallString.h> #include <llvm/ADT/SmallString.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
#include <iomanip>
#include <mutex>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <iomanip>
#include <mutex>
namespace ccls::log { namespace ccls::log {
static std::mutex mtx; static std::mutex mtx;
FILE* file; FILE *file;
Verbosity verbosity; Verbosity verbosity;
Message::Message(Verbosity verbosity, const char* file, int line) Message::Message(Verbosity verbosity, const char *file, int line)
: verbosity_(verbosity) { : verbosity_(verbosity) {
using namespace llvm; using namespace llvm;
time_t tim = time(NULL); time_t tim = time(NULL);
@ -32,7 +32,7 @@ Message::Message(Verbosity verbosity, const char* file, int line)
stream_ << std::left << std::setw(13) << Name.c_str(); stream_ << std::left << std::setw(13) << Name.c_str();
} }
{ {
const char* p = strrchr(file, '/'); const char *p = strrchr(file, '/');
if (p) if (p)
file = p + 1; file = p + 1;
stream_ << std::right << std::setw(15) << file << ':' << std::left stream_ << std::right << std::setw(15) << file << ':' << std::left
@ -52,11 +52,12 @@ Message::Message(Verbosity verbosity, const char* file, int line)
} }
Message::~Message() { Message::~Message() {
if (!file) return; if (!file)
return;
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
stream_ << '\n'; stream_ << '\n';
fputs(stream_.str().c_str(), file); fputs(stream_.str().c_str(), file);
if (verbosity_ == Verbosity_FATAL) if (verbosity_ == Verbosity_FATAL)
abort(); abort();
} }
} } // namespace ccls::log

View File

@ -8,31 +8,29 @@
// Cache that evicts old entries which have not been used recently. Implemented // Cache that evicts old entries which have not been used recently. Implemented
// using array/linear search so this works well for small array sizes. // using array/linear search so this works well for small array sizes.
template <typename TKey, typename TValue> template <typename TKey, typename TValue> struct LruCache {
struct LruCache {
explicit LruCache(int max_entries); explicit LruCache(int max_entries);
// Fetches an entry for |key|. If it does not exist, |allocator| will be // Fetches an entry for |key|. If it does not exist, |allocator| will be
// invoked to create one. // invoked to create one.
template <typename TAllocator> template <typename TAllocator>
std::shared_ptr<TValue> Get(const TKey& key, TAllocator allocator); std::shared_ptr<TValue> Get(const TKey &key, TAllocator allocator);
// Fetches the entry for |filename| and updates it's usage so it is less // Fetches the entry for |filename| and updates it's usage so it is less
// likely to be evicted. // likely to be evicted.
std::shared_ptr<TValue> TryGet(const TKey& key); std::shared_ptr<TValue> TryGet(const TKey &key);
// TryGetEntry, except the entry is removed from the cache. // TryGetEntry, except the entry is removed from the cache.
std::shared_ptr<TValue> TryTake(const TKey& key); std::shared_ptr<TValue> TryTake(const TKey &key);
// Inserts an entry. Evicts the oldest unused entry if there is no space. // Inserts an entry. Evicts the oldest unused entry if there is no space.
void Insert(const TKey& key, const std::shared_ptr<TValue>& value); void Insert(const TKey &key, const std::shared_ptr<TValue> &value);
// Call |func| on existing entries. If |func| returns false iteration // Call |func| on existing entries. If |func| returns false iteration
// temrinates early. // temrinates early.
template <typename TFunc> template <typename TFunc> void IterateValues(TFunc func);
void IterateValues(TFunc func);
// Empties the cache // Empties the cache
void Clear(void); void Clear(void);
private: private:
// There is a global score counter, when we access an element we increase // There is a global score counter, when we access an element we increase
// its score to the current global value, so it has the highest overall // its score to the current global value, so it has the highest overall
// score. This means that the oldest/least recently accessed value has the // score. This means that the oldest/least recently accessed value has the
@ -43,7 +41,7 @@ struct LruCache {
uint32_t score = 0; uint32_t score = 0;
TKey key; TKey key;
std::shared_ptr<TValue> value; std::shared_ptr<TValue> value;
bool operator<(const Entry& other) const { return score < other.score; } bool operator<(const Entry &other) const { return score < other.score; }
}; };
void IncrementScore(); void IncrementScore();
@ -60,7 +58,7 @@ LruCache<TKey, TValue>::LruCache(int max_entries) : max_entries_(max_entries) {
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
template <typename TAllocator> template <typename TAllocator>
std::shared_ptr<TValue> LruCache<TKey, TValue>::Get(const TKey& key, std::shared_ptr<TValue> LruCache<TKey, TValue>::Get(const TKey &key,
TAllocator allocator) { TAllocator allocator) {
std::shared_ptr<TValue> result = TryGet(key); std::shared_ptr<TValue> result = TryGet(key);
if (!result) if (!result)
@ -69,9 +67,9 @@ std::shared_ptr<TValue> LruCache<TKey, TValue>::Get(const TKey& key,
} }
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
std::shared_ptr<TValue> LruCache<TKey, TValue>::TryGet(const TKey& key) { std::shared_ptr<TValue> LruCache<TKey, TValue>::TryGet(const TKey &key) {
// Assign new score. // Assign new score.
for (Entry& entry : entries_) { for (Entry &entry : entries_) {
if (entry.key == key) { if (entry.key == key) {
entry.score = next_score_; entry.score = next_score_;
IncrementScore(); IncrementScore();
@ -83,7 +81,7 @@ std::shared_ptr<TValue> LruCache<TKey, TValue>::TryGet(const TKey& key) {
} }
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
std::shared_ptr<TValue> LruCache<TKey, TValue>::TryTake(const TKey& key) { std::shared_ptr<TValue> LruCache<TKey, TValue>::TryTake(const TKey &key) {
for (size_t i = 0; i < entries_.size(); ++i) { for (size_t i = 0; i < entries_.size(); ++i) {
if (entries_[i].key == key) { if (entries_[i].key == key) {
std::shared_ptr<TValue> copy = entries_[i].value; std::shared_ptr<TValue> copy = entries_[i].value;
@ -96,8 +94,8 @@ std::shared_ptr<TValue> LruCache<TKey, TValue>::TryTake(const TKey& key) {
} }
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::Insert(const TKey& key, void LruCache<TKey, TValue>::Insert(const TKey &key,
const std::shared_ptr<TValue>& value) { const std::shared_ptr<TValue> &value) {
if ((int)entries_.size() >= max_entries_) if ((int)entries_.size() >= max_entries_)
entries_.erase(std::min_element(entries_.begin(), entries_.end())); entries_.erase(std::min_element(entries_.begin(), entries_.end()));
@ -112,7 +110,7 @@ void LruCache<TKey, TValue>::Insert(const TKey& key,
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
template <typename TFunc> template <typename TFunc>
void LruCache<TKey, TValue>::IterateValues(TFunc func) { void LruCache<TKey, TValue>::IterateValues(TFunc func) {
for (Entry& entry : entries_) { for (Entry &entry : entries_) {
if (!func(entry.value)) if (!func(entry.value))
break; break;
} }
@ -123,13 +121,13 @@ void LruCache<TKey, TValue>::IncrementScore() {
// Overflow. // Overflow.
if (++next_score_ == 0) { if (++next_score_ == 0) {
std::sort(entries_.begin(), entries_.end()); std::sort(entries_.begin(), entries_.end());
for (Entry& entry : entries_) for (Entry &entry : entries_)
entry.score = next_score_++; entry.score = next_score_++;
} }
} }
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::Clear(void) { void LruCache<TKey, TValue>::Clear(void) {
entries_.clear(); entries_.clear();
next_score_ = 0; next_score_ = 0;
} }

View File

@ -7,7 +7,7 @@
#include <stdio.h> #include <stdio.h>
MessageRegistry* MessageRegistry::instance_ = nullptr; MessageRegistry *MessageRegistry::instance_ = nullptr;
lsTextDocumentIdentifier lsTextDocumentIdentifier
lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const { lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const {
@ -17,8 +17,8 @@ lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const {
} }
// Reads a JsonRpc message. |read| returns the next input character. // Reads a JsonRpc message. |read| returns the next input character.
std::optional<std::string> ReadJsonRpcContentFrom( std::optional<std::string>
std::function<std::optional<char>()> read) { ReadJsonRpcContentFrom(std::function<std::optional<char>()> read) {
// Read the content length. It is terminated by the "\r\n" sequence. // Read the content length. It is terminated by the "\r\n" sequence.
int exit_seq = 0; int exit_seq = 0;
std::string stringified_content_length; std::string stringified_content_length;
@ -37,7 +37,7 @@ std::optional<std::string> ReadJsonRpcContentFrom(
stringified_content_length += c; stringified_content_length += c;
} }
const char* kContentLengthStart = "Content-Length: "; const char *kContentLengthStart = "Content-Length: ";
assert(StartsWith(stringified_content_length, kContentLengthStart)); assert(StartsWith(stringified_content_length, kContentLengthStart));
int content_length = int content_length =
atoi(stringified_content_length.c_str() + strlen(kContentLengthStart)); atoi(stringified_content_length.c_str() + strlen(kContentLengthStart));
@ -78,8 +78,8 @@ std::optional<char> ReadCharFromStdinBlocking() {
return std::nullopt; return std::nullopt;
} }
std::optional<std::string> MessageRegistry::ReadMessageFromStdin( std::optional<std::string>
std::unique_ptr<InMessage>* message) { MessageRegistry::ReadMessageFromStdin(std::unique_ptr<InMessage> *message) {
std::optional<std::string> content = std::optional<std::string> content =
ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking); ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
if (!content) { if (!content) {
@ -95,9 +95,8 @@ std::optional<std::string> MessageRegistry::ReadMessageFromStdin(
return Parse(json_reader, message); return Parse(json_reader, message);
} }
std::optional<std::string> MessageRegistry::Parse( std::optional<std::string>
Reader& visitor, MessageRegistry::Parse(Reader &visitor, std::unique_ptr<InMessage> *message) {
std::unique_ptr<InMessage>* message) {
if (!visitor.HasMember("jsonrpc") || if (!visitor.HasMember("jsonrpc") ||
std::string(visitor["jsonrpc"]->GetString()) != "2.0") { std::string(visitor["jsonrpc"]->GetString()) != "2.0") {
LOG_S(FATAL) << "Bad or missing jsonrpc version"; LOG_S(FATAL) << "Bad or missing jsonrpc version";
@ -111,20 +110,20 @@ std::optional<std::string> MessageRegistry::Parse(
return std::string("Unable to find registered handler for method '") + return std::string("Unable to find registered handler for method '") +
method + "'"; method + "'";
Allocator& allocator = allocators[method]; Allocator &allocator = allocators[method];
try { try {
allocator(visitor, message); allocator(visitor, message);
return std::nullopt; return std::nullopt;
} catch (std::invalid_argument& e) { } catch (std::invalid_argument &e) {
// *message is partially deserialized but some field (e.g. |id|) are likely // *message is partially deserialized but some field (e.g. |id|) are likely
// available. // available.
return std::string("Fail to parse '") + method + "' " + return std::string("Fail to parse '") + method + "' " +
static_cast<JsonReader&>(visitor).GetPath() + ", expected " + static_cast<JsonReader &>(visitor).GetPath() + ", expected " +
e.what(); e.what();
} }
} }
MessageRegistry* MessageRegistry::instance() { MessageRegistry *MessageRegistry::instance() {
if (!instance_) if (!instance_)
instance_ = new MessageRegistry(); instance_ = new MessageRegistry();
@ -133,7 +132,7 @@ MessageRegistry* MessageRegistry::instance() {
lsBaseOutMessage::~lsBaseOutMessage() = default; lsBaseOutMessage::~lsBaseOutMessage() = default;
void lsBaseOutMessage::Write(std::ostream& out) { void lsBaseOutMessage::Write(std::ostream &out) {
rapidjson::StringBuffer output; rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> writer(output); rapidjson::Writer<rapidjson::StringBuffer> writer(output);
JsonWriter json_writer{&writer}; JsonWriter json_writer{&writer};
@ -144,8 +143,8 @@ void lsBaseOutMessage::Write(std::ostream& out) {
out.flush(); out.flush();
} }
void lsResponseError::Write(Writer& visitor) { void lsResponseError::Write(Writer &visitor) {
auto& value = *this; auto &value = *this;
int code2 = static_cast<int>(this->code); int code2 = static_cast<int>(this->code);
visitor.StartObject(); visitor.StartObject();
@ -154,22 +153,22 @@ void lsResponseError::Write(Writer& visitor) {
visitor.EndObject(); visitor.EndObject();
} }
lsDocumentUri lsDocumentUri::FromPath(const std::string& path) { lsDocumentUri lsDocumentUri::FromPath(const std::string &path) {
lsDocumentUri result; lsDocumentUri result;
result.SetPath(path); result.SetPath(path);
return result; return result;
} }
bool lsDocumentUri::operator==(const lsDocumentUri& other) const { bool lsDocumentUri::operator==(const lsDocumentUri &other) const {
return raw_uri == other.raw_uri; return raw_uri == other.raw_uri;
} }
void lsDocumentUri::SetPath(const std::string& path) { void lsDocumentUri::SetPath(const std::string &path) {
// file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests // file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests
raw_uri = path; raw_uri = path;
size_t index = raw_uri.find(":"); size_t index = raw_uri.find(":");
if (index == 1) { // widows drive letters must always be 1 char if (index == 1) { // widows drive letters must always be 1 char
raw_uri.replace(raw_uri.begin() + index, raw_uri.begin() + index + 1, raw_uri.replace(raw_uri.begin() + index, raw_uri.begin() + index + 1,
"%3A"); "%3A");
} }
@ -231,11 +230,11 @@ std::string lsPosition::ToString() const {
return std::to_string(line) + ":" + std::to_string(character); return std::to_string(line) + ":" + std::to_string(character);
} }
bool lsTextEdit::operator==(const lsTextEdit& that) { bool lsTextEdit::operator==(const lsTextEdit &that) {
return range == that.range && newText == that.newText; return range == that.range && newText == that.newText;
} }
void Reflect(Writer& visitor, lsMarkedString& value) { void Reflect(Writer &visitor, lsMarkedString &value) {
// If there is a language, emit a `{language:string, value:string}` object. If // If there is a language, emit a `{language:string, value:string}` object. If
// not, emit a string. // not, emit a string.
if (value.language) { if (value.language) {

View File

@ -8,52 +8,50 @@
#include <iosfwd> #include <iosfwd>
#include <unordered_map> #include <unordered_map>
#define REGISTER_IN_MESSAGE(type) \ #define REGISTER_IN_MESSAGE(type) \
static MessageRegistryRegister<type> type##message_handler_instance_; static MessageRegistryRegister<type> type##message_handler_instance_;
struct MessageRegistry { struct MessageRegistry {
static MessageRegistry* instance_; static MessageRegistry *instance_;
static MessageRegistry* instance(); static MessageRegistry *instance();
using Allocator = using Allocator =
std::function<void(Reader& visitor, std::unique_ptr<InMessage>*)>; std::function<void(Reader &visitor, std::unique_ptr<InMessage> *)>;
std::unordered_map<std::string, Allocator> allocators; std::unordered_map<std::string, Allocator> allocators;
std::optional<std::string> ReadMessageFromStdin( std::optional<std::string>
std::unique_ptr<InMessage>* message); ReadMessageFromStdin(std::unique_ptr<InMessage> *message);
std::optional<std::string> Parse(Reader& visitor, std::optional<std::string> Parse(Reader &visitor,
std::unique_ptr<InMessage>* message); std::unique_ptr<InMessage> *message);
}; };
template <typename T> template <typename T> struct MessageRegistryRegister {
struct MessageRegistryRegister {
MessageRegistryRegister() { MessageRegistryRegister() {
T dummy; T dummy;
std::string method_name = dummy.GetMethodType(); std::string method_name = dummy.GetMethodType();
MessageRegistry::instance()->allocators[method_name] = MessageRegistry::instance()->allocators[method_name] =
[](Reader& visitor, std::unique_ptr<InMessage>* message) { [](Reader &visitor, std::unique_ptr<InMessage> *message) {
*message = std::make_unique<T>(); *message = std::make_unique<T>();
// Reflect may throw and *message will be partially deserialized. // Reflect may throw and *message will be partially deserialized.
Reflect(visitor, static_cast<T&>(**message)); Reflect(visitor, static_cast<T &>(**message));
}; };
} }
}; };
struct lsBaseOutMessage { struct lsBaseOutMessage {
virtual ~lsBaseOutMessage(); virtual ~lsBaseOutMessage();
virtual void ReflectWriter(Writer&) = 0; virtual void ReflectWriter(Writer &) = 0;
// Send the message to the language client by writing it to stdout. // Send the message to the language client by writing it to stdout.
void Write(std::ostream& out); void Write(std::ostream &out);
}; };
template <typename TDerived> template <typename TDerived> struct lsOutMessage : lsBaseOutMessage {
struct lsOutMessage : lsBaseOutMessage {
// All derived types need to reflect on the |jsonrpc| member. // All derived types need to reflect on the |jsonrpc| member.
std::string jsonrpc = "2.0"; std::string jsonrpc = "2.0";
void ReflectWriter(Writer& writer) override { void ReflectWriter(Writer &writer) override {
Reflect(writer, static_cast<TDerived&>(*this)); Reflect(writer, static_cast<TDerived &>(*this));
} }
}; };
@ -75,7 +73,7 @@ struct lsResponseError {
// Short description. // Short description.
std::string message; std::string message;
void Write(Writer& visitor); void Write(Writer &visitor);
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -87,28 +85,28 @@ struct lsResponseError {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
struct lsDocumentUri { struct lsDocumentUri {
static lsDocumentUri FromPath(const std::string& path); static lsDocumentUri FromPath(const std::string &path);
bool operator==(const lsDocumentUri& other) const; bool operator==(const lsDocumentUri &other) const;
void SetPath(const std::string& path); void SetPath(const std::string &path);
std::string GetPath() const; std::string GetPath() const;
std::string raw_uri; std::string raw_uri;
}; };
template <typename TVisitor> template <typename TVisitor>
void Reflect(TVisitor& visitor, lsDocumentUri& value) { void Reflect(TVisitor &visitor, lsDocumentUri &value) {
Reflect(visitor, value.raw_uri); Reflect(visitor, value.raw_uri);
} }
struct lsPosition { struct lsPosition {
int line = 0; int line = 0;
int character = 0; int character = 0;
bool operator==(const lsPosition& o) const { bool operator==(const lsPosition &o) const {
return line == o.line && character == o.character; return line == o.line && character == o.character;
} }
bool operator<(const lsPosition& o) const { bool operator<(const lsPosition &o) const {
return line != o.line ? line < o.line : character < o.character; return line != o.line ? line < o.line : character < o.character;
} }
std::string ToString() const; std::string ToString() const;
@ -118,10 +116,10 @@ MAKE_REFLECT_STRUCT(lsPosition, line, character);
struct lsRange { struct lsRange {
lsPosition start; lsPosition start;
lsPosition end; lsPosition end;
bool operator==(const lsRange& o) const { bool operator==(const lsRange &o) const {
return start == o.start && end == o.end; return start == o.start && end == o.end;
} }
bool operator<(const lsRange& o) const { bool operator<(const lsRange &o) const {
return !(start == o.start) ? start < o.start : end < o.end; return !(start == o.start) ? start < o.start : end < o.end;
} }
}; };
@ -130,10 +128,10 @@ MAKE_REFLECT_STRUCT(lsRange, start, end);
struct lsLocation { struct lsLocation {
lsDocumentUri uri; lsDocumentUri uri;
lsRange range; lsRange range;
bool operator==(const lsLocation& o) const { bool operator==(const lsLocation &o) const {
return uri == o.uri && range == o.range; return uri == o.uri && range == o.range;
} }
bool operator<(const lsLocation& o) const { bool operator<(const lsLocation &o) const {
return !(uri.raw_uri == o.uri.raw_uri) ? uri.raw_uri < o.uri.raw_uri return !(uri.raw_uri == o.uri.raw_uri) ? uri.raw_uri < o.uri.raw_uri
: range < o.range; : range < o.range;
} }
@ -192,8 +190,7 @@ struct lsLocationEx : lsLocation {
}; };
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role); MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
template <typename T> template <typename T> struct lsCommand {
struct lsCommand {
// Title of the command (ie, 'save') // Title of the command (ie, 'save')
std::string title; std::string title;
// Actual command identifier. // Actual command identifier.
@ -204,7 +201,7 @@ struct lsCommand {
T arguments; T arguments;
}; };
template <typename TVisitor, typename T> template <typename TVisitor, typename T>
void Reflect(TVisitor& visitor, lsCommand<T>& value) { void Reflect(TVisitor &visitor, lsCommand<T> &value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(title); REFLECT_MEMBER(title);
REFLECT_MEMBER(command); REFLECT_MEMBER(command);
@ -212,8 +209,7 @@ void Reflect(TVisitor& visitor, lsCommand<T>& value) {
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
template <typename TData, typename TCommandArguments> template <typename TData, typename TCommandArguments> struct lsCodeLens {
struct lsCodeLens {
// The range in which this code lens is valid. Should only span a single line. // The range in which this code lens is valid. Should only span a single line.
lsRange range; lsRange range;
// The command this code lens represents. // The command this code lens represents.
@ -223,7 +219,7 @@ struct lsCodeLens {
TData data; TData data;
}; };
template <typename TVisitor, typename TData, typename TCommandArguments> template <typename TVisitor, typename TData, typename TCommandArguments>
void Reflect(TVisitor& visitor, lsCodeLens<TData, TCommandArguments>& value) { void Reflect(TVisitor &visitor, lsCodeLens<TData, TCommandArguments> &value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(range); REFLECT_MEMBER(range);
REFLECT_MEMBER(command); REFLECT_MEMBER(command);
@ -263,7 +259,7 @@ struct lsTextEdit {
// empty string. // empty string.
std::string newText; std::string newText;
bool operator==(const lsTextEdit& that); bool operator==(const lsTextEdit &that);
}; };
MAKE_REFLECT_STRUCT(lsTextEdit, range, newText); MAKE_REFLECT_STRUCT(lsTextEdit, range, newText);
@ -321,7 +317,7 @@ struct lsMarkedString {
std::optional<std::string> language; std::optional<std::string> language;
std::string value; std::string value;
}; };
void Reflect(Writer& visitor, lsMarkedString& value); void Reflect(Writer &visitor, lsMarkedString &value);
struct lsTextDocumentContentChangeEvent { struct lsTextDocumentContentChangeEvent {
// The range of the document that changed. // The range of the document that changed.
@ -337,8 +333,7 @@ struct lsTextDocumentDidChangeParams {
lsVersionedTextDocumentIdentifier textDocument; lsVersionedTextDocumentIdentifier textDocument;
std::vector<lsTextDocumentContentChangeEvent> contentChanges; std::vector<lsTextDocumentContentChangeEvent> contentChanges;
}; };
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams, MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams, textDocument,
textDocument,
contentChanges); contentChanges);
// Show a message to the user. // Show a message to the user.
@ -360,7 +355,7 @@ struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
}; };
template <typename TVisitor> template <typename TVisitor>
void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) { void Reflect(TVisitor &visitor, Out_ShowLogMessage &value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(jsonrpc); REFLECT_MEMBER(jsonrpc);
std::string method = value.method(); std::string method = value.method();

View File

@ -106,9 +106,9 @@ struct lsCompletionItem {
// nor with themselves. // nor with themselves.
// std::vector<TextEdit> additionalTextEdits; // std::vector<TextEdit> additionalTextEdits;
// An std::optional command that is executed *after* inserting this completion. // An std::optional command that is executed *after* inserting this
// *Note* that additional modifications to the current document should be // completion. *Note* that additional modifications to the current document
// described with the additionalTextEdits-property. Command command; // should be described with the additionalTextEdits-property. Command command;
// An data entry field that is preserved on a completion item between // An data entry field that is preserved on a completion item between
// a completion and a completion resolve request. // a completion and a completion resolve request.
@ -117,7 +117,7 @@ struct lsCompletionItem {
// Use this helper to figure out what content the completion item will insert // Use this helper to figure out what content the completion item will insert
// into the document, as it could live in either |textEdit|, |insertText|, or // into the document, as it could live in either |textEdit|, |insertText|, or
// |label|. // |label|.
const std::string& InsertedContent() const { const std::string &InsertedContent() const {
if (textEdit) if (textEdit)
return textEdit->newText; return textEdit->newText;
if (!insertText.empty()) if (!insertText.empty())
@ -125,13 +125,6 @@ struct lsCompletionItem {
return label; return label;
} }
}; };
MAKE_REFLECT_STRUCT(lsCompletionItem, MAKE_REFLECT_STRUCT(lsCompletionItem, label, kind, detail, documentation,
label, sortText, insertText, filterText, insertTextFormat,
kind,
detail,
documentation,
sortText,
insertText,
filterText,
insertTextFormat,
textEdit); textEdit);

View File

@ -88,7 +88,7 @@ struct Out_TextDocumentPublishDiagnostics
Params params; Params params;
}; };
template <typename TVisitor> template <typename TVisitor>
void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) { void Reflect(TVisitor &visitor, Out_TextDocumentPublishDiagnostics &value) {
std::string method = "textDocument/publishDiagnostics"; std::string method = "textDocument/publishDiagnostics";
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(jsonrpc); REFLECT_MEMBER(jsonrpc);
@ -96,6 +96,5 @@ void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
REFLECT_MEMBER(params); REFLECT_MEMBER(params);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, uri,
uri,
diagnostics); diagnostics);

View File

@ -28,21 +28,21 @@ std::string g_init_options;
namespace { namespace {
opt<bool> opt_help("h", desc("Alias for -help")); opt<bool> opt_help("h", desc("Alias for -help"));
opt<int> opt_verbose("v", desc("verbosity"), init(0)); opt<int> opt_verbose("v", desc("verbosity"), init(0));
opt<std::string> opt_test_index("test-index", ValueOptional, init("!"), desc("run index tests")); opt<std::string> opt_test_index("test-index", ValueOptional, init("!"),
desc("run index tests"));
opt<std::string> opt_init("init", desc("extra initialization options")); opt<std::string> opt_init("init", desc("extra initialization options"));
opt<std::string> opt_log_file("log-file", desc("log"), value_desc("filename")); opt<std::string> opt_log_file("log-file", desc("log"), value_desc("filename"));
opt<std::string> opt_log_file_append("log-file-append", desc("log"), value_desc("filename")); opt<std::string> opt_log_file_append("log-file-append", desc("log"),
value_desc("filename"));
list<std::string> opt_extra(Positional, ZeroOrMore, desc("extra")); list<std::string> opt_extra(Positional, ZeroOrMore, desc("extra"));
void CloseLog() { void CloseLog() { fclose(ccls::log::file); }
fclose(ccls::log::file);
}
} // namespace } // namespace
int main(int argc, char** argv) { int main(int argc, char **argv) {
TraceMe(); TraceMe();
sys::PrintStackTraceOnErrorSignal(argv[0]); sys::PrintStackTraceOnErrorSignal(argv[0]);
@ -98,9 +98,9 @@ int main(int argc, char** argv) {
try { try {
Config config; Config config;
Reflect(json_reader, config); Reflect(json_reader, config);
} catch (std::invalid_argument& e) { } catch (std::invalid_argument &e) {
fprintf(stderr, "Failed to parse --init %s, expected %s\n", fprintf(stderr, "Failed to parse --init %s, expected %s\n",
static_cast<JsonReader&>(json_reader).GetPath().c_str(), static_cast<JsonReader &>(json_reader).GetPath().c_str(),
e.what()); e.what());
return 1; return 1;
} }
@ -108,11 +108,13 @@ int main(int argc, char** argv) {
sys::ChangeStdinToBinary(); sys::ChangeStdinToBinary();
sys::ChangeStdoutToBinary(); sys::ChangeStdoutToBinary();
// The thread that reads from stdin and dispatchs commands to the main thread. // The thread that reads from stdin and dispatchs commands to the main
// thread.
pipeline::LaunchStdin(); pipeline::LaunchStdin();
// The thread that writes responses from the main thread to stdout. // The thread that writes responses from the main thread to stdout.
pipeline::LaunchStdout(); pipeline::LaunchStdout();
// Main thread which also spawns indexer threads upon the "initialize" request. // Main thread which also spawns indexer threads upon the "initialize"
// request.
pipeline::MainLoop(); pipeline::MainLoop();
} }

View File

@ -5,7 +5,7 @@
using namespace ccls; using namespace ccls;
// static // static
std::optional<Matcher> Matcher::Create(const std::string& search) { std::optional<Matcher> Matcher::Create(const std::string &search) {
/* /*
std::string real_search; std::string real_search;
real_search.reserve(search.size() * 3 + 2); real_search.reserve(search.size() * 3 + 2);
@ -19,51 +19,51 @@ std::optional<Matcher> Matcher::Create(const std::string& search) {
try { try {
Matcher m; Matcher m;
m.regex_string = search; m.regex_string = search;
m.regex = std::regex( m.regex = std::regex(search, std::regex_constants::ECMAScript |
search, std::regex_constants::ECMAScript | std::regex_constants::icase | std::regex_constants::icase |
std::regex_constants::optimize std::regex_constants::optimize
// std::regex_constants::nosubs // std::regex_constants::nosubs
); );
return m; return m;
} catch (const std::exception& e) { } catch (const std::exception &e) {
Out_ShowLogMessage out; Out_ShowLogMessage out;
out.display_type = Out_ShowLogMessage::DisplayType::Show; out.display_type = Out_ShowLogMessage::DisplayType::Show;
out.params.type = lsMessageType::Error; out.params.type = lsMessageType::Error;
out.params.message = "ccls: Parsing EMCAScript regex \"" + search + out.params.message =
"\" failed; " + e.what(); "ccls: Parsing EMCAScript regex \"" + search + "\" failed; " + e.what();
pipeline::WriteStdout(kMethodType_Unknown, out); pipeline::WriteStdout(kMethodType_Unknown, out);
return std::nullopt; return std::nullopt;
} }
} }
bool Matcher::IsMatch(const std::string& value) const { bool Matcher::IsMatch(const std::string &value) const {
// std::smatch match; // std::smatch match;
// return std::regex_match(value, match, regex); // return std::regex_match(value, match, regex);
return std::regex_search(value, regex, std::regex_constants::match_any); return std::regex_search(value, regex, std::regex_constants::match_any);
} }
GroupMatch::GroupMatch(const std::vector<std::string>& whitelist, GroupMatch::GroupMatch(const std::vector<std::string> &whitelist,
const std::vector<std::string>& blacklist) { const std::vector<std::string> &blacklist) {
for (const std::string& entry : whitelist) { for (const std::string &entry : whitelist) {
std::optional<Matcher> m = Matcher::Create(entry); std::optional<Matcher> m = Matcher::Create(entry);
if (m) if (m)
this->whitelist.push_back(*m); this->whitelist.push_back(*m);
} }
for (const std::string& entry : blacklist) { for (const std::string &entry : blacklist) {
std::optional<Matcher> m = Matcher::Create(entry); std::optional<Matcher> m = Matcher::Create(entry);
if (m) if (m)
this->blacklist.push_back(*m); this->blacklist.push_back(*m);
} }
} }
bool GroupMatch::IsMatch(const std::string& value, bool GroupMatch::IsMatch(const std::string &value,
std::string* match_failure_reason) const { std::string *match_failure_reason) const {
for (const Matcher& m : whitelist) { for (const Matcher &m : whitelist) {
if (m.IsMatch(value)) if (m.IsMatch(value))
return true; return true;
} }
for (const Matcher& m : blacklist) { for (const Matcher &m : blacklist) {
if (m.IsMatch(value)) { if (m.IsMatch(value)) {
if (match_failure_reason) if (match_failure_reason)
*match_failure_reason = "blacklist \"" + m.regex_string + "\""; *match_failure_reason = "blacklist \"" + m.regex_string + "\"";

View File

@ -7,9 +7,9 @@
#include <vector> #include <vector>
struct Matcher { struct Matcher {
static std::optional<Matcher> Create(const std::string& search); static std::optional<Matcher> Create(const std::string &search);
bool IsMatch(const std::string& value) const; bool IsMatch(const std::string &value) const;
std::string regex_string; std::string regex_string;
std::regex regex; std::regex regex;
@ -17,11 +17,11 @@ struct Matcher {
// Check multiple |Matcher| instances at the same time. // Check multiple |Matcher| instances at the same time.
struct GroupMatch { struct GroupMatch {
GroupMatch(const std::vector<std::string>& whitelist, GroupMatch(const std::vector<std::string> &whitelist,
const std::vector<std::string>& blacklist); const std::vector<std::string> &blacklist);
bool IsMatch(const std::string& value, bool IsMatch(const std::string &value,
std::string* match_failure_reason = nullptr) const; std::string *match_failure_reason = nullptr) const;
std::vector<Matcher> whitelist; std::vector<Matcher> whitelist;
std::vector<Matcher> blacklist; std::vector<Matcher> blacklist;

View File

@ -4,29 +4,28 @@
#include <utility> #include <utility>
// Like std::optional, but the stored data is responsible for containing the empty // Like std::optional, but the stored data is responsible for containing the
// state. T should define a function `bool T::Valid()`. // empty state. T should define a function `bool T::Valid()`.
template <typename T> template <typename T> class Maybe {
class Maybe {
T storage; T storage;
public: public:
constexpr Maybe() = default; constexpr Maybe() = default;
Maybe(const Maybe&) = default; Maybe(const Maybe &) = default;
Maybe(std::nullopt_t) {} Maybe(std::nullopt_t) {}
Maybe(const T& x) : storage(x) {} Maybe(const T &x) : storage(x) {}
Maybe(T&& x) : storage(std::forward<T>(x)) {} Maybe(T &&x) : storage(std::forward<T>(x)) {}
Maybe& operator=(const Maybe&) = default; Maybe &operator=(const Maybe &) = default;
Maybe& operator=(const T& x) { Maybe &operator=(const T &x) {
storage = x; storage = x;
return *this; return *this;
} }
const T* operator->() const { return &storage; } const T *operator->() const { return &storage; }
T* operator->() { return &storage; } T *operator->() { return &storage; }
const T& operator*() const { return storage; } const T &operator*() const { return storage; }
T& operator*() { return storage; } T &operator*() { return storage; }
bool Valid() const { return storage.Valid(); } bool Valid() const { return storage.Valid(); }
explicit operator bool() const { return Valid(); } explicit operator bool() const { return Valid(); }
@ -36,9 +35,9 @@ class Maybe {
return std::nullopt; return std::nullopt;
} }
void operator=(std::optional<T>&& o) { storage = o ? *o : T(); } void operator=(std::optional<T> &&o) { storage = o ? *o : T(); }
// Does not test if has_value() // Does not test if has_value()
bool operator==(const Maybe& o) const { return storage == o.storage; } bool operator==(const Maybe &o) const { return storage == o.storage; }
bool operator!=(const Maybe& o) const { return !(*this == o); } bool operator!=(const Maybe &o) const { return !(*this == o); }
}; };

View File

@ -337,15 +337,16 @@ void EmitSemanticHighlighting(DB *db,
out.params.uri = lsDocumentUri::FromPath(wfile->filename); out.params.uri = lsDocumentUri::FromPath(wfile->filename);
// Transform lsRange into pair<int, int> (offset pairs) // Transform lsRange into pair<int, int> (offset pairs)
if (!g_config->highlight.lsRanges) { if (!g_config->highlight.lsRanges) {
std::vector<std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>> std::vector<
scratch; std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>>
scratch;
for (auto &entry : grouped_symbols) { for (auto &entry : grouped_symbols) {
for (auto &range : entry.second.lsRanges) for (auto &range : entry.second.lsRanges)
scratch.emplace_back(range, &entry.second); scratch.emplace_back(range, &entry.second);
entry.second.lsRanges.clear(); entry.second.lsRanges.clear();
} }
std::sort(scratch.begin(), scratch.end(), std::sort(scratch.begin(), scratch.end(),
[](auto &l, auto &r) { return l.first.start < r.first.start; }); [](auto &l, auto &r) { return l.first.start < r.first.start; });
const auto &buf = wfile->buffer_content; const auto &buf = wfile->buffer_content;
int l = 0, c = 0, i = 0, p = 0; int l = 0, c = 0, i = 0, p = 0;
auto mov = [&](int line, int col) { auto mov = [&](int line, int col) {
@ -357,11 +358,13 @@ void EmitSemanticHighlighting(DB *db,
if (uint8_t(buf[i]) < 128 || 192 <= uint8_t(buf[i])) if (uint8_t(buf[i]) < 128 || 192 <= uint8_t(buf[i]))
p++; p++;
} }
if (l < line) return true; if (l < line)
return true;
for (; c < col && i < buf.size() && buf[i] != '\n'; c++) for (; c < col && i < buf.size() && buf[i] != '\n'; c++)
if (p++, uint8_t(buf[i++]) >= 128) if (p++, uint8_t(buf[i++]) >= 128)
// Skip 0b10xxxxxx // Skip 0b10xxxxxx
while (i < buf.size() && uint8_t(buf[i]) >= 128 && uint8_t(buf[i]) < 192) while (i < buf.size() && uint8_t(buf[i]) >= 128 &&
uint8_t(buf[i]) < 192)
i++; i++;
return c < col; return c < col;
}; };

View File

@ -6,8 +6,8 @@
#include "method.h" #include "method.h"
#include "query.h" #include "query.h"
#include <optional>
#include <memory> #include <memory>
#include <optional>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -28,7 +28,7 @@ struct WorkingFiles;
// relatively stable ids. Only supports xxx files at a time. // relatively stable ids. Only supports xxx files at a time.
struct SemanticHighlightSymbolCache { struct SemanticHighlightSymbolCache {
struct Entry { struct Entry {
SemanticHighlightSymbolCache* all_caches_ = nullptr; SemanticHighlightSymbolCache *all_caches_ = nullptr;
// The path this cache belongs to. // The path this cache belongs to.
std::string path; std::string path;
@ -38,13 +38,13 @@ struct SemanticHighlightSymbolCache {
TNameToId detailed_func_name_to_stable_id; TNameToId detailed_func_name_to_stable_id;
TNameToId detailed_var_name_to_stable_id; TNameToId detailed_var_name_to_stable_id;
Entry(SemanticHighlightSymbolCache* all_caches, const std::string& path); Entry(SemanticHighlightSymbolCache *all_caches, const std::string &path);
std::optional<int> TryGetStableId(SymbolKind kind, std::optional<int> TryGetStableId(SymbolKind kind,
const std::string& detailed_name); const std::string &detailed_name);
int GetStableId(SymbolKind kind, const std::string& detailed_name); int GetStableId(SymbolKind kind, const std::string &detailed_name);
TNameToId* GetMapForSymbol_(SymbolKind kind); TNameToId *GetMapForSymbol_(SymbolKind kind);
}; };
constexpr static int kCacheSize = 10; constexpr static int kCacheSize = 10;
@ -54,7 +54,7 @@ struct SemanticHighlightSymbolCache {
SemanticHighlightSymbolCache(); SemanticHighlightSymbolCache();
void Init(); void Init();
std::shared_ptr<Entry> GetCacheForFile(const std::string& path); std::shared_ptr<Entry> GetCacheForFile(const std::string &path);
}; };
struct Out_CclsPublishSemanticHighlighting struct Out_CclsPublishSemanticHighlighting
@ -79,9 +79,7 @@ struct Out_CclsPublishSemanticHighlighting
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Symbol, stableId, MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Symbol, stableId,
parentKind, kind, storage, ranges, lsRanges); parentKind, kind, storage, ranges, lsRanges);
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Params, uri, symbols); MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Params, uri, symbols);
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, jsonrpc, method,
jsonrpc,
method,
params); params);
// Usage: // Usage:
@ -94,54 +92,49 @@ MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting,
// Then there will be a global FooHandler instance in // Then there will be a global FooHandler instance in
// |MessageHandler::message_handlers|. // |MessageHandler::message_handlers|.
#define REGISTER_MESSAGE_HANDLER(type) \ #define REGISTER_MESSAGE_HANDLER(type) \
static type type##message_handler_instance_; static type type##message_handler_instance_;
struct MessageHandler { struct MessageHandler {
DB* db = nullptr; DB *db = nullptr;
MultiQueueWaiter* waiter = nullptr; MultiQueueWaiter *waiter = nullptr;
Project* project = nullptr; Project *project = nullptr;
DiagnosticsPublisher* diag_pub = nullptr; DiagnosticsPublisher *diag_pub = nullptr;
VFS* vfs = nullptr; VFS *vfs = nullptr;
ImportManager* import_manager = nullptr; ImportManager *import_manager = nullptr;
SemanticHighlightSymbolCache* semantic_cache = nullptr; SemanticHighlightSymbolCache *semantic_cache = nullptr;
WorkingFiles* working_files = nullptr; WorkingFiles *working_files = nullptr;
ClangCompleteManager* clang_complete = nullptr; ClangCompleteManager *clang_complete = nullptr;
IncludeComplete* include_complete = nullptr; IncludeComplete *include_complete = nullptr;
CodeCompleteCache* global_code_complete_cache = nullptr; CodeCompleteCache *global_code_complete_cache = nullptr;
CodeCompleteCache* non_global_code_complete_cache = nullptr; CodeCompleteCache *non_global_code_complete_cache = nullptr;
CodeCompleteCache* signature_cache = nullptr; CodeCompleteCache *signature_cache = nullptr;
virtual MethodType GetMethodType() const = 0; virtual MethodType GetMethodType() const = 0;
virtual void Run(std::unique_ptr<InMessage> message) = 0; virtual void Run(std::unique_ptr<InMessage> message) = 0;
static std::vector<MessageHandler*>* message_handlers; static std::vector<MessageHandler *> *message_handlers;
protected: protected:
MessageHandler(); MessageHandler();
}; };
template <typename TMessage> template <typename TMessage> struct BaseMessageHandler : MessageHandler {
struct BaseMessageHandler : MessageHandler { virtual void Run(TMessage *message) = 0;
virtual void Run(TMessage* message) = 0;
// MessageHandler: // MessageHandler:
void Run(std::unique_ptr<InMessage> message) override { void Run(std::unique_ptr<InMessage> message) override {
Run(static_cast<TMessage*>(message.get())); Run(static_cast<TMessage *>(message.get()));
} }
}; };
bool FindFileOrFail(DB* db, bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
Project* project, const std::string &absolute_path,
std::optional<lsRequestId> id, QueryFile **out_query_file, int *out_file_id = nullptr);
const std::string& absolute_path,
QueryFile** out_query_file,
int* out_file_id = nullptr);
void EmitSkippedRanges(WorkingFile *working_file, void EmitSkippedRanges(WorkingFile *working_file,
const std::vector<Range> &skipped_ranges); const std::vector<Range> &skipped_ranges);
void EmitSemanticHighlighting(DB* db, void EmitSemanticHighlighting(DB *db,
SemanticHighlightSymbolCache* semantic_cache, SemanticHighlightSymbolCache *semantic_cache,
WorkingFile* working_file, WorkingFile *working_file, QueryFile *file);
QueryFile* file);

View File

@ -18,14 +18,14 @@ REGISTER_IN_MESSAGE(In_CclsBase);
struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> { struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsBase* request) override { void Run(In_CclsBase *request) override {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file)) { request->params.textDocument.uri.GetPath(), &file)) {
return; return;
} }
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_LocationList out; Out_LocationList out;
@ -33,12 +33,12 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
if (sym.kind == SymbolKind::Type) { if (sym.kind == SymbolKind::Type) {
if (const auto* def = db->GetType(sym).AnyDef()) if (const auto *def = db->GetType(sym).AnyDef())
out.result = GetLsLocationExs(db, working_files, out.result = GetLsLocationExs(db, working_files,
GetTypeDeclarations(db, def->bases)); GetTypeDeclarations(db, def->bases));
break; break;
} else if (sym.kind == SymbolKind::Func) { } else if (sym.kind == SymbolKind::Func) {
if (const auto* def = db->GetFunc(sym).AnyDef()) if (const auto *def = db->GetFunc(sym).AnyDef())
out.result = GetLsLocationExs(db, working_files, out.result = GetLsLocationExs(db, working_files,
GetFuncDeclarations(db, def->bases)); GetFuncDeclarations(db, def->bases));
break; break;
@ -48,4 +48,4 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsBase); REGISTER_MESSAGE_HANDLER(Handler_CclsBase);
} // namespace } // namespace

View File

@ -44,16 +44,9 @@ struct In_CclsCallHierarchy : public RequestInMessage {
int levels = 1; int levels = 1;
}; };
Params params; Params params;
}; };
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy::Params, MAKE_REFLECT_STRUCT(In_CclsCallHierarchy::Params, textDocument, position, id,
textDocument, callee, callType, qualified, levels);
position,
id,
callee,
callType,
qualified,
levels);
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy, id, params); MAKE_REFLECT_STRUCT(In_CclsCallHierarchy, id, params);
REGISTER_IN_MESSAGE(In_CclsCallHierarchy); REGISTER_IN_MESSAGE(In_CclsCallHierarchy);
@ -72,26 +65,15 @@ struct Out_CclsCallHierarchy : public lsOutMessage<Out_CclsCallHierarchy> {
lsRequestId id; lsRequestId id;
std::optional<Entry> result; std::optional<Entry> result;
}; };
MAKE_REFLECT_STRUCT(Out_CclsCallHierarchy::Entry, MAKE_REFLECT_STRUCT(Out_CclsCallHierarchy::Entry, id, name, location, callType,
id, numChildren, children);
name, MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCallHierarchy, jsonrpc, id,
location,
callType,
numChildren,
children);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCallHierarchy,
jsonrpc,
id,
result); result);
bool Expand(MessageHandler* m, bool Expand(MessageHandler *m, Out_CclsCallHierarchy::Entry *entry, bool callee,
Out_CclsCallHierarchy::Entry* entry, CallType call_type, bool qualified, int levels) {
bool callee, const QueryFunc &func = m->db->Func(entry->usr);
CallType call_type, const QueryFunc::Def *def = func.AnyDef();
bool qualified,
int levels) {
const QueryFunc& func = m->db->Func(entry->usr);
const QueryFunc::Def* def = func.AnyDef();
entry->numChildren = 0; entry->numChildren = 0;
if (!def) if (!def)
return false; return false;
@ -108,13 +90,12 @@ bool Expand(MessageHandler* m,
entry->children.push_back(std::move(entry1)); entry->children.push_back(std::move(entry1));
} }
}; };
auto handle_uses = [&](const QueryFunc& func, CallType call_type) { auto handle_uses = [&](const QueryFunc &func, CallType call_type) {
if (callee) { if (callee) {
if (const auto* def = func.AnyDef()) if (const auto *def = func.AnyDef())
for (SymbolRef ref : def->callees) for (SymbolRef ref : def->callees)
if (ref.kind == SymbolKind::Func) if (ref.kind == SymbolKind::Func)
handle(Use{{ref.range, ref.usr, ref.kind, ref.role}, handle(Use{{ref.range, ref.usr, ref.kind, ref.role}, def->file_id},
def->file_id},
call_type); call_type);
} else { } else {
for (Use use : func.uses) for (Use use : func.uses)
@ -125,7 +106,7 @@ bool Expand(MessageHandler* m,
std::unordered_set<Usr> seen; std::unordered_set<Usr> seen;
seen.insert(func.usr); seen.insert(func.usr);
std::vector<const QueryFunc*> stack; std::vector<const QueryFunc *> stack;
entry->name = def->Name(qualified); entry->name = def->Name(qualified);
handle_uses(func, CallType::Direct); handle_uses(func, CallType::Direct);
@ -133,10 +114,10 @@ bool Expand(MessageHandler* m,
if (call_type & CallType::Base) { if (call_type & CallType::Base) {
stack.push_back(&func); stack.push_back(&func);
while (stack.size()) { while (stack.size()) {
const QueryFunc& func1 = *stack.back(); const QueryFunc &func1 = *stack.back();
stack.pop_back(); stack.pop_back();
if (auto* def1 = func1.AnyDef()) { if (auto *def1 = func1.AnyDef()) {
EachDefinedFunc(m->db, def1->bases, [&](QueryFunc& func2) { EachDefinedFunc(m->db, def1->bases, [&](QueryFunc &func2) {
if (!seen.count(func2.usr)) { if (!seen.count(func2.usr)) {
seen.insert(func2.usr); seen.insert(func2.usr);
stack.push_back(&func2); stack.push_back(&func2);
@ -151,9 +132,9 @@ bool Expand(MessageHandler* m,
if (call_type & CallType::Derived) { if (call_type & CallType::Derived) {
stack.push_back(&func); stack.push_back(&func);
while (stack.size()) { while (stack.size()) {
const QueryFunc& func1 = *stack.back(); const QueryFunc &func1 = *stack.back();
stack.pop_back(); stack.pop_back();
EachDefinedFunc(m->db, func1.derived, [&](QueryFunc& func2) { EachDefinedFunc(m->db, func1.derived, [&](QueryFunc &func2) {
if (!seen.count(func2.usr)) { if (!seen.count(func2.usr)) {
seen.insert(func2.usr); seen.insert(func2.usr);
stack.push_back(&func2); stack.push_back(&func2);
@ -165,16 +146,13 @@ bool Expand(MessageHandler* m,
return true; return true;
} }
struct Handler_CclsCallHierarchy struct Handler_CclsCallHierarchy : BaseMessageHandler<In_CclsCallHierarchy> {
: BaseMessageHandler<In_CclsCallHierarchy> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
std::optional<Out_CclsCallHierarchy::Entry> BuildInitial(Usr root_usr, std::optional<Out_CclsCallHierarchy::Entry>
bool callee, BuildInitial(Usr root_usr, bool callee, CallType call_type, bool qualified,
CallType call_type, int levels) {
bool qualified, const auto *def = db->Func(root_usr).AnyDef();
int levels) {
const auto* def = db->Func(root_usr).AnyDef();
if (!def) if (!def)
return {}; return {};
@ -191,8 +169,8 @@ struct Handler_CclsCallHierarchy
return entry; return entry;
} }
void Run(In_CclsCallHierarchy* request) override { void Run(In_CclsCallHierarchy *request) override {
auto& params = request->params; auto &params = request->params;
Out_CclsCallHierarchy out; Out_CclsCallHierarchy out;
out.id = request->id; out.id = request->id;
@ -211,11 +189,11 @@ struct Handler_CclsCallHierarchy
params.levels); params.levels);
out.result = std::move(entry); out.result = std::move(entry);
} else { } else {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, params.position)) { FindSymbolsAtLocation(working_file, file, params.position)) {
@ -232,4 +210,4 @@ struct Handler_CclsCallHierarchy
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy); REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy);
} // namespace } // namespace

View File

@ -15,14 +15,14 @@ REGISTER_IN_MESSAGE(In_CclsCallers);
struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> { struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsCallers* request) override { void Run(In_CclsCallers *request) override {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file)) { request->params.textDocument.uri.GetPath(), &file)) {
return; return;
} }
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_LocationList out; Out_LocationList out;
@ -30,7 +30,7 @@ struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
if (sym.kind == SymbolKind::Func) { if (sym.kind == SymbolKind::Func) {
QueryFunc& func = db->GetFunc(sym); QueryFunc &func = db->GetFunc(sym);
std::vector<Use> uses = func.uses; std::vector<Use> uses = func.uses;
for (Use func_ref : GetUsesForAllBases(db, func)) for (Use func_ref : GetUsesForAllBases(db, func))
uses.push_back(func_ref); uses.push_back(func_ref);
@ -44,4 +44,4 @@ struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsCallers); REGISTER_MESSAGE_HANDLER(Handler_CclsCallers);
} // namespace } // namespace

View File

@ -3,14 +3,8 @@
#include "query_utils.h" #include "query_utils.h"
using namespace ccls; using namespace ccls;
MAKE_REFLECT_STRUCT(QueryFile::Def, MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, outline, all_symbols,
path, skipped_ranges, dependencies);
args,
language,
outline,
all_symbols,
skipped_ranges,
dependencies);
namespace { namespace {
MethodType kMethodType = "$ccls/fileInfo"; MethodType kMethodType = "$ccls/fileInfo";
@ -35,8 +29,8 @@ MAKE_REFLECT_STRUCT(Out_CclsFileInfo, jsonrpc, id, result);
struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> { struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsFileInfo* request) override { void Run(In_CclsFileInfo *request) override {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file)) { request->params.textDocument.uri.GetPath(), &file)) {
return; return;
@ -54,4 +48,4 @@ struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo); REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo);
} // namespace } // namespace

View File

@ -1,8 +1,8 @@
#include "match.h" #include "match.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "pipeline.hh"
#include "working_files.h" #include "working_files.h"
using namespace ccls; using namespace ccls;
@ -21,38 +21,36 @@ struct In_CclsFreshenIndex : public NotificationInMessage {
}; };
Params params; Params params;
}; };
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex::Params, MAKE_REFLECT_STRUCT(In_CclsFreshenIndex::Params, dependencies, whitelist,
dependencies,
whitelist,
blacklist); blacklist);
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex, params); MAKE_REFLECT_STRUCT(In_CclsFreshenIndex, params);
REGISTER_IN_MESSAGE(In_CclsFreshenIndex); REGISTER_IN_MESSAGE(In_CclsFreshenIndex);
struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> { struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsFreshenIndex* request) override { void Run(In_CclsFreshenIndex *request) override {
GroupMatch matcher(request->params.whitelist, request->params.blacklist); GroupMatch matcher(request->params.whitelist, request->params.blacklist);
std::queue<const QueryFile*> q; std::queue<const QueryFile *> q;
// |need_index| stores every filename ever enqueued. // |need_index| stores every filename ever enqueued.
std::unordered_set<std::string> need_index; std::unordered_set<std::string> need_index;
// Reverse dependency graph. // Reverse dependency graph.
std::unordered_map<std::string, std::vector<std::string>> graph; std::unordered_map<std::string, std::vector<std::string>> graph;
// filename -> QueryFile mapping for files haven't enqueued. // filename -> QueryFile mapping for files haven't enqueued.
std::unordered_map<std::string, const QueryFile*> path_to_file; std::unordered_map<std::string, const QueryFile *> path_to_file;
for (const auto& file : db->files) for (const auto &file : db->files)
if (file.def) { if (file.def) {
if (matcher.IsMatch(file.def->path)) if (matcher.IsMatch(file.def->path))
q.push(&file); q.push(&file);
else else
path_to_file[file.def->path] = &file; path_to_file[file.def->path] = &file;
for (const std::string& dependency : file.def->dependencies) for (const std::string &dependency : file.def->dependencies)
graph[dependency].push_back(file.def->path); graph[dependency].push_back(file.def->path);
} }
while (!q.empty()) { while (!q.empty()) {
const QueryFile* file = q.front(); const QueryFile *file = q.front();
q.pop(); q.pop();
need_index.insert(file->def->path); need_index.insert(file->def->path);
@ -61,13 +59,13 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
continue; continue;
{ {
std::lock_guard<std::mutex> lock(vfs->mutex); std::lock_guard<std::mutex> lock(vfs->mutex);
VFS::State& st = vfs->state[file->def->path]; VFS::State &st = vfs->state[file->def->path];
if (st.timestamp < write_time) if (st.timestamp < write_time)
st.stage = 0; st.stage = 0;
} }
if (request->params.dependencies) if (request->params.dependencies)
for (const std::string& path : graph[file->def->path]) { for (const std::string &path : graph[file->def->path]) {
auto it = path_to_file.find(path); auto it = path_to_file.find(path);
if (it != path_to_file.end()) { if (it != path_to_file.end()) {
q.push(it->second); q.push(it->second);
@ -81,4 +79,4 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex); REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex);
} // namespace } // namespace

View File

@ -51,32 +51,18 @@ struct Out_CclsInheritanceHierarchy
lsRequestId id; lsRequestId id;
std::optional<Entry> result; std::optional<Entry> result;
}; };
MAKE_REFLECT_STRUCT(Out_CclsInheritanceHierarchy::Entry, MAKE_REFLECT_STRUCT(Out_CclsInheritanceHierarchy::Entry, id, kind, name,
id, location, numChildren, children);
kind, MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritanceHierarchy, jsonrpc,
name, id, result);
location,
numChildren,
children);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritanceHierarchy,
jsonrpc,
id,
result);
bool Expand(MessageHandler* m, bool Expand(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
Out_CclsInheritanceHierarchy::Entry* entry, bool derived, bool qualified, int levels);
bool derived,
bool qualified,
int levels);
template <typename Q> template <typename Q>
bool ExpandHelper(MessageHandler* m, bool ExpandHelper(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
Out_CclsInheritanceHierarchy::Entry* entry, bool derived, bool qualified, int levels, Q &entity) {
bool derived, const auto *def = entity.AnyDef();
bool qualified,
int levels,
Q& entity) {
const auto* def = entity.AnyDef();
if (def) { if (def) {
entry->name = def->Name(qualified); entry->name = def->Name(qualified);
if (def->spell) { if (def->spell) {
@ -122,11 +108,8 @@ bool ExpandHelper(MessageHandler* m,
return true; return true;
} }
bool Expand(MessageHandler* m, bool Expand(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
Out_CclsInheritanceHierarchy::Entry* entry, bool derived, bool qualified, int levels) {
bool derived,
bool qualified,
int levels) {
if (entry->kind == SymbolKind::Func) if (entry->kind == SymbolKind::Func)
return ExpandHelper(m, entry, derived, qualified, levels, return ExpandHelper(m, entry, derived, qualified, levels,
m->db->Func(entry->usr)); m->db->Func(entry->usr));
@ -149,8 +132,8 @@ struct Handler_CclsInheritanceHierarchy
return entry; return entry;
} }
void Run(In_CclsInheritanceHierarchy* request) override { void Run(In_CclsInheritanceHierarchy *request) override {
auto& params = request->params; auto &params = request->params;
Out_CclsInheritanceHierarchy out; Out_CclsInheritanceHierarchy out;
out.id = request->id; out.id = request->id;
@ -169,12 +152,11 @@ struct Handler_CclsInheritanceHierarchy
Expand(this, &entry, params.derived, params.qualified, params.levels)) Expand(this, &entry, params.derived, params.qualified, params.levels))
out.result = std::move(entry); out.result = std::move(entry);
} else { } else {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile* wfile = WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
working_files->GetFileByFilename(file->def->path);
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position))
if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) { if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
@ -208,4 +190,4 @@ struct Handler_CclsInheritanceHierarchy
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy); REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy);
} // namespace } // namespace

View File

@ -30,17 +30,12 @@ struct In_CclsMemberHierarchy : public RequestInMessage {
Params params; Params params;
}; };
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy::Params, MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy::Params, textDocument, position, id,
textDocument, qualified, levels);
position,
id,
qualified,
levels);
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy, id, params); MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy, id, params);
REGISTER_IN_MESSAGE(In_CclsMemberHierarchy); REGISTER_IN_MESSAGE(In_CclsMemberHierarchy);
struct Out_CclsMemberHierarchy struct Out_CclsMemberHierarchy : public lsOutMessage<Out_CclsMemberHierarchy> {
: public lsOutMessage<Out_CclsMemberHierarchy> {
struct Entry { struct Entry {
Usr usr; Usr usr;
std::string id; std::string id;
@ -56,31 +51,18 @@ struct Out_CclsMemberHierarchy
lsRequestId id; lsRequestId id;
std::optional<Entry> result; std::optional<Entry> result;
}; };
MAKE_REFLECT_STRUCT(Out_CclsMemberHierarchy::Entry, MAKE_REFLECT_STRUCT(Out_CclsMemberHierarchy::Entry, id, name, fieldName,
id, location, numChildren, children);
name, MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMemberHierarchy, jsonrpc, id,
fieldName,
location,
numChildren,
children);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMemberHierarchy,
jsonrpc,
id,
result); result);
bool Expand(MessageHandler* m, bool Expand(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
Out_CclsMemberHierarchy::Entry* entry, bool qualified, int levels);
bool qualified,
int levels);
// Add a field to |entry| which is a Func/Type. // Add a field to |entry| which is a Func/Type.
void DoField(MessageHandler* m, void DoField(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
Out_CclsMemberHierarchy::Entry* entry, const QueryVar &var, int64_t offset, bool qualified, int levels) {
const QueryVar& var, const QueryVar::Def *def1 = var.AnyDef();
int64_t offset,
bool qualified,
int levels) {
const QueryVar::Def* def1 = var.AnyDef();
if (!def1) if (!def1)
return; return;
Out_CclsMemberHierarchy::Entry entry1; Out_CclsMemberHierarchy::Entry entry1;
@ -120,37 +102,35 @@ void DoField(MessageHandler* m,
} }
// Expand a type node by adding members recursively to it. // Expand a type node by adding members recursively to it.
bool Expand(MessageHandler* m, bool Expand(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
Out_CclsMemberHierarchy::Entry* entry, bool qualified, int levels) {
bool qualified,
int levels) {
if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) { if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
entry->name = ClangBuiltinTypeName(int(entry->usr)); entry->name = ClangBuiltinTypeName(int(entry->usr));
return true; return true;
} }
const QueryType& type = m->db->Type(entry->usr); const QueryType &type = m->db->Type(entry->usr);
const QueryType::Def* def = type.AnyDef(); const QueryType::Def *def = type.AnyDef();
// builtin types have no declaration and empty |qualified|. // builtin types have no declaration and empty |qualified|.
if (!def) if (!def)
return false; return false;
entry->name = def->Name(qualified); entry->name = def->Name(qualified);
std::unordered_set<Usr> seen; std::unordered_set<Usr> seen;
if (levels > 0) { if (levels > 0) {
std::vector<const QueryType*> stack; std::vector<const QueryType *> stack;
seen.insert(type.usr); seen.insert(type.usr);
stack.push_back(&type); stack.push_back(&type);
while (stack.size()) { while (stack.size()) {
const auto* def = stack.back()->AnyDef(); const auto *def = stack.back()->AnyDef();
stack.pop_back(); stack.pop_back();
if (def) { if (def) {
EachDefinedType(m->db, def->bases, [&](QueryType& type1) { EachDefinedType(m->db, def->bases, [&](QueryType &type1) {
if (!seen.count(type1.usr)) { if (!seen.count(type1.usr)) {
seen.insert(type1.usr); seen.insert(type1.usr);
stack.push_back(&type1); stack.push_back(&type1);
} }
}); });
if (def->alias_of) { if (def->alias_of) {
const QueryType::Def* def1 = m->db->Type(def->alias_of).AnyDef(); const QueryType::Def *def1 = m->db->Type(def->alias_of).AnyDef();
Out_CclsMemberHierarchy::Entry entry1; Out_CclsMemberHierarchy::Entry entry1;
entry1.id = std::to_string(def->alias_of); entry1.id = std::to_string(def->alias_of);
entry1.usr = def->alias_of; entry1.usr = def->alias_of;
@ -176,7 +156,7 @@ bool Expand(MessageHandler* m,
} }
} else { } else {
for (auto it : def->vars) { for (auto it : def->vars) {
QueryVar& var = m->db->Var(it.first); QueryVar &var = m->db->Var(it.first);
if (!var.def.empty()) if (!var.def.empty())
DoField(m, entry, var, it.second, qualified, levels - 1); DoField(m, entry, var, it.second, qualified, levels - 1);
} }
@ -193,15 +173,13 @@ struct Handler_CclsMemberHierarchy
: BaseMessageHandler<In_CclsMemberHierarchy> { : BaseMessageHandler<In_CclsMemberHierarchy> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
std::optional<Out_CclsMemberHierarchy::Entry> BuildInitial(SymbolKind kind, std::optional<Out_CclsMemberHierarchy::Entry>
Usr root_usr, BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels) {
bool qualified,
int levels) {
switch (kind) { switch (kind) {
default: default:
return {}; return {};
case SymbolKind::Func: { case SymbolKind::Func: {
const auto* def = db->Func(root_usr).AnyDef(); const auto *def = db->Func(root_usr).AnyDef();
if (!def) if (!def)
return {}; return {};
@ -210,16 +188,16 @@ struct Handler_CclsMemberHierarchy
entry.name = def->Name(qualified); entry.name = def->Name(qualified);
if (def->spell) { if (def->spell) {
if (std::optional<lsLocation> loc = if (std::optional<lsLocation> loc =
GetLsLocation(db, working_files, *def->spell)) GetLsLocation(db, working_files, *def->spell))
entry.location = *loc; entry.location = *loc;
} }
EachDefinedVar(db, def->vars, [&](QueryVar& var) { EachDefinedVar(db, def->vars, [&](QueryVar &var) {
DoField(this, &entry, var, -1, qualified, levels - 1); DoField(this, &entry, var, -1, qualified, levels - 1);
}); });
return entry; return entry;
} }
case SymbolKind::Type: { case SymbolKind::Type: {
const auto* def = db->Type(root_usr).AnyDef(); const auto *def = db->Type(root_usr).AnyDef();
if (!def) if (!def)
return {}; return {};
@ -228,7 +206,7 @@ struct Handler_CclsMemberHierarchy
entry.usr = root_usr; entry.usr = root_usr;
if (def->spell) { if (def->spell) {
if (std::optional<lsLocation> loc = if (std::optional<lsLocation> loc =
GetLsLocation(db, working_files, *def->spell)) GetLsLocation(db, working_files, *def->spell))
entry.location = *loc; entry.location = *loc;
} }
Expand(this, &entry, qualified, levels); Expand(this, &entry, qualified, levels);
@ -237,8 +215,8 @@ struct Handler_CclsMemberHierarchy
} }
} }
void Run(In_CclsMemberHierarchy* request) override { void Run(In_CclsMemberHierarchy *request) override {
auto& params = request->params; auto &params = request->params;
Out_CclsMemberHierarchy out; Out_CclsMemberHierarchy out;
out.id = request->id; out.id = request->id;
@ -256,29 +234,28 @@ struct Handler_CclsMemberHierarchy
Expand(this, &entry, params.qualified, params.levels)) Expand(this, &entry, params.qualified, params.levels))
out.result = std::move(entry); out.result = std::move(entry);
} else { } else {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile* wfile = WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
working_files->GetFileByFilename(file->def->path);
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(wfile, file, params.position)) { FindSymbolsAtLocation(wfile, file, params.position)) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Func: case SymbolKind::Func:
case SymbolKind::Type: case SymbolKind::Type:
out.result = BuildInitial(sym.kind, sym.usr, params.qualified, out.result =
params.levels); BuildInitial(sym.kind, sym.usr, params.qualified, params.levels);
break; break;
case SymbolKind::Var: { case SymbolKind::Var: {
const QueryVar::Def* def = db->GetVar(sym).AnyDef(); const QueryVar::Def *def = db->GetVar(sym).AnyDef();
if (def && def->type) if (def && def->type)
out.result = BuildInitial(SymbolKind::Type, def->type, out.result = BuildInitial(SymbolKind::Type, def->type,
params.qualified, params.levels); params.qualified, params.levels);
break; break;
} }
default: default:
continue; continue;
} }
break; break;
} }
@ -289,4 +266,4 @@ struct Handler_CclsMemberHierarchy
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy); REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy);
} // namespace } // namespace

View File

@ -1,6 +1,6 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -15,24 +15,21 @@ struct In_CclsVars : public RequestInMessage {
unsigned kind = ~0u; unsigned kind = ~0u;
} params; } params;
}; };
MAKE_REFLECT_STRUCT(In_CclsVars::Params, MAKE_REFLECT_STRUCT(In_CclsVars::Params, textDocument, position, kind);
textDocument,
position,
kind);
MAKE_REFLECT_STRUCT(In_CclsVars, id, params); MAKE_REFLECT_STRUCT(In_CclsVars, id, params);
REGISTER_IN_MESSAGE(In_CclsVars); REGISTER_IN_MESSAGE(In_CclsVars);
struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> { struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsVars* request) override { void Run(In_CclsVars *request) override {
auto& params = request->params; auto &params = request->params;
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_LocationList out; Out_LocationList out;
@ -41,24 +38,24 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
FindSymbolsAtLocation(working_file, file, params.position)) { FindSymbolsAtLocation(working_file, file, params.position)) {
Usr usr = sym.usr; Usr usr = sym.usr;
switch (sym.kind) { switch (sym.kind) {
default: default:
break; break;
case SymbolKind::Var: { case SymbolKind::Var: {
const QueryVar::Def* def = db->GetVar(sym).AnyDef(); const QueryVar::Def *def = db->GetVar(sym).AnyDef();
if (!def || !def->type) if (!def || !def->type)
continue; continue;
usr = def->type; usr = def->type;
[[fallthrough]]; [[fallthrough]];
} }
case SymbolKind::Type: case SymbolKind::Type:
out.result = GetLsLocationExs( out.result = GetLsLocationExs(
db, working_files, db, working_files,
GetVarDeclarations(db, db->Type(usr).instances, params.kind)); GetVarDeclarations(db, db->Type(usr).instances, params.kind));
break; break;
} }
} }
pipeline::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsVars); REGISTER_MESSAGE_HANDLER(Handler_CclsVars);
} // namespace } // namespace

View File

@ -10,9 +10,7 @@ REGISTER_IN_MESSAGE(In_Exit);
struct Handler_Exit : MessageHandler { struct Handler_Exit : MessageHandler {
MethodType GetMethodType() const override { return kMethodType_Exit; } MethodType GetMethodType() const override { return kMethodType_Exit; }
void Run(std::unique_ptr<InMessage> request) override { void Run(std::unique_ptr<InMessage> request) override { exit(0); }
exit(0);
}
}; };
REGISTER_MESSAGE_HANDLER(Handler_Exit); REGISTER_MESSAGE_HANDLER(Handler_Exit);
} // namespace } // namespace

View File

@ -55,8 +55,7 @@ struct lsDocumentOnTypeFormattingOptions {
// More trigger characters. // More trigger characters.
std::vector<std::string> moreTriggerCharacter; std::vector<std::string> moreTriggerCharacter;
}; };
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, firstTriggerCharacter,
firstTriggerCharacter,
moreTriggerCharacter); moreTriggerCharacter);
// Document link options // Document link options
@ -119,12 +118,8 @@ struct lsTextDocumentSyncOptions {
// Save notifications are sent to the server. // Save notifications are sent to the server.
std::optional<lsSaveOptions> save; std::optional<lsSaveOptions> save;
}; };
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, openClose, change, willSave,
openClose, willSaveWaitUntil, save);
change,
willSave,
willSaveWaitUntil,
save);
struct lsServerCapabilities { struct lsServerCapabilities {
// Defines how text documents are synced. Is either a detailed structure // Defines how text documents are synced. Is either a detailed structure
@ -161,7 +156,8 @@ struct lsServerCapabilities {
// The server provides document range formatting. // The server provides document range formatting.
bool documentRangeFormattingProvider = false; bool documentRangeFormattingProvider = false;
// The server provides document formatting on typing. // The server provides document formatting on typing.
std::optional<lsDocumentOnTypeFormattingOptions> documentOnTypeFormattingProvider; std::optional<lsDocumentOnTypeFormattingOptions>
documentOnTypeFormattingProvider;
// The server provides rename support. // The server provides rename support.
bool renameProvider = true; bool renameProvider = true;
// The server provides document link support. // The server provides document link support.
@ -169,25 +165,15 @@ struct lsServerCapabilities {
// The server provides execute command support. // The server provides execute command support.
lsExecuteCommandOptions executeCommandProvider; lsExecuteCommandOptions executeCommandProvider;
}; };
MAKE_REFLECT_STRUCT(lsServerCapabilities, MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider,
textDocumentSync, completionProvider, signatureHelpProvider,
hoverProvider, definitionProvider, typeDefinitionProvider,
completionProvider, referencesProvider, documentHighlightProvider,
signatureHelpProvider, documentSymbolProvider, workspaceSymbolProvider,
definitionProvider, codeActionProvider, codeLensProvider,
typeDefinitionProvider, documentFormattingProvider, documentRangeFormattingProvider,
referencesProvider, documentOnTypeFormattingProvider, renameProvider,
documentHighlightProvider, documentLinkProvider, executeCommandProvider);
documentSymbolProvider,
workspaceSymbolProvider,
codeActionProvider,
codeLensProvider,
documentFormattingProvider,
documentRangeFormattingProvider,
documentOnTypeFormattingProvider,
renameProvider,
documentLinkProvider,
executeCommandProvider);
// Workspace specific client capabilities. // Workspace specific client capabilities.
struct lsWorkspaceClientCapabilites { struct lsWorkspaceClientCapabilites {
@ -226,12 +212,8 @@ MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsWorkspaceEdit,
documentChanges); documentChanges);
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsGenericDynamicReg, MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsGenericDynamicReg,
dynamicRegistration); dynamicRegistration);
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites, MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites, applyEdit, workspaceEdit,
applyEdit, didChangeConfiguration, didChangeWatchedFiles, symbol,
workspaceEdit,
didChangeConfiguration,
didChangeWatchedFiles,
symbol,
executeCommand); executeCommand);
// Text document specific client capabilities. // Text document specific client capabilities.
@ -287,13 +269,9 @@ struct lsTextDocumentClientCapabilities {
}; };
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsSynchronization, MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsSynchronization,
dynamicRegistration, dynamicRegistration, willSave, willSaveWaitUntil, didSave);
willSave,
willSaveWaitUntil,
didSave);
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion, MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion,
dynamicRegistration, dynamicRegistration, completionItem);
completionItem);
MAKE_REFLECT_STRUCT( MAKE_REFLECT_STRUCT(
lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem, lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem,
snippetSupport); snippetSupport);
@ -301,12 +279,9 @@ MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsGenericDynamicReg,
dynamicRegistration); dynamicRegistration);
MAKE_REFLECT_STRUCT( MAKE_REFLECT_STRUCT(
lsTextDocumentClientCapabilities::CodeLensRegistrationOptions, lsTextDocumentClientCapabilities::CodeLensRegistrationOptions,
dynamicRegistration, dynamicRegistration, resolveProvider);
resolveProvider); MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities, synchronization,
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities, completion, rename);
synchronization,
completion,
rename);
struct lsClientCapabilities { struct lsClientCapabilities {
// Workspace specific client capabilities. // Workspace specific client capabilities.
@ -343,16 +318,16 @@ struct lsInitializeParams {
enum class lsTrace { enum class lsTrace {
// NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose'; // NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose';
Off, // off Off, // off
Messages, // messages Messages, // messages
Verbose // verbose Verbose // verbose
}; };
// The initial trace setting. If omitted trace is disabled ('off'). // The initial trace setting. If omitted trace is disabled ('off').
lsTrace trace = lsTrace::Off; lsTrace trace = lsTrace::Off;
}; };
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) { void Reflect(Reader &reader, lsInitializeParams::lsTrace &value) {
if (!reader.IsString()) { if (!reader.IsString()) {
value = lsInitializeParams::lsTrace::Off; value = lsInitializeParams::lsTrace::Off;
return; return;
@ -366,7 +341,7 @@ void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) {
value = lsInitializeParams::lsTrace::Verbose; value = lsInitializeParams::lsTrace::Verbose;
} }
#if 0 // unused #if 0 // unused
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) { void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
switch (value) { switch (value) {
case lsInitializeParams::lsTrace::Off: case lsInitializeParams::lsTrace::Off:
@ -382,13 +357,8 @@ void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
} }
#endif #endif
MAKE_REFLECT_STRUCT(lsInitializeParams, MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri,
processId, initializationOptions, capabilities, trace);
rootPath,
rootUri,
initializationOptions,
capabilities,
trace);
struct lsInitializeError { struct lsInitializeError {
// Indicates whether the client should retry to send the // Indicates whether the client should retry to send the
@ -419,8 +389,8 @@ MAKE_REFLECT_STRUCT(Out_InitializeResponse, jsonrpc, id, result);
struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> { struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_InitializeRequest* request) override { void Run(In_InitializeRequest *request) override {
auto& params = request->params; auto &params = request->params;
if (!params.rootUri) if (!params.rootUri)
return; return;
std::string project_path = NormalizePath(params.rootUri->GetPath()); std::string project_path = NormalizePath(params.rootUri->GetPath());
@ -438,7 +408,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
JsonReader json_reader{&reader}; JsonReader json_reader{&reader};
try { try {
Reflect(json_reader, *g_config); Reflect(json_reader, *g_config);
} catch (std::invalid_argument&) { } catch (std::invalid_argument &) {
// This will not trigger because parse error is handled in // This will not trigger because parse error is handled in
// MessageRegistry::Parse in lsp.cc // MessageRegistry::Parse in lsp.cc
} }
@ -460,7 +430,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
} }
// Client capabilities // Client capabilities
const auto& capabilities = params.capabilities; const auto &capabilities = params.capabilities;
g_config->client.snippetSupport = g_config->client.snippetSupport =
capabilities.textDocument.completion.completionItem.snippetSupport; capabilities.textDocument.completion.completionItem.snippetSupport;
@ -508,7 +478,8 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
std::string name = "indexer" + std::to_string(i); std::string name = "indexer" + std::to_string(i);
set_thread_name(name.c_str()); set_thread_name(name.c_str());
pipeline::Indexer_Main(diag_pub, vfs, project, working_files); pipeline::Indexer_Main(diag_pub, vfs, project, working_files);
}).detach(); })
.detach();
} }
// Start scanning include directories before dispatching project // Start scanning include directories before dispatching project
@ -520,4 +491,4 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_Initialize); REGISTER_MESSAGE_HANDLER(Handler_Initialize);
} // namespace } // namespace

View File

@ -19,11 +19,11 @@ MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result);
struct Handler_Shutdown : BaseMessageHandler<In_Shutdown> { struct Handler_Shutdown : BaseMessageHandler<In_Shutdown> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_Shutdown* request) override { void Run(In_Shutdown *request) override {
Out_Shutdown out; Out_Shutdown out;
out.id = request->id; out.id = request->id;
pipeline::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_Shutdown); REGISTER_MESSAGE_HANDLER(Handler_Shutdown);
} // namespace } // namespace

View File

@ -33,10 +33,8 @@ struct In_TextDocumentCodeAction : public RequestInMessage {
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionContext, MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionContext,
diagnostics); diagnostics);
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams, MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams, textDocument,
textDocument, range, context);
range,
context);
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentCodeAction); REGISTER_IN_MESSAGE(In_TextDocumentCodeAction);
@ -51,7 +49,7 @@ struct Handler_TextDocumentCodeAction
: BaseMessageHandler<In_TextDocumentCodeAction> { : BaseMessageHandler<In_TextDocumentCodeAction> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentCodeAction* request) override { void Run(In_TextDocumentCodeAction *request) override {
const auto &params = request->params; const auto &params = request->params;
WorkingFile *wfile = WorkingFile *wfile =
working_files->GetFileByFilename(params.textDocument.uri.GetPath()); working_files->GetFileByFilename(params.textDocument.uri.GetPath());
@ -74,4 +72,4 @@ struct Handler_TextDocumentCodeAction
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction);
} } // namespace

View File

@ -1,8 +1,8 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "lsp_code_action.h" #include "lsp_code_action.h"
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -30,10 +30,10 @@ struct Out_TextDocumentCodeLens
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
struct CommonCodeLensParams { struct CommonCodeLensParams {
std::vector<TCodeLens>* result; std::vector<TCodeLens> *result;
DB* db; DB *db;
WorkingFiles* working_files; WorkingFiles *working_files;
WorkingFile* working_file; WorkingFile *working_file;
}; };
Use OffsetStartColumn(Use use, int16_t offset) { Use OffsetStartColumn(Use use, int16_t offset) {
@ -41,12 +41,9 @@ Use OffsetStartColumn(Use use, int16_t offset) {
return use; return use;
} }
void AddCodeLens(const char* singular, void AddCodeLens(const char *singular, const char *plural,
const char* plural, CommonCodeLensParams *common, Use use,
CommonCodeLensParams* common, const std::vector<Use> &uses, bool force_display) {
Use use,
const std::vector<Use>& uses,
bool force_display) {
TCodeLens code_lens; TCodeLens code_lens;
std::optional<lsRange> range = GetLsRange(common->working_file, use.range); std::optional<lsRange> range = GetLsRange(common->working_file, use.range);
if (!range) if (!range)
@ -83,7 +80,7 @@ void AddCodeLens(const char* singular,
struct Handler_TextDocumentCodeLens struct Handler_TextDocumentCodeLens
: BaseMessageHandler<In_TextDocumentCodeLens> { : BaseMessageHandler<In_TextDocumentCodeLens> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentCodeLens* request) override { void Run(In_TextDocumentCodeLens *request) override {
Out_TextDocumentCodeLens out; Out_TextDocumentCodeLens out;
out.id = request->id; out.id = request->id;
@ -92,7 +89,7 @@ struct Handler_TextDocumentCodeLens
clang_complete->NotifyView(path); clang_complete->NotifyView(path);
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file)) { request->params.textDocument.uri.GetPath(), &file)) {
return; return;
@ -110,119 +107,118 @@ struct Handler_TextDocumentCodeLens
Use use{{sym.range, sym.usr, sym.kind, sym.role}, file->id}; Use use{{sym.range, sym.usr, sym.kind, sym.role}, file->id};
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
QueryType& type = db->GetType(sym); QueryType &type = db->GetType(sym);
const QueryType::Def* def = type.AnyDef(); const QueryType::Def *def = type.AnyDef();
if (!def || def->kind == lsSymbolKind::Namespace) if (!def || def->kind == lsSymbolKind::Namespace)
continue; continue;
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
type.uses, true /*force_display*/); type.uses, true /*force_display*/);
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1), AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
GetTypeDeclarations(db, type.derived), GetTypeDeclarations(db, type.derived),
false /*force_display*/); false /*force_display*/);
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2), AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
GetVarDeclarations(db, type.instances, true), GetVarDeclarations(db, type.instances, true),
false /*force_display*/); false /*force_display*/);
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
QueryFunc& func = db->GetFunc(sym); QueryFunc &func = db->GetFunc(sym);
const QueryFunc::Def* def = func.AnyDef(); const QueryFunc::Def *def = func.AnyDef();
if (!def) if (!def)
continue; continue;
int16_t offset = 0; int16_t offset = 0;
// For functions, the outline will report a location that is using the // For functions, the outline will report a location that is using the
// extent since that is better for outline. This tries to convert the // extent since that is better for outline. This tries to convert the
// extent location to the spelling location. // extent location to the spelling location.
auto try_ensure_spelling = [&](Use use) { auto try_ensure_spelling = [&](Use use) {
Maybe<Use> def = GetDefinitionSpell(db, use); Maybe<Use> def = GetDefinitionSpell(db, use);
if (!def || def->range.start.line != use.range.start.line) { if (!def || def->range.start.line != use.range.start.line) {
return use; return use;
}
return *def;
};
std::vector<Use> base_callers = GetUsesForAllBases(db, func);
std::vector<Use> derived_callers = GetUsesForAllDerived(db, func);
if (base_callers.empty() && derived_callers.empty()) {
Use loc = try_ensure_spelling(use);
AddCodeLens("call", "calls", &common,
OffsetStartColumn(loc, offset++), func.uses,
true /*force_display*/);
} else {
Use loc = try_ensure_spelling(use);
AddCodeLens("direct call", "direct calls", &common,
OffsetStartColumn(loc, offset++), func.uses,
false /*force_display*/);
if (!base_callers.empty())
AddCodeLens("base call", "base calls", &common,
OffsetStartColumn(loc, offset++), base_callers,
false /*force_display*/);
if (!derived_callers.empty())
AddCodeLens("derived call", "derived calls", &common,
OffsetStartColumn(loc, offset++), derived_callers,
false /*force_display*/);
} }
return *def;
};
AddCodeLens("derived", "derived", &common, std::vector<Use> base_callers = GetUsesForAllBases(db, func);
OffsetStartColumn(use, offset++), std::vector<Use> derived_callers = GetUsesForAllDerived(db, func);
GetFuncDeclarations(db, func.derived), if (base_callers.empty() && derived_callers.empty()) {
Use loc = try_ensure_spelling(use);
AddCodeLens("call", "calls", &common,
OffsetStartColumn(loc, offset++), func.uses,
true /*force_display*/);
} else {
Use loc = try_ensure_spelling(use);
AddCodeLens("direct call", "direct calls", &common,
OffsetStartColumn(loc, offset++), func.uses,
false /*force_display*/); false /*force_display*/);
if (!base_callers.empty())
AddCodeLens("base call", "base calls", &common,
OffsetStartColumn(loc, offset++), base_callers,
false /*force_display*/);
if (!derived_callers.empty())
AddCodeLens("derived call", "derived calls", &common,
OffsetStartColumn(loc, offset++), derived_callers,
false /*force_display*/);
}
// "Base" AddCodeLens(
if (def->bases.size() == 1) { "derived", "derived", &common, OffsetStartColumn(use, offset++),
Maybe<Use> base_loc = GetDefinitionSpell( GetFuncDeclarations(db, func.derived), false /*force_display*/);
db, SymbolIdx{def->bases[0], SymbolKind::Func});
if (base_loc) { // "Base"
std::optional<lsLocation> ls_base = if (def->bases.size() == 1) {
GetLsLocation(db, working_files, *base_loc); Maybe<Use> base_loc = GetDefinitionSpell(
if (ls_base) { db, SymbolIdx{def->bases[0], SymbolKind::Func});
std::optional<lsRange> range = if (base_loc) {
GetLsRange(common.working_file, sym.range); std::optional<lsLocation> ls_base =
if (range) { GetLsLocation(db, working_files, *base_loc);
TCodeLens code_lens; if (ls_base) {
code_lens.range = *range; std::optional<lsRange> range =
code_lens.range.start.character += offset++; GetLsRange(common.working_file, sym.range);
code_lens.command = lsCommand<lsCodeLensCommandArguments>(); if (range) {
code_lens.command->title = "Base"; TCodeLens code_lens;
code_lens.command->command = "ccls.goto"; code_lens.range = *range;
code_lens.command->arguments.uri = ls_base->uri; code_lens.range.start.character += offset++;
code_lens.command->arguments.position = ls_base->range.start; code_lens.command = lsCommand<lsCodeLensCommandArguments>();
out.result.push_back(code_lens); code_lens.command->title = "Base";
} code_lens.command->command = "ccls.goto";
code_lens.command->arguments.uri = ls_base->uri;
code_lens.command->arguments.position = ls_base->range.start;
out.result.push_back(code_lens);
} }
} }
} else {
AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
GetTypeDeclarations(db, def->bases),
false /*force_display*/);
} }
} else {
break; AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
GetTypeDeclarations(db, def->bases),
false /*force_display*/);
} }
case SymbolKind::Var: {
QueryVar& var = db->GetVar(sym);
const QueryVar::Def* def = var.AnyDef();
if (!def || (def->is_local() && !g_config->codeLens.localVariables))
continue;
bool force_display = true; break;
// Do not show 0 refs on macro with no uses, as it is most likely }
// a header guard. case SymbolKind::Var: {
if (def->kind == lsSymbolKind::Macro) QueryVar &var = db->GetVar(sym);
force_display = false; const QueryVar::Def *def = var.AnyDef();
if (!def || (def->is_local() && !g_config->codeLens.localVariables))
continue;
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), bool force_display = true;
var.uses, force_display); // Do not show 0 refs on macro with no uses, as it is most likely
break; // a header guard.
} if (def->kind == lsSymbolKind::Macro)
case SymbolKind::File: force_display = false;
case SymbolKind::Invalid: {
assert(false && "unexpected"); AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), var.uses,
break; force_display);
} break;
}
case SymbolKind::File:
case SymbolKind::Invalid: {
assert(false && "unexpected");
break;
}
}; };
} }
@ -230,4 +226,4 @@ struct Handler_TextDocumentCodeLens
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
} // namespace } // namespace

View File

@ -70,8 +70,8 @@ struct Out_TextDocumentComplete
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result);
void DecorateIncludePaths(const std::smatch& match, void DecorateIncludePaths(const std::smatch &match,
std::vector<lsCompletionItem>* items) { std::vector<lsCompletionItem> *items) {
std::string spaces_after_include = " "; std::string spaces_after_include = " ";
if (match[3].compare("include") == 0 && match[5].length()) if (match[3].compare("include") == 0 && match[5].length())
spaces_after_include = match[4].str(); spaces_after_include = match[4].str();
@ -80,7 +80,7 @@ void DecorateIncludePaths(const std::smatch& match,
match[1].str() + '#' + match[2].str() + "include" + spaces_after_include; match[1].str() + '#' + match[2].str() + "include" + spaces_after_include;
std::string suffix = match[7].str(); std::string suffix = match[7].str();
for (lsCompletionItem& item : *items) { for (lsCompletionItem &item : *items) {
char quote0, quote1; char quote0, quote1;
if (match[5].compare("<") == 0 || if (match[5].compare("<") == 0 ||
(match[5].length() == 0 && item.use_angle_brackets_)) (match[5].length() == 0 && item.use_angle_brackets_))
@ -103,17 +103,16 @@ struct ParseIncludeLineResult {
std::smatch match; std::smatch match;
}; };
ParseIncludeLineResult ParseIncludeLine(const std::string& line) { ParseIncludeLineResult ParseIncludeLine(const std::string &line) {
static const std::regex pattern( static const std::regex pattern("(\\s*)" // [1]: spaces before '#'
"(\\s*)" // [1]: spaces before '#' "#" //
"#" // "(\\s*)" // [2]: spaces after '#'
"(\\s*)" // [2]: spaces after '#' "([^\\s\"<]*)" // [3]: "include"
"([^\\s\"<]*)" // [3]: "include" "(\\s*)" // [4]: spaces before quote
"(\\s*)" // [4]: spaces before quote "([\"<])?" // [5]: the first quote char
"([\"<])?" // [5]: the first quote char "([^\\s\">]*)" // [6]: path of file
"([^\\s\">]*)" // [6]: path of file "[\">]?" //
"[\">]?" // "(.*)"); // [7]: suffix after quote char
"(.*)"); // [7]: suffix after quote char
std::smatch match; std::smatch match;
bool ok = std::regex_match(line, match, pattern); bool ok = std::regex_match(line, match, pattern);
return {ok, match[3], match[5], match[6], match}; return {ok, match[3], match[5], match[6], match};
@ -123,10 +122,10 @@ static const std::vector<std::string> preprocessorKeywords = {
"define", "undef", "include", "if", "ifdef", "ifndef", "define", "undef", "include", "if", "ifdef", "ifndef",
"else", "elif", "endif", "line", "error", "pragma"}; "else", "elif", "endif", "line", "error", "pragma"};
std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems( std::vector<lsCompletionItem>
const std::smatch& match) { PreprocessorKeywordCompletionItems(const std::smatch &match) {
std::vector<lsCompletionItem> items; std::vector<lsCompletionItem> items;
for (auto& keyword : preprocessorKeywords) { for (auto &keyword : preprocessorKeywords) {
lsCompletionItem item; lsCompletionItem item;
item.label = keyword; item.label = keyword;
item.priority_ = (keyword == "include" ? 2 : 1); item.priority_ = (keyword == "include" ? 2 : 1);
@ -140,12 +139,10 @@ std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems(
return items; return items;
} }
template <typename T> template <typename T> char *tofixedbase64(T input, char *out) {
char* tofixedbase64(T input, char* out) { const char *digits = "./0123456789"
const char* digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"./0123456789" "abcdefghijklmnopqrstuvwxyz";
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
int len = (sizeof(T) * 8 - 1) / 6 + 1; int len = (sizeof(T) * 8 - 1) / 6 + 1;
for (int i = len - 1; i >= 0; i--) { for (int i = len - 1; i >= 0; i--) {
out[i] = digits[input % 64]; out[i] = digits[input % 64];
@ -159,16 +156,15 @@ char* tofixedbase64(T input, char* out) {
// significantly snappier completion experience as vscode is easily overloaded // significantly snappier completion experience as vscode is easily overloaded
// when given 1000+ completion items. // when given 1000+ completion items.
void FilterAndSortCompletionResponse( void FilterAndSortCompletionResponse(
Out_TextDocumentComplete* complete_response, Out_TextDocumentComplete *complete_response,
const std::string& complete_text, const std::string &complete_text, bool has_open_paren) {
bool has_open_paren) {
if (!g_config->completion.filterAndSort) if (!g_config->completion.filterAndSort)
return; return;
static Timer timer("FilterAndSortCompletionResponse", ""); static Timer timer("FilterAndSortCompletionResponse", "");
TimeRegion region(timer); TimeRegion region(timer);
auto& items = complete_response->result.items; auto &items = complete_response->result.items;
auto finalize = [&]() { auto finalize = [&]() {
const size_t kMaxResultSize = 100u; const size_t kMaxResultSize = 100u;
@ -178,7 +174,7 @@ void FilterAndSortCompletionResponse(
} }
if (has_open_paren) if (has_open_paren)
for (auto& item: items) for (auto &item : items)
item.insertText = item.label; item.insertText = item.label;
// Set sortText. Note that this happens after resizing - we could do it // Set sortText. Note that this happens after resizing - we could do it
@ -195,7 +191,7 @@ void FilterAndSortCompletionResponse(
} }
// Make sure all items have |filterText| set, code that follow needs it. // Make sure all items have |filterText| set, code that follow needs it.
for (auto& item : items) { for (auto &item : items) {
if (!item.filterText) if (!item.filterText)
item.filterText = item.label; item.filterText = item.label;
} }
@ -203,19 +199,19 @@ void FilterAndSortCompletionResponse(
// Fuzzy match and remove awful candidates. // Fuzzy match and remove awful candidates.
bool sensitive = g_config->completion.caseSensitivity; bool sensitive = g_config->completion.caseSensitivity;
FuzzyMatcher fuzzy(complete_text, sensitive); FuzzyMatcher fuzzy(complete_text, sensitive);
for (auto& item : items) { for (auto &item : items) {
item.score_ = item.score_ =
ReverseSubseqMatch(complete_text, *item.filterText, sensitive) >= 0 ReverseSubseqMatch(complete_text, *item.filterText, sensitive) >= 0
? fuzzy.Match(*item.filterText) ? fuzzy.Match(*item.filterText)
: FuzzyMatcher::kMinScore; : FuzzyMatcher::kMinScore;
} }
items.erase(std::remove_if(items.begin(), items.end(), items.erase(std::remove_if(items.begin(), items.end(),
[](const lsCompletionItem& item) { [](const lsCompletionItem &item) {
return item.score_ <= FuzzyMatcher::kMinScore; return item.score_ <= FuzzyMatcher::kMinScore;
}), }),
items.end()); items.end());
std::sort(items.begin(), items.end(), std::sort(items.begin(), items.end(),
[](const lsCompletionItem& lhs, const lsCompletionItem& rhs) { [](const lsCompletionItem &lhs, const lsCompletionItem &rhs) {
if (lhs.score_ != rhs.score_) if (lhs.score_ != rhs.score_)
return lhs.score_ > rhs.score_; return lhs.score_ > rhs.score_;
if (lhs.priority_ != rhs.priority_) if (lhs.priority_ != rhs.priority_)
@ -231,16 +227,17 @@ void FilterAndSortCompletionResponse(
// Returns true if position is an points to a '(' character in |lines|. Skips // Returns true if position is an points to a '(' character in |lines|. Skips
// whitespace. // whitespace.
bool IsOpenParenOrAngle(const std::vector<std::string>& lines, bool IsOpenParenOrAngle(const std::vector<std::string> &lines,
const lsPosition& position) { const lsPosition &position) {
auto [c, l] = position; auto [c, l] = position;
while (l < lines.size()) { while (l < lines.size()) {
const auto& line = lines[l]; const auto &line = lines[l];
if (c >= line.size()) if (c >= line.size())
return false; return false;
if (line[c] == '(' || line[c] == '<') if (line[c] == '(' || line[c] == '<')
return true; return true;
if (!isspace(line[c])) break; if (!isspace(line[c]))
break;
if (++c >= line.size()) { if (++c >= line.size()) {
c = 0; c = 0;
l++; l++;
@ -254,8 +251,8 @@ struct Handler_TextDocumentCompletion : MessageHandler {
void Run(std::unique_ptr<InMessage> message) override { void Run(std::unique_ptr<InMessage> message) override {
auto request = std::shared_ptr<In_TextDocumentComplete>( auto request = std::shared_ptr<In_TextDocumentComplete>(
static_cast<In_TextDocumentComplete*>(message.release())); static_cast<In_TextDocumentComplete *>(message.release()));
auto& params = request->params; auto &params = request->params;
auto write_empty_result = [request]() { auto write_empty_result = [request]() {
Out_TextDocumentComplete out; Out_TextDocumentComplete out;
@ -264,7 +261,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
}; };
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
WorkingFile* file = working_files->GetFileByFilename(path); WorkingFile *file = working_files->GetFileByFilename(path);
if (!file) { if (!file) {
write_empty_result(); write_empty_result();
return; return;
@ -350,15 +347,16 @@ struct Handler_TextDocumentCompletion : MessageHandler {
if (include_complete->is_scanning) if (include_complete->is_scanning)
lock.lock(); lock.lock();
std::string quote = result.match[5]; std::string quote = result.match[5];
for (auto& item : include_complete->completion_items) for (auto &item : include_complete->completion_items)
if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\"")) if (quote.empty() ||
out.result.items.push_back(item); quote == (item.use_angle_brackets_ ? "<" : "\""))
out.result.items.push_back(item);
} }
FilterAndSortCompletionResponse(&out, result.pattern, has_open_paren); FilterAndSortCompletionResponse(&out, result.pattern, has_open_paren);
DecorateIncludePaths(result.match, &out.result.items); DecorateIncludePaths(result.match, &out.result.items);
} }
for (lsCompletionItem& item : out.result.items) { for (lsCompletionItem &item : out.result.items) {
item.textEdit->range.start.line = params.position.line; item.textEdit->range.start.line = params.position.line;
item.textEdit->range.start.character = 0; item.textEdit->range.start.character = 0;
item.textEdit->range.end.line = params.position.line; item.textEdit->range.end.line = params.position.line;
@ -369,14 +367,15 @@ struct Handler_TextDocumentCompletion : MessageHandler {
} else { } else {
ClangCompleteManager::OnComplete callback = std::bind( ClangCompleteManager::OnComplete callback = std::bind(
[this, request, params, is_global_completion, existing_completion, [this, request, params, is_global_completion, existing_completion,
has_open_paren](const std::vector<lsCompletionItem>& results, has_open_paren](const std::vector<lsCompletionItem> &results,
bool is_cached_result) { bool is_cached_result) {
Out_TextDocumentComplete out; Out_TextDocumentComplete out;
out.id = request->id; out.id = request->id;
out.result.items = results; out.result.items = results;
// Emit completion results. // Emit completion results.
FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren); FilterAndSortCompletionResponse(&out, existing_completion,
has_open_paren);
pipeline::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
// Cache completion results. // Cache completion results.
@ -435,4 +434,4 @@ struct Handler_TextDocumentCompletion : MessageHandler {
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCompletion); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCompletion);
} // namespace } // namespace

View File

@ -3,9 +3,9 @@
#include "query_utils.h" #include "query_utils.h"
using namespace ccls; using namespace ccls;
#include <cstdlib>
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <cstdlib>
namespace { namespace {
MethodType kMethodType = "textDocument/definition"; MethodType kMethodType = "textDocument/definition";
@ -24,35 +24,35 @@ struct Out_TextDocumentDefinition
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
std::vector<Use> GetNonDefDeclarationTargets(DB* db, SymbolRef sym) { std::vector<Use> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Var: { case SymbolKind::Var: {
std::vector<Use> ret = GetNonDefDeclarations(db, sym); std::vector<Use> ret = GetNonDefDeclarations(db, sym);
// If there is no declaration, jump the its type. // If there is no declaration, jump the its type.
if (ret.empty()) { if (ret.empty()) {
for (auto& def : db->GetVar(sym).def) for (auto &def : db->GetVar(sym).def)
if (def.type) { if (def.type) {
if (Maybe<Use> use = GetDefinitionSpell( if (Maybe<Use> use = GetDefinitionSpell(
db, SymbolIdx{def.type, SymbolKind::Type})) { db, SymbolIdx{def.type, SymbolKind::Type})) {
ret.push_back(*use); ret.push_back(*use);
break; break;
}
} }
} }
return ret;
} }
default: return ret;
return GetNonDefDeclarations(db, sym); }
default:
return GetNonDefDeclarations(db, sym);
} }
} }
struct Handler_TextDocumentDefinition struct Handler_TextDocumentDefinition
: BaseMessageHandler<In_TextDocumentDefinition> { : BaseMessageHandler<In_TextDocumentDefinition> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDefinition* request) override { void Run(In_TextDocumentDefinition *request) override {
auto& params = request->params; auto &params = request->params;
int file_id; int file_id;
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file, &file_id)) params.textDocument.uri.GetPath(), &file, &file_id))
return; return;
@ -62,9 +62,8 @@ struct Handler_TextDocumentDefinition
Maybe<Use> on_def; Maybe<Use> on_def;
bool has_symbol = false; bool has_symbol = false;
WorkingFile* wfile = WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
working_files->GetFileByFilename(file->def->path); lsPosition &ls_pos = params.position;
lsPosition& ls_pos = params.position;
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) { for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) {
// Found symbol. Return definition. // Found symbol. Return definition.
@ -75,7 +74,7 @@ struct Handler_TextDocumentDefinition
// - start at spelling but end at extent for better mouse tooltip // - start at spelling but end at extent for better mouse tooltip
// - goto declaration while in definition of recursive type // - goto declaration while in definition of recursive type
std::vector<Use> uses; std::vector<Use> uses;
EachEntityDef(db, sym, [&](const auto& def) { EachEntityDef(db, sym, [&](const auto &def) {
if (def.spell && def.extent) { if (def.spell && def.extent) {
Use spell = *def.spell; Use spell = *def.spell;
// If on a definition, clear |uses| to find declarations below. // If on a definition, clear |uses| to find declarations below.
@ -109,7 +108,7 @@ struct Handler_TextDocumentDefinition
// No symbols - check for includes. // No symbols - check for includes.
if (out.result.empty()) { if (out.result.empty()) {
for (const IndexInclude& include : file->def->includes) { for (const IndexInclude &include : file->def->includes) {
if (include.line == ls_pos.line) { if (include.line == ls_pos.line) {
lsLocationEx result; lsLocationEx result;
result.uri = lsDocumentUri::FromPath(include.resolved_path); result.uri = lsDocumentUri::FromPath(include.resolved_path);
@ -121,7 +120,7 @@ struct Handler_TextDocumentDefinition
// Find the best match of the identifier at point. // Find the best match of the identifier at point.
if (!has_symbol) { if (!has_symbol) {
lsPosition position = request->params.position; lsPosition position = request->params.position;
const std::string& buffer = wfile->buffer_content; const std::string &buffer = wfile->buffer_content;
std::string_view query = LexIdentifierAroundPos(position, buffer); std::string_view query = LexIdentifierAroundPos(position, buffer);
std::string_view short_query = query; std::string_view short_query = query;
{ {
@ -161,11 +160,11 @@ struct Handler_TextDocumentDefinition
} }
} }
}; };
for (auto& func : db->funcs) for (auto &func : db->funcs)
fn({func.usr, SymbolKind::Func}); fn({func.usr, SymbolKind::Func});
for (auto& type : db->types) for (auto &type : db->types)
fn({type.usr, SymbolKind::Type}); fn({type.usr, SymbolKind::Type});
for (auto& var : db->vars) for (auto &var : db->vars)
if (var.def.size() && !var.def[0].is_local()) if (var.def.size() && !var.def[0].is_local())
fn({var.usr, SymbolKind::Var}); fn({var.usr, SymbolKind::Var});
@ -183,4 +182,4 @@ struct Handler_TextDocumentDefinition
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition);
} // namespace } // namespace

View File

@ -1,8 +1,8 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "project.h" #include "project.h"
#include "working_files.h" #include "working_files.h"
#include "pipeline.hh"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -20,7 +20,7 @@ struct Handler_TextDocumentDidChange
: BaseMessageHandler<In_TextDocumentDidChange> { : BaseMessageHandler<In_TextDocumentDidChange> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDidChange* request) override { void Run(In_TextDocumentDidChange *request) override {
std::string path = request->params.textDocument.uri.GetPath(); std::string path = request->params.textDocument.uri.GetPath();
working_files->OnChange(request->params); working_files->OnChange(request->params);
if (g_config->index.onDidChange) { if (g_config->index.onDidChange) {
@ -33,4 +33,4 @@ struct Handler_TextDocumentDidChange
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange);
} // namespace } // namespace

View File

@ -22,7 +22,7 @@ struct Handler_TextDocumentDidClose
: BaseMessageHandler<In_TextDocumentDidClose> { : BaseMessageHandler<In_TextDocumentDidClose> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDidClose* request) override { void Run(In_TextDocumentDidClose *request) override {
std::string path = request->params.textDocument.uri.GetPath(); std::string path = request->params.textDocument.uri.GetPath();
// Clear any diagnostics for the file. // Clear any diagnostics for the file.
@ -36,4 +36,4 @@ struct Handler_TextDocumentDidClose
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose);
} // namespace } // namespace

View File

@ -1,8 +1,8 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "include_complete.h" #include "include_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls; using namespace ccls;
@ -12,7 +12,7 @@ MethodType kMethodType = "textDocument/didOpen";
// Open, view, change, close file // Open, view, change, close file
struct In_TextDocumentDidOpen : public NotificationInMessage { struct In_TextDocumentDidOpen : public NotificationInMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
lsTextDocumentItem textDocument; lsTextDocumentItem textDocument;
@ -31,18 +31,18 @@ struct Handler_TextDocumentDidOpen
: BaseMessageHandler<In_TextDocumentDidOpen> { : BaseMessageHandler<In_TextDocumentDidOpen> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDidOpen* request) override { void Run(In_TextDocumentDidOpen *request) override {
// NOTE: This function blocks code lens. If it starts taking a long time // NOTE: This function blocks code lens. If it starts taking a long time
// we will need to find a way to unblock the code lens request. // we will need to find a way to unblock the code lens request.
const auto& params = request->params; const auto &params = request->params;
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
WorkingFile* working_file = working_files->OnOpen(params.textDocument); WorkingFile *working_file = working_files->OnOpen(params.textDocument);
if (std::optional<std::string> cached_file_contents = if (std::optional<std::string> cached_file_contents =
pipeline::LoadCachedFileContents(path)) pipeline::LoadCachedFileContents(path))
working_file->SetIndexContent(*cached_file_contents); working_file->SetIndexContent(*cached_file_contents);
QueryFile* file = nullptr; QueryFile *file = nullptr;
FindFileOrFail(db, project, std::nullopt, path, &file); FindFileOrFail(db, project, std::nullopt, path, &file);
if (file && file->def) { if (file && file->def) {
EmitSkippedRanges(working_file, file->def->skipped_ranges); EmitSkippedRanges(working_file, file->def->skipped_ranges);
@ -68,4 +68,4 @@ struct Handler_TextDocumentDidOpen
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
} // namespace } // namespace

View File

@ -1,7 +1,7 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -28,8 +28,8 @@ struct Handler_TextDocumentDidSave
: BaseMessageHandler<In_TextDocumentDidSave> { : BaseMessageHandler<In_TextDocumentDidSave> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDidSave* request) override { void Run(In_TextDocumentDidSave *request) override {
const auto& params = request->params; const auto &params = request->params;
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
// Send out an index request, and copy the current buffer state so we // Send out an index request, and copy the current buffer state so we
@ -55,4 +55,4 @@ struct Handler_TextDocumentDidSave
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidSave); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidSave);
} // namespace } // namespace

View File

@ -24,16 +24,16 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentHighlight, jsonrpc, id, result);
struct Handler_TextDocumentDocumentHighlight struct Handler_TextDocumentDocumentHighlight
: BaseMessageHandler<In_TextDocumentDocumentHighlight> { : BaseMessageHandler<In_TextDocumentDocumentHighlight> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDocumentHighlight* request) override { void Run(In_TextDocumentDocumentHighlight *request) override {
int file_id; int file_id;
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file, request->params.textDocument.uri.GetPath(), &file,
&file_id)) { &file_id)) {
return; return;
} }
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentDocumentHighlight out; Out_TextDocumentDocumentHighlight out;
@ -66,4 +66,4 @@ struct Handler_TextDocumentDocumentHighlight
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);
} // namespace } // namespace

View File

@ -38,10 +38,10 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
struct Handler_TextDocumentDocumentSymbol struct Handler_TextDocumentDocumentSymbol
: BaseMessageHandler<In_TextDocumentDocumentSymbol> { : BaseMessageHandler<In_TextDocumentDocumentSymbol> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDocumentSymbol* request) override { void Run(In_TextDocumentDocumentSymbol *request) override {
auto& params = request->params; auto &params = request->params;
QueryFile* file; QueryFile *file;
int file_id; int file_id;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file, &file_id)) params.textDocument.uri.GetPath(), &file, &file_id))
@ -67,8 +67,8 @@ struct Handler_TextDocumentDocumentSymbol
if (std::optional<lsSymbolInformation> info = if (std::optional<lsSymbolInformation> info =
GetSymbolInfo(db, working_files, sym, false)) { GetSymbolInfo(db, working_files, sym, false)) {
if (sym.kind == SymbolKind::Var) { if (sym.kind == SymbolKind::Var) {
QueryVar& var = db->GetVar(sym); QueryVar &var = db->GetVar(sym);
auto* def = var.AnyDef(); auto *def = var.AnyDef();
if (!def || !def->spell || def->is_local()) if (!def || !def->spell || def->is_local())
continue; continue;
} }
@ -84,4 +84,4 @@ struct Handler_TextDocumentDocumentSymbol
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol);
} // namespace } // namespace

View File

@ -7,10 +7,10 @@ namespace {
MethodType kMethodType = "textDocument/hover"; MethodType kMethodType = "textDocument/hover";
// Find the comments for |sym|, if any. // Find the comments for |sym|, if any.
std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) { std::optional<lsMarkedString> GetComments(DB *db, SymbolRef sym) {
std::optional<lsMarkedString> ret; std::optional<lsMarkedString> ret;
WithEntity(db, sym, [&](const auto& entity) { WithEntity(db, sym, [&](const auto &entity) {
if (const auto* def = entity.AnyDef()) if (const auto *def = entity.AnyDef())
if (def->comments[0]) { if (def->comments[0]) {
lsMarkedString m; lsMarkedString m;
m.value = def->comments; m.value = def->comments;
@ -21,12 +21,11 @@ std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) {
} }
// Returns the hover or detailed name for `sym`, if any. // Returns the hover or detailed name for `sym`, if any.
std::optional<lsMarkedString> GetHoverOrName(DB* db, std::optional<lsMarkedString> GetHoverOrName(DB *db, LanguageId lang,
LanguageId lang,
SymbolRef sym) { SymbolRef sym) {
std::optional<lsMarkedString> ret; std::optional<lsMarkedString> ret;
WithEntity(db, sym, [&](const auto& entity) { WithEntity(db, sym, [&](const auto &entity) {
if (const auto* def = entity.AnyDef()) { if (const auto *def = entity.AnyDef()) {
lsMarkedString m; lsMarkedString m;
m.language = LanguageIdentifier(lang); m.language = LanguageIdentifier(lang);
if (def->hover[0]) { if (def->hover[0]) {
@ -58,21 +57,19 @@ struct Out_TextDocumentHover : public lsOutMessage<Out_TextDocumentHover> {
std::optional<Result> result; std::optional<Result> result;
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range); MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover, MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover, jsonrpc, id,
jsonrpc,
id,
result); result);
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> { struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentHover* request) override { void Run(In_TextDocumentHover *request) override {
auto& params = request->params; auto &params = request->params;
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentHover out; Out_TextDocumentHover out;
@ -104,4 +101,4 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover);
} // namespace } // namespace

View File

@ -1,6 +1,6 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -16,14 +16,14 @@ REGISTER_IN_MESSAGE(In_TextDocumentImplementation);
struct Handler_TextDocumentImplementation struct Handler_TextDocumentImplementation
: BaseMessageHandler<In_TextDocumentImplementation> { : BaseMessageHandler<In_TextDocumentImplementation> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentImplementation* request) override { void Run(In_TextDocumentImplementation *request) override {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file)) { request->params.textDocument.uri.GetPath(), &file)) {
return; return;
} }
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_LocationList out; Out_LocationList out;
@ -31,12 +31,12 @@ struct Handler_TextDocumentImplementation
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
if (sym.kind == SymbolKind::Type) { if (sym.kind == SymbolKind::Type) {
QueryType& type = db->GetType(sym); QueryType &type = db->GetType(sym);
out.result = GetLsLocationExs(db, working_files, out.result = GetLsLocationExs(db, working_files,
GetTypeDeclarations(db, type.derived)); GetTypeDeclarations(db, type.derived));
break; break;
} else if (sym.kind == SymbolKind::Func) { } else if (sym.kind == SymbolKind::Func) {
QueryFunc& func = db->GetFunc(sym); QueryFunc &func = db->GetFunc(sym);
out.result = GetLsLocationExs(db, working_files, out.result = GetLsLocationExs(db, working_files,
GetFuncDeclarations(db, func.derived)); GetFuncDeclarations(db, func.derived));
break; break;
@ -46,4 +46,4 @@ struct Handler_TextDocumentImplementation
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
} // namespace } // namespace

View File

@ -27,14 +27,9 @@ struct In_TextDocumentReferences : public RequestInMessage {
Params params; Params params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::lsReferenceContext, MAKE_REFLECT_STRUCT(In_TextDocumentReferences::lsReferenceContext, base,
base, excludeRole, includeDeclaration, role);
excludeRole, MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params, textDocument, position,
includeDeclaration,
role);
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params,
textDocument,
position,
context); context);
MAKE_REFLECT_STRUCT(In_TextDocumentReferences, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentReferences, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentReferences); REGISTER_IN_MESSAGE(In_TextDocumentReferences);
@ -50,15 +45,14 @@ struct Handler_TextDocumentReferences
: BaseMessageHandler<In_TextDocumentReferences> { : BaseMessageHandler<In_TextDocumentReferences> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentReferences* request) override { void Run(In_TextDocumentReferences *request) override {
auto& params = request->params; auto &params = request->params;
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile* wfile = WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
working_files->GetFileByFilename(file->def->path);
Out_TextDocumentReferences out; Out_TextDocumentReferences out;
out.id = request->id; out.id = request->id;
@ -86,9 +80,9 @@ struct Handler_TextDocumentReferences
out.result.push_back(*ls_loc); out.result.push_back(*ls_loc);
} }
}; };
WithEntity(db, sym, [&](const auto& entity) { WithEntity(db, sym, [&](const auto &entity) {
lsSymbolKind parent_kind = lsSymbolKind::Unknown; lsSymbolKind parent_kind = lsSymbolKind::Unknown;
for (auto& def : entity.def) for (auto &def : entity.def)
if (def.spell) { if (def.spell) {
parent_kind = GetSymbolKind(db, sym); parent_kind = GetSymbolKind(db, sym);
if (params.context.base) if (params.context.base)
@ -102,7 +96,7 @@ struct Handler_TextDocumentReferences
for (Use use : entity.uses) for (Use use : entity.uses)
fn(use, parent_kind); fn(use, parent_kind);
if (params.context.includeDeclaration) { if (params.context.includeDeclaration) {
for (auto& def : entity.def) for (auto &def : entity.def)
if (def.spell) if (def.spell)
fn(*def.spell, parent_kind); fn(*def.spell, parent_kind);
for (Use use : entity.declarations) for (Use use : entity.declarations)
@ -120,21 +114,20 @@ struct Handler_TextDocumentReferences
std::string path; std::string path;
if (params.position.line == 0) if (params.position.line == 0)
path = file->def->path; path = file->def->path;
for (const IndexInclude& include : file->def->includes) for (const IndexInclude &include : file->def->includes)
if (include.line == params.position.line) { if (include.line == params.position.line) {
path = include.resolved_path; path = include.resolved_path;
break; break;
} }
if (path.size()) if (path.size())
for (QueryFile& file1 : db->files) for (QueryFile &file1 : db->files)
if (file1.def) if (file1.def)
for (const IndexInclude& include : file1.def->includes) for (const IndexInclude &include : file1.def->includes)
if (include.resolved_path == path) { if (include.resolved_path == path) {
// Another file |file1| has the same include line. // Another file |file1| has the same include line.
lsLocationEx result; lsLocationEx result;
result.uri = lsDocumentUri::FromPath(file1.def->path); result.uri = lsDocumentUri::FromPath(file1.def->path);
result.range.start.line = result.range.end.line = result.range.start.line = result.range.end.line = include.line;
include.line;
out.result.push_back(std::move(result)); out.result.push_back(std::move(result));
break; break;
} }
@ -146,4 +139,4 @@ struct Handler_TextDocumentReferences
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences);
} // namespace } // namespace

View File

@ -1,19 +1,18 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/rename"; MethodType kMethodType = "textDocument/rename";
lsWorkspaceEdit BuildWorkspaceEdit(DB* db, lsWorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *working_files,
WorkingFiles* working_files, SymbolRef sym, const std::string &new_text) {
SymbolRef sym,
const std::string& new_text) {
std::unordered_map<int, lsTextDocumentEdit> path_to_edit; std::unordered_map<int, lsTextDocumentEdit> path_to_edit;
EachOccurrence(db, sym, true, [&](Use use) { EachOccurrence(db, sym, true, [&](Use use) {
std::optional<lsLocation> ls_location = GetLsLocation(db, working_files, use); std::optional<lsLocation> ls_location =
GetLsLocation(db, working_files, use);
if (!ls_location) if (!ls_location)
return; return;
@ -21,14 +20,14 @@ lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
if (path_to_edit.find(file_id) == path_to_edit.end()) { if (path_to_edit.find(file_id) == path_to_edit.end()) {
path_to_edit[file_id] = lsTextDocumentEdit(); path_to_edit[file_id] = lsTextDocumentEdit();
QueryFile& file = db->files[file_id]; QueryFile &file = db->files[file_id];
if (!file.def) if (!file.def)
return; return;
const std::string& path = file.def->path; const std::string &path = file.def->path;
path_to_edit[file_id].textDocument.uri = lsDocumentUri::FromPath(path); path_to_edit[file_id].textDocument.uri = lsDocumentUri::FromPath(path);
WorkingFile* working_file = working_files->GetFileByFilename(path); WorkingFile *working_file = working_files->GetFileByFilename(path);
if (working_file) if (working_file)
path_to_edit[file_id].textDocument.version = working_file->version; path_to_edit[file_id].textDocument.version = working_file->version;
} }
@ -38,13 +37,13 @@ lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
edit.newText = new_text; edit.newText = new_text;
// vscode complains if we submit overlapping text edits. // vscode complains if we submit overlapping text edits.
auto& edits = path_to_edit[file_id].edits; auto &edits = path_to_edit[file_id].edits;
if (std::find(edits.begin(), edits.end(), edit) == edits.end()) if (std::find(edits.begin(), edits.end(), edit) == edits.end())
edits.push_back(edit); edits.push_back(edit);
}); });
lsWorkspaceEdit edit; lsWorkspaceEdit edit;
for (const auto& changes : path_to_edit) for (const auto &changes : path_to_edit)
edit.documentChanges.push_back(changes.second); edit.documentChanges.push_back(changes.second);
return edit; return edit;
} }
@ -65,9 +64,7 @@ struct In_TextDocumentRename : public RequestInMessage {
}; };
Params params; Params params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params, MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params, textDocument, position,
textDocument,
position,
newName); newName);
MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentRename); REGISTER_IN_MESSAGE(In_TextDocumentRename);
@ -80,16 +77,16 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result);
struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> { struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentRename* request) override { void Run(In_TextDocumentRename *request) override {
int file_id; int file_id;
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file, request->params.textDocument.uri.GetPath(), &file,
&file_id)) { &file_id)) {
return; return;
} }
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentRename out; Out_TextDocumentRename out;
@ -107,4 +104,4 @@ struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename);
} // namespace } // namespace

View File

@ -70,9 +70,7 @@ struct lsSignatureHelp {
// active signature does have any. // active signature does have any.
std::optional<int> activeParameter; std::optional<int> activeParameter;
}; };
MAKE_REFLECT_STRUCT(lsSignatureHelp, MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature,
signatures,
activeSignature,
activeParameter); activeParameter);
struct Out_TextDocumentSignatureHelp struct Out_TextDocumentSignatureHelp
@ -86,9 +84,9 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(std::unique_ptr<InMessage> message) override { void Run(std::unique_ptr<InMessage> message) override {
auto request = static_cast<In_TextDocumentSignatureHelp*>(message.get()); auto request = static_cast<In_TextDocumentSignatureHelp *>(message.get());
lsTextDocumentPositionParams& params = request->params; lsTextDocumentPositionParams &params = request->params;
WorkingFile* file = WorkingFile *file =
working_files->GetFileByFilename(params.textDocument.uri.GetPath()); working_files->GetFileByFilename(params.textDocument.uri.GetPath());
std::string search; std::string search;
int active_param = 0; int active_param = 0;
@ -102,21 +100,21 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
return; return;
ClangCompleteManager::OnComplete callback = std::bind( ClangCompleteManager::OnComplete callback = std::bind(
[this](InMessage* message, std::string search, int active_param, [this](InMessage *message, std::string search, int active_param,
const std::vector<lsCompletionItem>& results, const std::vector<lsCompletionItem> &results,
bool is_cached_result) { bool is_cached_result) {
auto msg = static_cast<In_TextDocumentSignatureHelp*>(message); auto msg = static_cast<In_TextDocumentSignatureHelp *>(message);
Out_TextDocumentSignatureHelp out; Out_TextDocumentSignatureHelp out;
out.id = msg->id; out.id = msg->id;
for (auto& result : results) { for (auto &result : results) {
if (result.label != search) if (result.label != search)
continue; continue;
lsSignatureInformation signature; lsSignatureInformation signature;
signature.label = result.detail; signature.label = result.detail;
for (auto& parameter : result.parameters_) { for (auto &parameter : result.parameters_) {
lsParameterInformation ls_param; lsParameterInformation ls_param;
ls_param.label = parameter; ls_param.label = parameter;
signature.parameters.push_back(ls_param); signature.parameters.push_back(ls_param);
@ -168,4 +166,4 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentSignatureHelp); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentSignatureHelp);
} // namespace } // namespace

View File

@ -23,14 +23,14 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentTypeDefinition, jsonrpc, id, result);
struct Handler_TextDocumentTypeDefinition struct Handler_TextDocumentTypeDefinition
: BaseMessageHandler<In_TextDocumentTypeDefinition> { : BaseMessageHandler<In_TextDocumentTypeDefinition> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentTypeDefinition* request) override { void Run(In_TextDocumentTypeDefinition *request) override {
QueryFile* file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file, request->params.textDocument.uri.GetPath(), &file,
nullptr)) { nullptr)) {
return; return;
} }
WorkingFile* working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentTypeDefinition out; Out_TextDocumentTypeDefinition out;
@ -39,25 +39,25 @@ struct Handler_TextDocumentTypeDefinition
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
Usr usr = sym.usr; Usr usr = sym.usr;
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Var: { case SymbolKind::Var: {
const QueryVar::Def* def = db->GetVar(sym).AnyDef(); const QueryVar::Def *def = db->GetVar(sym).AnyDef();
if (!def || !def->type) if (!def || !def->type)
continue; continue;
usr = def->type; usr = def->type;
[[fallthrough]]; [[fallthrough]];
} }
case SymbolKind::Type: { case SymbolKind::Type: {
QueryType& type = db->Type(usr); QueryType &type = db->Type(usr);
for (const auto& def : type.def) for (const auto &def : type.def)
if (def.spell) { if (def.spell) {
if (auto ls_loc = GetLsLocationEx(db, working_files, *def.spell, if (auto ls_loc = GetLsLocationEx(db, working_files, *def.spell,
g_config->xref.container)) g_config->xref.container))
out.result.push_back(*ls_loc); out.result.push_back(*ls_loc);
} }
break; break;
} }
default: default:
break; break;
} }
} }
@ -66,4 +66,4 @@ struct Handler_TextDocumentTypeDefinition
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);
} // namespace } // namespace

View File

@ -1,7 +1,7 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls; using namespace ccls;
@ -23,7 +23,7 @@ REGISTER_IN_MESSAGE(In_WorkspaceDidChangeConfiguration);
struct Handler_WorkspaceDidChangeConfiguration struct Handler_WorkspaceDidChangeConfiguration
: BaseMessageHandler<In_WorkspaceDidChangeConfiguration> { : BaseMessageHandler<In_WorkspaceDidChangeConfiguration> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_WorkspaceDidChangeConfiguration* request) override { void Run(In_WorkspaceDidChangeConfiguration *request) override {
project->Load(g_config->projectRoot); project->Load(g_config->projectRoot);
project->Index(working_files, lsRequestId()); project->Index(working_files, lsRequestId());
@ -31,4 +31,4 @@ struct Handler_WorkspaceDidChangeConfiguration
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeConfiguration); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeConfiguration);
} // namespace } // namespace

View File

@ -1,7 +1,7 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls; using namespace ccls;
@ -36,8 +36,8 @@ REGISTER_IN_MESSAGE(In_WorkspaceDidChangeWatchedFiles);
struct Handler_WorkspaceDidChangeWatchedFiles struct Handler_WorkspaceDidChangeWatchedFiles
: BaseMessageHandler<In_WorkspaceDidChangeWatchedFiles> { : BaseMessageHandler<In_WorkspaceDidChangeWatchedFiles> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_WorkspaceDidChangeWatchedFiles* request) override { void Run(In_WorkspaceDidChangeWatchedFiles *request) override {
for (lsFileEvent& event : request->params.changes) { for (lsFileEvent &event : request->params.changes) {
std::string path = event.uri.GetPath(); std::string path = event.uri.GetPath();
Project::Entry entry; Project::Entry entry;
{ {
@ -50,19 +50,19 @@ struct Handler_WorkspaceDidChangeWatchedFiles
bool is_interactive = bool is_interactive =
working_files->GetFileByFilename(entry.filename) != nullptr; working_files->GetFileByFilename(entry.filename) != nullptr;
switch (event.type) { switch (event.type) {
case lsFileChangeType::Created: case lsFileChangeType::Created:
case lsFileChangeType::Changed: { case lsFileChangeType::Changed: {
pipeline::Index(path, entry.args, is_interactive); pipeline::Index(path, entry.args, is_interactive);
if (is_interactive) if (is_interactive)
clang_complete->NotifySave(path); clang_complete->NotifySave(path);
break; break;
} }
case lsFileChangeType::Deleted: case lsFileChangeType::Deleted:
pipeline::Index(path, entry.args, is_interactive); pipeline::Index(path, entry.args, is_interactive);
break; break;
} }
} }
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeWatchedFiles); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeWatchedFiles);
} // namespace } // namespace

View File

@ -1,7 +1,7 @@
#include "lsp_code_action.h" #include "lsp_code_action.h"
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -24,8 +24,8 @@ MAKE_REFLECT_STRUCT(Out_WorkspaceExecuteCommand, jsonrpc, id, result);
struct Handler_WorkspaceExecuteCommand struct Handler_WorkspaceExecuteCommand
: BaseMessageHandler<In_WorkspaceExecuteCommand> { : BaseMessageHandler<In_WorkspaceExecuteCommand> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_WorkspaceExecuteCommand* request) override { void Run(In_WorkspaceExecuteCommand *request) override {
const auto& params = request->params; const auto &params = request->params;
Out_WorkspaceExecuteCommand out; Out_WorkspaceExecuteCommand out;
out.id = request->id; out.id = request->id;
if (params.command == "ccls._applyFixIt") { if (params.command == "ccls._applyFixIt") {
@ -40,4 +40,4 @@ struct Handler_WorkspaceExecuteCommand
}; };
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
} // namespace } // namespace

View File

@ -4,21 +4,18 @@
#include "query_utils.h" #include "query_utils.h"
using namespace ccls; using namespace ccls;
#include <ctype.h>
#include <limits.h>
#include <algorithm> #include <algorithm>
#include <ctype.h>
#include <functional> #include <functional>
#include <limits.h>
namespace { namespace {
MethodType kMethodType = "workspace/symbol"; MethodType kMethodType = "workspace/symbol";
// Lookup |symbol| in |db| and insert the value into |result|. // Lookup |symbol| in |db| and insert the value into |result|.
bool AddSymbol( bool AddSymbol(
DB* db, DB *db, WorkingFiles *working_files, SymbolIdx sym, bool use_detailed,
WorkingFiles* working_files, std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) {
SymbolIdx sym,
bool use_detailed,
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>>* result) {
std::optional<lsSymbolInformation> info = std::optional<lsSymbolInformation> info =
GetSymbolInfo(db, working_files, sym, true); GetSymbolInfo(db, working_files, sym, true);
if (!info) if (!info)
@ -63,7 +60,7 @@ MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result);
struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> { struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_WorkspaceSymbol* request) override { void Run(In_WorkspaceSymbol *request) override {
Out_WorkspaceSymbol out; Out_WorkspaceSymbol out;
out.id = request->id; out.id = request->id;
@ -83,40 +80,41 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
auto Add = [&](SymbolIdx sym) { auto Add = [&](SymbolIdx sym) {
std::string_view detailed_name = db->GetSymbolName(sym, true); std::string_view detailed_name = db->GetSymbolName(sym, true);
int pos = int pos =
ReverseSubseqMatch(query_without_space, detailed_name, sensitive); ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
return pos >= 0 && return pos >= 0 &&
AddSymbol(db, working_files, sym, AddSymbol(db, working_files, sym,
detailed_name.find(':', pos) != std::string::npos, detailed_name.find(':', pos) != std::string::npos,
&cands) && &cands) &&
cands.size() >= g_config->workspaceSymbol.maxNum; cands.size() >= g_config->workspaceSymbol.maxNum;
}; };
for (auto& func : db->funcs) for (auto &func : db->funcs)
if (Add({func.usr, SymbolKind::Func})) if (Add({func.usr, SymbolKind::Func}))
goto done_add; goto done_add;
for (auto& type : db->types) for (auto &type : db->types)
if (Add({type.usr, SymbolKind::Type})) if (Add({type.usr, SymbolKind::Type}))
goto done_add; goto done_add;
for (auto& var : db->vars) for (auto &var : db->vars)
if (var.def.size() && !var.def[0].is_local() && if (var.def.size() && !var.def[0].is_local() &&
Add({var.usr, SymbolKind::Var})) Add({var.usr, SymbolKind::Var}))
goto done_add; goto done_add;
done_add: done_add:
if (g_config->workspaceSymbol.sort && query.size() <= FuzzyMatcher::kMaxPat) { if (g_config->workspaceSymbol.sort &&
query.size() <= FuzzyMatcher::kMaxPat) {
// Sort results with a fuzzy matching algorithm. // Sort results with a fuzzy matching algorithm.
int longest = 0; int longest = 0;
for (auto& cand : cands) for (auto &cand : cands)
longest = std::max( longest = std::max(
longest, int(db->GetSymbolName(std::get<2>(cand), true).size())); longest, int(db->GetSymbolName(std::get<2>(cand), true).size()));
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity); FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
for (auto& cand : cands) for (auto &cand : cands)
std::get<1>(cand) = fuzzy.Match( std::get<1>(cand) = fuzzy.Match(
db->GetSymbolName(std::get<2>(cand), std::get<1>(cand))); db->GetSymbolName(std::get<2>(cand), std::get<1>(cand)));
std::sort(cands.begin(), cands.end(), [](const auto& l, const auto& r) { std::sort(cands.begin(), cands.end(), [](const auto &l, const auto &r) {
return std::get<1>(l) > std::get<1>(r); return std::get<1>(l) > std::get<1>(r);
}); });
out.result.reserve(cands.size()); out.result.reserve(cands.size());
for (auto& cand: cands) { for (auto &cand : cands) {
// Discard awful candidates. // Discard awful candidates.
if (std::get<1>(cand) <= FuzzyMatcher::kMinScore) if (std::get<1>(cand) <= FuzzyMatcher::kMinScore)
break; break;
@ -124,7 +122,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
} }
} else { } else {
out.result.reserve(cands.size()); out.result.reserve(cands.size());
for (auto& cand : cands) for (auto &cand : cands)
out.result.push_back(std::get<0>(cand)); out.result.push_back(std::get<0>(cand));
} }
@ -132,4 +130,4 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);
} // namespace } // namespace

View File

@ -4,12 +4,11 @@ MethodType kMethodType_Unknown = "$unknown";
MethodType kMethodType_Exit = "exit"; MethodType kMethodType_Exit = "exit";
MethodType kMethodType_TextDocumentPublishDiagnostics = MethodType kMethodType_TextDocumentPublishDiagnostics =
"textDocument/publishDiagnostics"; "textDocument/publishDiagnostics";
MethodType kMethodType_CclsPublishSkippedRanges = MethodType kMethodType_CclsPublishSkippedRanges = "$ccls/publishSkippedRanges";
"$ccls/publishSkippedRanges";
MethodType kMethodType_CclsPublishSemanticHighlighting = MethodType kMethodType_CclsPublishSemanticHighlighting =
"$ccls/publishSemanticHighlighting"; "$ccls/publishSemanticHighlighting";
void Reflect(Reader& visitor, lsRequestId& value) { void Reflect(Reader &visitor, lsRequestId &value) {
if (visitor.IsInt64()) { if (visitor.IsInt64()) {
value.type = lsRequestId::kInt; value.type = lsRequestId::kInt;
value.value = int(visitor.GetInt64()); value.value = int(visitor.GetInt64());
@ -25,7 +24,7 @@ void Reflect(Reader& visitor, lsRequestId& value) {
} }
} }
void Reflect(Writer& visitor, lsRequestId& value) { void Reflect(Writer &visitor, lsRequestId &value) {
switch (value.type) { switch (value.type) {
case lsRequestId::kNone: case lsRequestId::kNone:
visitor.Null(); visitor.Null();

View File

@ -5,7 +5,7 @@
#include <string> #include <string>
using MethodType = const char*; using MethodType = const char *;
extern MethodType kMethodType_Unknown; extern MethodType kMethodType_Unknown;
extern MethodType kMethodType_Exit; extern MethodType kMethodType_Exit;
extern MethodType kMethodType_TextDocumentPublishDiagnostics; extern MethodType kMethodType_TextDocumentPublishDiagnostics;
@ -22,8 +22,8 @@ struct lsRequestId {
bool Valid() const { return type != kNone; } bool Valid() const { return type != kNone; }
}; };
void Reflect(Reader& visitor, lsRequestId& value); void Reflect(Reader &visitor, lsRequestId &value);
void Reflect(Writer& visitor, lsRequestId& value); void Reflect(Writer &visitor, lsRequestId &value);
struct InMessage { struct InMessage {
virtual ~InMessage() = default; virtual ~InMessage() = default;
@ -35,14 +35,10 @@ struct InMessage {
struct RequestInMessage : public InMessage { struct RequestInMessage : public InMessage {
// number or string, actually no null // number or string, actually no null
lsRequestId id; lsRequestId id;
lsRequestId GetRequestId() const override { lsRequestId GetRequestId() const override { return id; }
return id;
}
}; };
// NotificationInMessage does not have |id|. // NotificationInMessage does not have |id|.
struct NotificationInMessage : public InMessage { struct NotificationInMessage : public InMessage {
lsRequestId GetRequestId() const override { lsRequestId GetRequestId() const override { return lsRequestId(); }
return lsRequestId();
}
}; };

View File

@ -6,10 +6,10 @@
#include "log.hh" #include "log.hh"
#include "lsp.h" #include "lsp.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "query_utils.h" #include "query_utils.h"
#include "pipeline.hh"
#include <llvm/ADT/Twine.h> #include <llvm/ADT/Twine.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
@ -28,12 +28,12 @@ void DiagnosticsPublisher::Init() {
g_config->diagnostics.blacklist); g_config->diagnostics.blacklist);
} }
void DiagnosticsPublisher::Publish(WorkingFiles* working_files, void DiagnosticsPublisher::Publish(WorkingFiles *working_files,
std::string path, std::string path,
std::vector<lsDiagnostic> diagnostics) { std::vector<lsDiagnostic> diagnostics) {
bool good = true; bool good = true;
// Cache diagnostics so we can show fixits. // Cache diagnostics so we can show fixits.
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) { working_files->DoActionOnFile(path, [&](WorkingFile *working_file) {
if (working_file) { if (working_file) {
good = working_file->diagnostics_.empty(); good = working_file->diagnostics_.empty();
working_file->diagnostics_ = diagnostics; working_file->diagnostics_ = diagnostics;
@ -52,7 +52,8 @@ void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
Out_TextDocumentPublishDiagnostics out; Out_TextDocumentPublishDiagnostics out;
out.params.uri = lsDocumentUri::FromPath(path); out.params.uri = lsDocumentUri::FromPath(path);
out.params.diagnostics = diagnostics; out.params.diagnostics = diagnostics;
ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out); ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics,
out);
} }
} }
@ -71,13 +72,13 @@ struct Stdout_Request {
std::string content; std::string content;
}; };
MultiQueueWaiter* main_waiter; MultiQueueWaiter *main_waiter;
MultiQueueWaiter* indexer_waiter; MultiQueueWaiter *indexer_waiter;
MultiQueueWaiter* stdout_waiter; MultiQueueWaiter *stdout_waiter;
ThreadedQueue<std::unique_ptr<InMessage>>* on_request; ThreadedQueue<std::unique_ptr<InMessage>> *on_request;
ThreadedQueue<Index_Request>* index_request; ThreadedQueue<Index_Request> *index_request;
ThreadedQueue<IndexUpdate>* on_indexed; ThreadedQueue<IndexUpdate> *on_indexed;
ThreadedQueue<Stdout_Request>* for_stdout; ThreadedQueue<Stdout_Request> *for_stdout;
bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path, bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
const std::vector<std::string> &args, const std::vector<std::string> &args,
@ -92,23 +93,24 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
} }
if (prev->args != args) { if (prev->args != args) {
LOG_S(INFO) << "args changed for " << path << (from ? " (via " + *from + ")" : std::string()); LOG_S(INFO) << "args changed for " << path
<< (from ? " (via " + *from + ")" : std::string());
return true; return true;
} }
return false; return false;
}; };
std::string AppendSerializationFormat(const std::string& base) { std::string AppendSerializationFormat(const std::string &base) {
switch (g_config->cacheFormat) { switch (g_config->cacheFormat) {
case SerializeFormat::Binary: case SerializeFormat::Binary:
return base + ".blob"; return base + ".blob";
case SerializeFormat::Json: case SerializeFormat::Json:
return base + ".json"; return base + ".json";
} }
} }
std::string GetCachePath(const std::string& source_file) { std::string GetCachePath(const std::string &source_file) {
std::string cache_file; std::string cache_file;
size_t len = g_config->projectRoot.size(); size_t len = g_config->projectRoot.size();
if (StartsWith(source_file, g_config->projectRoot)) { if (StartsWith(source_file, g_config->projectRoot)) {
@ -122,8 +124,7 @@ std::string GetCachePath(const std::string& source_file) {
return g_config->cacheDirectory + cache_file; return g_config->cacheDirectory + cache_file;
} }
std::unique_ptr<IndexFile> RawCacheLoad( std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
const std::string& path) {
std::string cache_path = GetCachePath(path); std::string cache_path = GetCachePath(path);
std::optional<std::string> file_content = ReadContent(cache_path); std::optional<std::string> file_content = ReadContent(cache_path);
std::optional<std::string> serialized_indexed_content = std::optional<std::string> serialized_indexed_content =
@ -136,14 +137,12 @@ std::unique_ptr<IndexFile> RawCacheLoad(
IndexFile::kMajorVersion); IndexFile::kMajorVersion);
} }
bool Indexer_Parse(DiagnosticsPublisher* diag_pub, bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
WorkingFiles* working_files, Project *project, VFS *vfs) {
Project* project,
VFS* vfs) {
std::optional<Index_Request> opt_request = index_request->TryPopFront(); std::optional<Index_Request> opt_request = index_request->TryPopFront();
if (!opt_request) if (!opt_request)
return false; return false;
auto& request = *opt_request; auto &request = *opt_request;
// Dummy one to trigger refresh semantic highlight. // Dummy one to trigger refresh semantic highlight.
if (request.path.empty()) { if (request.path.empty()) {
@ -183,7 +182,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
reparse = 2; reparse = 2;
int reparseForDep = g_config->index.reparseForDependency; int reparseForDep = g_config->index.reparseForDependency;
if (reparseForDep > 1 || (reparseForDep == 1 && !Project::loaded)) if (reparseForDep > 1 || (reparseForDep == 1 && !Project::loaded))
for (const auto& dep : prev->dependencies) { for (const auto &dep : prev->dependencies) {
if (auto write_time1 = LastWriteTime(dep.first().str())) { if (auto write_time1 = LastWriteTime(dep.first().str())) {
if (dep.second < *write_time1) { if (dep.second < *write_time1) {
reparse = 2; reparse = 2;
@ -210,7 +209,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
} }
std::lock_guard<std::mutex> lock(vfs->mutex); std::lock_guard<std::mutex> lock(vfs->mutex);
VFS::State& state = vfs->state[path_to_index]; VFS::State &state = vfs->state[path_to_index];
if (state.owner == g_thread_id) if (state.owner == g_thread_id)
state.stage = 0; state.stage = 0;
return true; return true;
@ -218,7 +217,8 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
LOG_S(INFO) << "parse " << path_to_index; LOG_S(INFO) << "parse " << path_to_index;
auto indexes = idx::Index(vfs, entry.directory, path_to_index, entry.args, {}); auto indexes =
idx::Index(vfs, entry.directory, path_to_index, entry.args, {});
if (indexes.empty()) { if (indexes.empty()) {
if (g_config->index.enabled && request.id.Valid()) { if (g_config->index.enabled && request.id.Valid()) {
@ -232,7 +232,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
return true; return true;
} }
for (std::unique_ptr<IndexFile>& curr : indexes) { for (std::unique_ptr<IndexFile> &curr : indexes) {
// Only emit diagnostics for non-interactive sessions, which makes it easier // Only emit diagnostics for non-interactive sessions, which makes it easier
// to identify indexing problems. For interactive sessions, diagnostics are // to identify indexing problems. For interactive sessions, diagnostics are
// handled by code completion. // handled by code completion.
@ -260,7 +260,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
vfs->Reset(path); vfs->Reset(path);
if (entry.id >= 0) { if (entry.id >= 0) {
std::lock_guard<std::mutex> lock(project->mutex_); std::lock_guard<std::mutex> lock(project->mutex_);
for (auto& dep : curr->dependencies) for (auto &dep : curr->dependencies)
project->absolute_path_to_entry_index_[dep.first()] = entry.id; project->absolute_path_to_entry_index_[dep.first()] = entry.id;
} }
@ -274,7 +274,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
return true; return true;
} }
} // namespace } // namespace
void Init() { void Init() {
main_waiter = new MultiQueueWaiter; main_waiter = new MultiQueueWaiter;
@ -288,28 +288,25 @@ void Init() {
for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter); for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
} }
void Indexer_Main(DiagnosticsPublisher* diag_pub, void Indexer_Main(DiagnosticsPublisher *diag_pub, VFS *vfs, Project *project,
VFS* vfs, WorkingFiles *working_files) {
Project* project,
WorkingFiles* working_files) {
while (true) while (true)
if (!Indexer_Parse(diag_pub, working_files, project, vfs)) if (!Indexer_Parse(diag_pub, working_files, project, vfs))
indexer_waiter->Wait(index_request); indexer_waiter->Wait(index_request);
} }
void Main_OnIndexed(DB* db, void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
SemanticHighlightSymbolCache* semantic_cache, WorkingFiles *working_files, IndexUpdate *update) {
WorkingFiles* working_files,
IndexUpdate* update) {
if (update->refresh) { if (update->refresh) {
Project::loaded = true; Project::loaded = true;
LOG_S(INFO) << "loaded project. Refresh semantic highlight for all working file."; LOG_S(INFO)
<< "loaded project. Refresh semantic highlight for all working file.";
std::lock_guard<std::mutex> lock(working_files->files_mutex); std::lock_guard<std::mutex> lock(working_files->files_mutex);
for (auto& f : working_files->files) { for (auto &f : working_files->files) {
std::string filename = LowerPathIfInsensitive(f->filename); std::string filename = LowerPathIfInsensitive(f->filename);
if (db->name2file_id.find(filename) == db->name2file_id.end()) if (db->name2file_id.find(filename) == db->name2file_id.end())
continue; continue;
QueryFile* file = &db->files[db->name2file_id[filename]]; QueryFile *file = &db->files[db->name2file_id[filename]];
EmitSemanticHighlighting(db, semantic_cache, f.get(), file); EmitSemanticHighlighting(db, semantic_cache, f.get(), file);
} }
return; return;
@ -322,9 +319,9 @@ void Main_OnIndexed(DB* db,
// Update indexed content, skipped ranges, and semantic highlighting. // Update indexed content, skipped ranges, and semantic highlighting.
if (update->files_def_update) { if (update->files_def_update) {
auto& def_u = *update->files_def_update; auto &def_u = *update->files_def_update;
LOG_S(INFO) << "apply index for " << def_u.first.path; LOG_S(INFO) << "apply index for " << def_u.first.path;
if (WorkingFile* working_file = if (WorkingFile *working_file =
working_files->GetFileByFilename(def_u.first.path)) { working_files->GetFileByFilename(def_u.first.path)) {
working_file->SetIndexContent(def_u.second); working_file->SetIndexContent(def_u.second);
EmitSkippedRanges(working_file, def_u.first.skipped_ranges); EmitSkippedRanges(working_file, def_u.first.skipped_ranges);
@ -369,7 +366,8 @@ void LaunchStdin() {
if (method_type == kMethodType_Exit) if (method_type == kMethodType_Exit)
break; break;
} }
}).detach(); })
.detach();
} }
void LaunchStdout() { void LaunchStdout() {
@ -383,7 +381,7 @@ void LaunchStdout() {
continue; continue;
} }
for (auto& message : messages) { for (auto &message : messages) {
#ifdef _WIN32 #ifdef _WIN32
fwrite(message.content.c_str(), message.content.size(), 1, stdout); fwrite(message.content.c_str(), message.content.size(), 1, stdout);
fflush(stdout); fflush(stdout);
@ -392,7 +390,8 @@ void LaunchStdout() {
#endif #endif
} }
} }
}).detach(); })
.detach();
} }
void MainLoop() { void MainLoop() {
@ -412,9 +411,8 @@ void MainLoop() {
Out_Error out; Out_Error out;
out.id = id; out.id = id;
out.error.code = lsErrorCodes::InternalError; out.error.code = lsErrorCodes::InternalError;
out.error.message = out.error.message = "Dropping completion request; a newer request "
"Dropping completion request; a newer request " "has come in that will be serviced instead.";
"has come in that will be serviced instead.";
pipeline::WriteStdout(kMethodType_Unknown, out); pipeline::WriteStdout(kMethodType_Unknown, out);
} }
}); });
@ -426,7 +424,7 @@ void MainLoop() {
DB db; DB db;
// Setup shared references. // Setup shared references.
for (MessageHandler* handler : *MessageHandler::message_handlers) { for (MessageHandler *handler : *MessageHandler::message_handlers) {
handler->db = &db; handler->db = &db;
handler->waiter = indexer_waiter; handler->waiter = indexer_waiter;
handler->project = &project; handler->project = &project;
@ -445,9 +443,9 @@ void MainLoop() {
while (true) { while (true) {
std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll(); std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll();
bool did_work = messages.size(); bool did_work = messages.size();
for (auto& message : messages) { for (auto &message : messages) {
// TODO: Consider using std::unordered_map to lookup the handler // TODO: Consider using std::unordered_map to lookup the handler
for (MessageHandler* handler : *MessageHandler::message_handlers) { for (MessageHandler *handler : *MessageHandler::message_handlers) {
if (handler->GetMethodType() == message->GetMethodType()) { if (handler->GetMethodType() == message->GetMethodType()) {
handler->Run(std::move(message)); handler->Run(std::move(message));
break; break;
@ -473,18 +471,16 @@ void MainLoop() {
} }
} }
void Index(const std::string& path, void Index(const std::string &path, const std::vector<std::string> &args,
const std::vector<std::string>& args, bool interactive, lsRequestId id) {
bool interactive,
lsRequestId id) {
index_request->PushBack({path, args, interactive, id}, interactive); index_request->PushBack({path, args, interactive, id}, interactive);
} }
std::optional<std::string> LoadCachedFileContents(const std::string& path) { std::optional<std::string> LoadCachedFileContents(const std::string &path) {
return ReadContent(GetCachePath(path)); return ReadContent(GetCachePath(path));
} }
void WriteStdout(MethodType method, lsBaseOutMessage& response) { void WriteStdout(MethodType method, lsBaseOutMessage &response) {
std::ostringstream sstream; std::ostringstream sstream;
response.Write(sstream); response.Write(sstream);
@ -494,4 +490,4 @@ void WriteStdout(MethodType method, lsBaseOutMessage& response) {
for_stdout->PushBack(std::move(out)); for_stdout->PushBack(std::move(out));
} }
} } // namespace ccls::pipeline

View File

@ -4,7 +4,7 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
std::string NormalizePath(const std::string& path); std::string NormalizePath(const std::string &path);
// Free any unused memory and return it to the system. // Free any unused memory and return it to the system.
void FreeUnusedMemory(); void FreeUnusedMemory();
@ -12,5 +12,5 @@ void FreeUnusedMemory();
// Stop self and wait for SIGCONT. // Stop self and wait for SIGCONT.
void TraceMe(); void TraceMe();
std::string GetExternalCommandOutput(const std::vector<std::string>& command, std::string GetExternalCommandOutput(const std::vector<std::string> &command,
std::string_view input); std::string_view input);

View File

@ -14,10 +14,10 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> // required for stat.h #include <sys/types.h> // required for stat.h
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h>
#ifdef __GLIBC__ #ifdef __GLIBC__
#include <malloc.h> #include <malloc.h>
#endif #endif
@ -89,9 +89,9 @@ std::optional<std::string> RealPathNotExpandSymlink(std::string path) {
return resolved; return resolved;
} }
} // namespace } // namespace
std::string NormalizePath(const std::string& path) { std::string NormalizePath(const std::string &path) {
std::optional<std::string> resolved = RealPathNotExpandSymlink(path); std::optional<std::string> resolved = RealPathNotExpandSymlink(path);
return resolved ? *resolved : path; return resolved ? *resolved : path;
} }
@ -106,12 +106,12 @@ void TraceMe() {
// If the environment variable is defined, wait for a debugger. // If the environment variable is defined, wait for a debugger.
// In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue // In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
// after detaching. // after detaching.
const char* traceme = getenv("CCLS_TRACEME"); const char *traceme = getenv("CCLS_TRACEME");
if (traceme) if (traceme)
raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP); raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
} }
std::string GetExternalCommandOutput(const std::vector<std::string>& command, std::string GetExternalCommandOutput(const std::vector<std::string> &command,
std::string_view input) { std::string_view input) {
int pin[2], pout[2]; int pin[2], pout[2];
if (pipe(pin) < 0) { if (pipe(pin) < 0) {
@ -132,9 +132,9 @@ std::string GetExternalCommandOutput(const std::vector<std::string>& command,
close(pin[1]); close(pin[1]);
close(pout[0]); close(pout[0]);
close(pout[1]); close(pout[1]);
auto argv = new char*[command.size() + 1]; auto argv = new char *[command.size() + 1];
for (size_t i = 0; i < command.size(); i++) for (size_t i = 0; i < command.size(); i++)
argv[i] = const_cast<char*>(command[i].c_str()); argv[i] = const_cast<char *>(command[i].c_str());
argv[command.size()] = nullptr; argv[command.size()] = nullptr;
execvp(argv[0], argv); execvp(argv[0], argv);
_Exit(127); _Exit(127);

View File

@ -15,10 +15,10 @@
#include <cassert> #include <cassert>
#include <string> #include <string>
std::string NormalizePath(const std::string& path) { std::string NormalizePath(const std::string &path) {
DWORD retval = 0; DWORD retval = 0;
TCHAR buffer[MAX_PATH] = TEXT(""); TCHAR buffer[MAX_PATH] = TEXT("");
TCHAR** lpp_part = {NULL}; TCHAR **lpp_part = {NULL};
retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part); retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part);
// fail, return original // fail, return original
@ -36,7 +36,7 @@ void FreeUnusedMemory() {}
// TODO Wait for debugger to attach // TODO Wait for debugger to attach
void TraceMe() {} void TraceMe() {}
std::string GetExternalCommandOutput(const std::vector<std::string>& command, std::string GetExternalCommandOutput(const std::vector<std::string> &command,
std::string_view input) { std::string_view input) {
return ""; return "";
} }

View File

@ -6,8 +6,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
Position Position::FromString(const std::string& encoded) { Position Position::FromString(const std::string &encoded) {
char* p = const_cast<char*>(encoded.c_str()); char *p = const_cast<char *>(encoded.c_str());
int16_t line = int16_t(strtol(p, &p, 10)) - 1; int16_t line = int16_t(strtol(p, &p, 10)) - 1;
assert(*p == ':'); assert(*p == ':');
p++; p++;
@ -21,9 +21,9 @@ std::string Position::ToString() {
return buf; return buf;
} }
Range Range::FromString(const std::string& encoded) { Range Range::FromString(const std::string &encoded) {
Position start, end; Position start, end;
char* p = const_cast<char*>(encoded.c_str()); char *p = const_cast<char *>(encoded.c_str());
start.line = int16_t(strtol(p, &p, 10)) - 1; start.line = int16_t(strtol(p, &p, 10)) - 1;
assert(*p == ':'); assert(*p == ':');
p++; p++;
@ -57,7 +57,7 @@ std::string Range::ToString() {
} }
// Position // Position
void Reflect(Reader& visitor, Position& value) { void Reflect(Reader &visitor, Position &value) {
if (visitor.Format() == SerializeFormat::Json) { if (visitor.Format() == SerializeFormat::Json) {
value = Position::FromString(visitor.GetString()); value = Position::FromString(visitor.GetString());
} else { } else {
@ -65,7 +65,7 @@ void Reflect(Reader& visitor, Position& value) {
Reflect(visitor, value.column); Reflect(visitor, value.column);
} }
} }
void Reflect(Writer& visitor, Position& value) { void Reflect(Writer &visitor, Position &value) {
if (visitor.Format() == SerializeFormat::Json) { if (visitor.Format() == SerializeFormat::Json) {
std::string output = value.ToString(); std::string output = value.ToString();
visitor.String(output.c_str(), output.size()); visitor.String(output.c_str(), output.size());
@ -76,7 +76,7 @@ void Reflect(Writer& visitor, Position& value) {
} }
// Range // Range
void Reflect(Reader& visitor, Range& value) { void Reflect(Reader &visitor, Range &value) {
if (visitor.Format() == SerializeFormat::Json) { if (visitor.Format() == SerializeFormat::Json) {
value = Range::FromString(visitor.GetString()); value = Range::FromString(visitor.GetString());
} else { } else {
@ -86,7 +86,7 @@ void Reflect(Reader& visitor, Range& value) {
Reflect(visitor, value.end.column); Reflect(visitor, value.end.column);
} }
} }
void Reflect(Writer& visitor, Range& value) { void Reflect(Writer &visitor, Range &value) {
if (visitor.Format() == SerializeFormat::Json) { if (visitor.Format() == SerializeFormat::Json) {
std::string output = value.ToString(); std::string output = value.ToString();
visitor.String(output.c_str(), output.size()); visitor.String(output.c_str(), output.size());

View File

@ -10,17 +10,17 @@ struct Position {
int16_t line = -1; int16_t line = -1;
int16_t column = -1; int16_t column = -1;
static Position FromString(const std::string& encoded); static Position FromString(const std::string &encoded);
bool Valid() const { return line >= 0; } bool Valid() const { return line >= 0; }
std::string ToString(); std::string ToString();
// Compare two Positions and check if they are equal. Ignores the value of // Compare two Positions and check if they are equal. Ignores the value of
// |interesting|. // |interesting|.
bool operator==(const Position& o) const { bool operator==(const Position &o) const {
return line == o.line && column == o.column; return line == o.line && column == o.column;
} }
bool operator<(const Position& o) const { bool operator<(const Position &o) const {
if (line != o.line) if (line != o.line)
return line < o.line; return line < o.line;
return column < o.column; return column < o.column;
@ -32,7 +32,7 @@ struct Range {
Position start; Position start;
Position end; Position end;
static Range FromString(const std::string& encoded); static Range FromString(const std::string &encoded);
bool Valid() const { return start.Valid(); } bool Valid() const { return start.Valid(); }
bool Contains(int line, int column) const; bool Contains(int line, int column) const;
@ -40,17 +40,16 @@ struct Range {
std::string ToString(); std::string ToString();
bool operator==(const Range& o) const { bool operator==(const Range &o) const {
return start == o.start && end == o.end; return start == o.start && end == o.end;
} }
bool operator<(const Range& o) const { bool operator<(const Range &o) const {
return !(start == o.start) ? start < o.start : end < o.end; return !(start == o.start) ? start < o.start : end < o.end;
} }
}; };
namespace std { namespace std {
template <> template <> struct hash<Range> {
struct hash<Range> {
std::size_t operator()(Range x) const { std::size_t operator()(Range x) const {
union U { union U {
Range range = {}; Range range = {};
@ -61,12 +60,12 @@ struct hash<Range> {
return hash<uint64_t>()(u.u64); return hash<uint64_t>()(u.u64);
} }
}; };
} } // namespace std
// Reflection // Reflection
class Reader; class Reader;
class Writer; class Writer;
void Reflect(Reader& visitor, Position& value); void Reflect(Reader &visitor, Position &value);
void Reflect(Writer& visitor, Position& value); void Reflect(Writer &visitor, Position &value);
void Reflect(Reader& visitor, Range& value); void Reflect(Reader &visitor, Range &value);
void Reflect(Writer& visitor, Range& value); void Reflect(Writer &visitor, Range &value);

View File

@ -5,8 +5,8 @@
#include "language.h" #include "language.h"
#include "log.hh" #include "log.hh"
#include "match.h" #include "match.h"
#include "platform.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.h"
#include "serializers/json.h" #include "serializers/json.h"
#include "utils.h" #include "utils.h"
#include "working_files.h" #include "working_files.h"
@ -67,9 +67,9 @@ enum OptionClass {
Separate, Separate,
}; };
Project::Entry GetCompilationEntryFromCompileCommandEntry( Project::Entry
ProjectConfig* config, GetCompilationEntryFromCompileCommandEntry(ProjectConfig *config,
const CompileCommandsEntry& entry) { const CompileCommandsEntry &entry) {
Project::Entry result; Project::Entry result;
result.filename = entry.file; result.filename = entry.file;
const std::string base_name = sys::path::filename(entry.file); const std::string base_name = sys::path::filename(entry.file);
@ -77,7 +77,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
// Expand %c %cpp %clang // Expand %c %cpp %clang
std::vector<std::string> args; std::vector<std::string> args;
const LanguageId lang = SourceFileLanguage(entry.file); const LanguageId lang = SourceFileLanguage(entry.file);
for (const std::string& arg : entry.args) { for (const std::string &arg : entry.args) {
if (arg.compare(0, 3, "%c ") == 0) { if (arg.compare(0, 3, "%c ") == 0) {
if (lang == LanguageId::C) if (lang == LanguageId::C)
args.push_back(arg.substr(3)); args.push_back(arg.substr(3));
@ -106,21 +106,21 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
auto TargetAndMode = auto TargetAndMode =
driver::ToolChain::getTargetAndModeFromProgramName(args[0]); driver::ToolChain::getTargetAndModeFromProgramName(args[0]);
if (!TargetAndMode.TargetPrefix.empty()) { if (!TargetAndMode.TargetPrefix.empty()) {
const char* arr[] = {"-target", TargetAndMode.TargetPrefix.c_str()}; const char *arr[] = {"-target", TargetAndMode.TargetPrefix.c_str()};
args.insert(args.begin() + 1, std::begin(arr), std::end(arr)); args.insert(args.begin() + 1, std::begin(arr), std::end(arr));
Driver.setTargetAndMode(TargetAndMode); Driver.setTargetAndMode(TargetAndMode);
} }
Driver.setCheckInputsExist(false); Driver.setCheckInputsExist(false);
std::vector<const char*> cargs; std::vector<const char *> cargs;
for (auto& arg : args) for (auto &arg : args)
cargs.push_back(arg.c_str()); cargs.push_back(arg.c_str());
cargs.push_back("-fsyntax-only"); cargs.push_back("-fsyntax-only");
std::unique_ptr<driver::Compilation> C(Driver.BuildCompilation(cargs)); std::unique_ptr<driver::Compilation> C(Driver.BuildCompilation(cargs));
const driver::JobList& Jobs = C->getJobs(); const driver::JobList &Jobs = C->getJobs();
if (Jobs.size() != 1) if (Jobs.size() != 1)
return result; return result;
const driver::ArgStringList& CCArgs = Jobs.begin()->getArguments(); const driver::ArgStringList &CCArgs = Jobs.begin()->getArguments();
auto CI = std::make_unique<CompilerInvocation>(); auto CI = std::make_unique<CompilerInvocation>();
CompilerInvocation::CreateFromArgs(*CI, CCArgs.data(), CompilerInvocation::CreateFromArgs(*CI, CCArgs.data(),
@ -132,16 +132,16 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
for (auto &E : HeaderOpts.UserEntries) { for (auto &E : HeaderOpts.UserEntries) {
std::string path = entry.ResolveIfRelative(E.Path); std::string path = entry.ResolveIfRelative(E.Path);
switch (E.Group) { switch (E.Group) {
default: default:
config->angle_dirs.insert(path); config->angle_dirs.insert(path);
break; break;
case frontend::Quoted: case frontend::Quoted:
config->quote_dirs.insert(path); config->quote_dirs.insert(path);
break; break;
case frontend::Angled: case frontend::Angled:
config->angle_dirs.insert(path); config->angle_dirs.insert(path);
config->quote_dirs.insert(path); config->quote_dirs.insert(path);
break; break;
} }
} }
@ -155,7 +155,8 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
continue; continue;
} }
// if (!sys::fs::exists(HeaderOpts.ResourceDir) && HeaderOpts.UseBuiltinIncludes) // if (!sys::fs::exists(HeaderOpts.ResourceDir) &&
// HeaderOpts.UseBuiltinIncludes)
args.push_back("-resource-dir=" + g_config->clang.resourceDir); args.push_back("-resource-dir=" + g_config->clang.resourceDir);
if (CI->getFileSystemOpts().WorkingDir.empty()) if (CI->getFileSystemOpts().WorkingDir.empty())
args.push_back("-working-directory=" + entry.directory); args.push_back("-working-directory=" + entry.directory);
@ -169,17 +170,18 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
return result; return result;
} }
std::vector<std::string> ReadCompilerArgumentsFromFile( std::vector<std::string>
const std::string& path) { ReadCompilerArgumentsFromFile(const std::string &path) {
auto MBOrErr = MemoryBuffer::getFile(path); auto MBOrErr = MemoryBuffer::getFile(path);
if (!MBOrErr) return {}; if (!MBOrErr)
return {};
std::vector<std::string> args; std::vector<std::string> args;
for (line_iterator I(*MBOrErr.get(), true, '#'), E; I != E; ++I) for (line_iterator I(*MBOrErr.get(), true, '#'), E; I != E; ++I)
args.push_back(*I); args.push_back(*I);
return args; return args;
} }
std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) { std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig *config) {
std::vector<Project::Entry> result; std::vector<Project::Entry> result;
config->mode = ProjectMode::DotCcls; config->mode = ProjectMode::DotCcls;
SmallString<256> Path; SmallString<256> Path;
@ -194,7 +196,7 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
GetFilesInFolder(config->project_dir, true /*recursive*/, GetFilesInFolder(config->project_dir, true /*recursive*/,
true /*add_folder_to_path*/, true /*add_folder_to_path*/,
[&folder_args, &files](const std::string& path) { [&folder_args, &files](const std::string &path) {
if (SourceFileLanguage(path) != LanguageId::Unknown) { if (SourceFileLanguage(path) != LanguageId::Unknown) {
files.push_back(path); files.push_back(path);
} else if (sys::path::filename(path) == ".ccls") { } else if (sys::path::filename(path) == ".ccls") {
@ -204,12 +206,13 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
} }
}); });
const std::string& project_dir = config->project_dir; const std::string &project_dir = config->project_dir;
const auto& project_dir_args = folder_args[project_dir]; const auto &project_dir_args = folder_args[project_dir];
LOG_IF_S(INFO, !project_dir_args.empty()) LOG_IF_S(INFO, !project_dir_args.empty())
<< "Using .ccls arguments " << StringJoin(project_dir_args); << "Using .ccls arguments " << StringJoin(project_dir_args);
auto GetCompilerArgumentForFile = [&project_dir, &folder_args](std::string cur) { auto GetCompilerArgumentForFile = [&project_dir,
&folder_args](std::string cur) {
while (!(cur = sys::path::parent_path(cur)).empty()) { while (!(cur = sys::path::parent_path(cur)).empty()) {
auto it = folder_args.find(cur); auto it = folder_args.find(cur);
if (it != folder_args.end()) if (it != folder_args.end())
@ -223,13 +226,13 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
return folder_args[project_dir]; return folder_args[project_dir];
}; };
for (const std::string& file : files) { for (const std::string &file : files) {
CompileCommandsEntry e; CompileCommandsEntry e;
e.directory = config->project_dir; e.directory = config->project_dir;
e.file = file; e.file = file;
e.args = GetCompilerArgumentForFile(file); e.args = GetCompilerArgumentForFile(file);
if (e.args.empty()) if (e.args.empty())
e.args.push_back("%clang"); // Add a Dummy. e.args.push_back("%clang"); // Add a Dummy.
e.args.push_back(e.file); e.args.push_back(e.file);
result.push_back(GetCompilationEntryFromCompileCommandEntry(config, e)); result.push_back(GetCompilationEntryFromCompileCommandEntry(config, e));
} }
@ -237,9 +240,9 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
return result; return result;
} }
std::vector<Project::Entry> LoadCompilationEntriesFromDirectory( std::vector<Project::Entry>
ProjectConfig* project, LoadCompilationEntriesFromDirectory(ProjectConfig *project,
const std::string& opt_compilation_db_dir) { const std::string &opt_compilation_db_dir) {
// If there is a .ccls file always load using directory listing. // If there is a .ccls file always load using directory listing.
SmallString<256> Path; SmallString<256> Path;
sys::path::append(Path, project->project_dir, ".ccls"); sys::path::append(Path, project->project_dir, ".ccls");
@ -273,7 +276,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
std::vector<std::string>{g_config->compilationDatabaseCommand, std::vector<std::string>{g_config->compilationDatabaseCommand,
project->project_dir}, project->project_dir},
input.GetString()); input.GetString());
FILE* fout = fopen(Path.c_str(), "wb"); FILE *fout = fopen(Path.c_str(), "wb");
fwrite(contents.c_str(), contents.size(), 1, fout); fwrite(contents.c_str(), contents.size(), 1, fout);
fclose(fout); fclose(fout);
#endif #endif
@ -284,7 +287,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
tooling::CompilationDatabase::loadFromDirectory(comp_db_dir, err_msg); tooling::CompilationDatabase::loadFromDirectory(comp_db_dir, err_msg);
if (!g_config->compilationDatabaseCommand.empty()) { if (!g_config->compilationDatabaseCommand.empty()) {
#ifdef _WIN32 #ifdef _WIN32
// TODO // TODO
#else #else
unlink(Path.c_str()); unlink(Path.c_str());
rmdir(comp_db_dir.c_str()); rmdir(comp_db_dir.c_str());
@ -326,11 +329,11 @@ int ComputeGuessScore(std::string_view a, std::string_view b) {
return score; return score;
} }
} // namespace } // namespace
bool Project::loaded = false; bool Project::loaded = false;
void Project::Load(const std::string& root_directory) { void Project::Load(const std::string &root_directory) {
Project::loaded = false; Project::loaded = false;
// Load data. // Load data.
ProjectConfig project; ProjectConfig project;
@ -344,11 +347,11 @@ void Project::Load(const std::string& root_directory) {
project.quote_dirs.end()); project.quote_dirs.end());
angle_include_directories.assign(project.angle_dirs.begin(), angle_include_directories.assign(project.angle_dirs.begin(),
project.angle_dirs.end()); project.angle_dirs.end());
for (std::string& path : quote_include_directories) { for (std::string &path : quote_include_directories) {
EnsureEndsInSlash(path); EnsureEndsInSlash(path);
LOG_S(INFO) << "quote_include_dir: " << path; LOG_S(INFO) << "quote_include_dir: " << path;
} }
for (std::string& path : angle_include_directories) { for (std::string &path : angle_include_directories) {
EnsureEndsInSlash(path); EnsureEndsInSlash(path);
LOG_S(INFO) << "angle_include_dir: " << path; LOG_S(INFO) << "angle_include_dir: " << path;
} }
@ -362,9 +365,8 @@ void Project::Load(const std::string& root_directory) {
} }
} }
void Project::SetFlagsForFile( void Project::SetFlagsForFile(const std::vector<std::string> &flags,
const std::vector<std::string>& flags, const std::string &path) {
const std::string& path) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto it = absolute_path_to_entry_index_.find(path); auto it = absolute_path_to_entry_index_.find(path);
if (it != absolute_path_to_entry_index_.end()) { if (it != absolute_path_to_entry_index_.end()) {
@ -380,8 +382,8 @@ void Project::SetFlagsForFile(
} }
} }
Project::Entry Project::FindCompilationEntryForFile( Project::Entry
const std::string& filename) { Project::FindCompilationEntryForFile(const std::string &filename) {
{ {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto it = absolute_path_to_entry_index_.find(filename); auto it = absolute_path_to_entry_index_.find(filename);
@ -391,9 +393,9 @@ Project::Entry Project::FindCompilationEntryForFile(
// We couldn't find the file. Try to infer it. // We couldn't find the file. Try to infer it.
// TODO: Cache inferred file in a separate array (using a lock or similar) // TODO: Cache inferred file in a separate array (using a lock or similar)
Entry* best_entry = nullptr; Entry *best_entry = nullptr;
int best_score = std::numeric_limits<int>::min(); int best_score = std::numeric_limits<int>::min();
for (Entry& entry : entries) { for (Entry &entry : entries) {
int score = ComputeGuessScore(filename, entry.filename); int score = ComputeGuessScore(filename, entry.filename);
if (score > best_score) { if (score > best_score) {
best_score = score; best_score = score;
@ -412,8 +414,9 @@ Project::Entry Project::FindCompilationEntryForFile(
// |best_entry| probably has its own path in the arguments. We need to remap // |best_entry| probably has its own path in the arguments. We need to remap
// that path to the new filename. // that path to the new filename.
std::string best_entry_base_name = sys::path::filename(best_entry->filename); std::string best_entry_base_name =
for (std::string& arg : result.args) { sys::path::filename(best_entry->filename);
for (std::string &arg : result.args) {
try { try {
if (arg == best_entry->filename || if (arg == best_entry->filename ||
sys::path::filename(arg) == best_entry_base_name) sys::path::filename(arg) == best_entry_base_name)
@ -427,10 +430,10 @@ Project::Entry Project::FindCompilationEntryForFile(
} }
void Project::ForAllFilteredFiles( void Project::ForAllFilteredFiles(
std::function<void(int i, const Entry& entry)> action) { std::function<void(int i, const Entry &entry)> action) {
GroupMatch matcher(g_config->index.whitelist, g_config->index.blacklist); GroupMatch matcher(g_config->index.whitelist, g_config->index.blacklist);
for (int i = 0; i < entries.size(); ++i) { for (int i = 0; i < entries.size(); ++i) {
const Project::Entry& entry = entries[i]; const Project::Entry &entry = entries[i];
std::string failure_reason; std::string failure_reason;
if (matcher.IsMatch(entry.filename, &failure_reason)) if (matcher.IsMatch(entry.filename, &failure_reason))
action(i, entries[i]); action(i, entries[i]);
@ -441,9 +444,8 @@ void Project::ForAllFilteredFiles(
} }
} }
void Project::Index(WorkingFiles* wfiles, void Project::Index(WorkingFiles *wfiles, lsRequestId id) {
lsRequestId id) { ForAllFilteredFiles([&](int i, const Project::Entry &entry) {
ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr; bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
pipeline::Index(entry.filename, entry.args, is_interactive, id); pipeline::Index(entry.filename, entry.args, is_interactive, id);
}); });

View File

@ -40,24 +40,23 @@ struct Project {
// will affect flags in their subtrees (relative paths are relative to the // will affect flags in their subtrees (relative paths are relative to the
// project root, not subdirectories). For compile_commands.json, its entries // project root, not subdirectories). For compile_commands.json, its entries
// are indexed. // are indexed.
void Load(const std::string& root_directory); void Load(const std::string &root_directory);
// Lookup the CompilationEntry for |filename|. If no entry was found this // Lookup the CompilationEntry for |filename|. If no entry was found this
// will infer one based on existing project structure. // will infer one based on existing project structure.
Entry FindCompilationEntryForFile(const std::string& filename); Entry FindCompilationEntryForFile(const std::string &filename);
// If the client has overridden the flags, or specified them for a file // If the client has overridden the flags, or specified them for a file
// that is not in the compilation_database.json make sure those changes // that is not in the compilation_database.json make sure those changes
// are permanent. // are permanent.
void SetFlagsForFile( void SetFlagsForFile(const std::vector<std::string> &flags,
const std::vector<std::string>& flags, const std::string &path);
const std::string& path);
// Run |action| on every file in the project. // Run |action| on every file in the project.
void ForAllFilteredFiles( void
std::function<void(int i, const Entry& entry)> action); ForAllFilteredFiles(std::function<void(int i, const Entry &entry)> action);
void Index(WorkingFiles* wfiles, lsRequestId id); void Index(WorkingFiles *wfiles, lsRequestId id);
static bool loaded; static bool loaded;
}; };

View File

@ -19,7 +19,7 @@ void AssignFileId(const Lid2file_id &, int file_id, SymbolRef &ref) {
ref.usr = file_id; ref.usr = file_id;
} }
void AssignFileId(const Lid2file_id& lid2file_id, int file_id, Use& use) { void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Use &use) {
if (use.kind == SymbolKind::File) if (use.kind == SymbolKind::File)
use.usr = file_id; use.usr = file_id;
if (use.file_id == -1) if (use.file_id == -1)
@ -44,35 +44,35 @@ void AssignFileId(const Lid2file_id &lid2file_id, int file_id,
AssignFileId(lid2file_id, file_id, x); AssignFileId(lid2file_id, file_id, x);
} }
void AddRange(std::vector<Use>& into, const std::vector<Use>& from) { void AddRange(std::vector<Use> &into, const std::vector<Use> &from) {
into.reserve(into.size() + from.size()); into.reserve(into.size() + from.size());
for (Use use : from) for (Use use : from)
into.push_back(use); into.push_back(use);
} }
void AddRange(std::vector<Usr>& into, const std::vector<Usr>& from) { void AddRange(std::vector<Usr> &into, const std::vector<Usr> &from) {
into.insert(into.end(), from.begin(), from.end()); into.insert(into.end(), from.begin(), from.end());
} }
template <typename T> template <typename T>
void RemoveRange(std::vector<T>& from, const std::vector<T>& to_remove) { void RemoveRange(std::vector<T> &from, const std::vector<T> &to_remove) {
if (to_remove.size()) { if (to_remove.size()) {
std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end()); std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
from.erase( from.erase(
std::remove_if(from.begin(), from.end(), std::remove_if(from.begin(), from.end(),
[&](const T& t) { return to_remove_set.count(t) > 0; }), [&](const T &t) { return to_remove_set.count(t) > 0; }),
from.end()); from.end());
} }
} }
QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) { QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile &indexed) {
QueryFile::Def def; QueryFile::Def def;
def.path = std::move(indexed.path); def.path = std::move(indexed.path);
def.args = std::move(indexed.args); def.args = std::move(indexed.args);
def.includes = std::move(indexed.includes); def.includes = std::move(indexed.includes);
def.skipped_ranges = std::move(indexed.skipped_ranges); def.skipped_ranges = std::move(indexed.skipped_ranges);
def.dependencies.reserve(indexed.dependencies.size()); def.dependencies.reserve(indexed.dependencies.size());
for (auto& dep : indexed.dependencies) for (auto &dep : indexed.dependencies)
def.dependencies.push_back(dep.first()); def.dependencies.push_back(dep.first());
def.language = indexed.language; def.language = indexed.language;
@ -83,8 +83,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
def.outline.push_back(SymbolRef{{use.range, usr, kind, use.role}}); def.outline.push_back(SymbolRef{{use.range, usr, kind, use.role}});
}; };
for (auto& it : indexed.usr2type) { for (auto &it : indexed.usr2type) {
const IndexType& type = it.second; const IndexType &type = it.second;
if (type.def.spell) if (type.def.spell)
add_all_symbols(*type.def.spell, type.usr, SymbolKind::Type); add_all_symbols(*type.def.spell, type.usr, SymbolKind::Type);
if (type.def.extent) if (type.def.extent)
@ -100,8 +100,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
if (use.file_id == -1) if (use.file_id == -1)
add_all_symbols(use, type.usr, SymbolKind::Type); add_all_symbols(use, type.usr, SymbolKind::Type);
} }
for (auto& it: indexed.usr2func) { for (auto &it : indexed.usr2func) {
const IndexFunc& func = it.second; const IndexFunc &func = it.second;
if (func.def.spell) if (func.def.spell)
add_all_symbols(*func.def.spell, func.usr, SymbolKind::Func); add_all_symbols(*func.def.spell, func.usr, SymbolKind::Func);
if (func.def.extent) if (func.def.extent)
@ -124,8 +124,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
add_all_symbols(use, func.usr, SymbolKind::Func); add_all_symbols(use, func.usr, SymbolKind::Func);
} }
} }
for (auto& it : indexed.usr2var) { for (auto &it : indexed.usr2var) {
const IndexVar& var = it.second; const IndexVar &var = it.second;
if (var.def.spell) if (var.def.spell)
add_all_symbols(*var.def.spell, var.usr, SymbolKind::Var); add_all_symbols(*var.def.spell, var.usr, SymbolKind::Var);
if (var.def.extent) if (var.def.extent)
@ -140,11 +140,11 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
} }
std::sort(def.outline.begin(), def.outline.end(), std::sort(def.outline.begin(), def.outline.end(),
[](const SymbolRef& a, const SymbolRef& b) { [](const SymbolRef &a, const SymbolRef &b) {
return a.range.start < b.range.start; return a.range.start < b.range.start;
}); });
std::sort(def.all_symbols.begin(), def.all_symbols.end(), std::sort(def.all_symbols.begin(), def.all_symbols.end(),
[](const SymbolRef& a, const SymbolRef& b) { [](const SymbolRef &a, const SymbolRef &b) {
return a.range.start < b.range.start; return a.range.start < b.range.start;
}); });
@ -153,8 +153,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
// Returns true if an element with the same file is found. // Returns true if an element with the same file is found.
template <typename Q> template <typename Q>
bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) { bool TryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
for (auto& def1 : def_list) for (auto &def1 : def_list)
if (def1.file_id == def.file_id) { if (def1.file_id == def.file_id) {
def1 = std::move(def); def1 = std::move(def);
return true; return true;
@ -162,10 +162,9 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) {
return false; return false;
} }
} // namespace } // namespace
IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
IndexFile* current) {
IndexUpdate r; IndexUpdate r;
static IndexFile empty(llvm::sys::fs::UniqueID(0, 0), current->path, static IndexFile empty(llvm::sys::fs::UniqueID(0, 0), current->path,
"<empty>"); "<empty>");
@ -177,16 +176,16 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
r.files_def_update = BuildFileDefUpdate(std::move(*current)); r.files_def_update = BuildFileDefUpdate(std::move(*current));
r.funcs_hint = current->usr2func.size() - previous->usr2func.size(); r.funcs_hint = current->usr2func.size() - previous->usr2func.size();
for (auto& it : previous->usr2func) { for (auto &it : previous->usr2func) {
auto& func = it.second; auto &func = it.second;
if (func.def.detailed_name[0]) if (func.def.detailed_name[0])
r.funcs_removed.push_back(func.usr); r.funcs_removed.push_back(func.usr);
r.funcs_declarations[func.usr].first = std::move(func.declarations); r.funcs_declarations[func.usr].first = std::move(func.declarations);
r.funcs_uses[func.usr].first = std::move(func.uses); r.funcs_uses[func.usr].first = std::move(func.uses);
r.funcs_derived[func.usr].first = std::move(func.derived); r.funcs_derived[func.usr].first = std::move(func.derived);
} }
for (auto& it : current->usr2func) { for (auto &it : current->usr2func) {
auto& func = it.second; auto &func = it.second;
if (func.def.detailed_name[0]) if (func.def.detailed_name[0])
r.funcs_def_update.emplace_back(it.first, func.def); r.funcs_def_update.emplace_back(it.first, func.def);
r.funcs_declarations[func.usr].second = std::move(func.declarations); r.funcs_declarations[func.usr].second = std::move(func.declarations);
@ -195,8 +194,8 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
} }
r.types_hint = current->usr2type.size() - previous->usr2type.size(); r.types_hint = current->usr2type.size() - previous->usr2type.size();
for (auto& it : previous->usr2type) { for (auto &it : previous->usr2type) {
auto& type = it.second; auto &type = it.second;
if (type.def.detailed_name[0]) if (type.def.detailed_name[0])
r.types_removed.push_back(type.usr); r.types_removed.push_back(type.usr);
r.types_declarations[type.usr].first = std::move(type.declarations); r.types_declarations[type.usr].first = std::move(type.declarations);
@ -204,8 +203,8 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
r.types_derived[type.usr].first = std::move(type.derived); r.types_derived[type.usr].first = std::move(type.derived);
r.types_instances[type.usr].first = std::move(type.instances); r.types_instances[type.usr].first = std::move(type.instances);
}; };
for (auto& it : current->usr2type) { for (auto &it : current->usr2type) {
auto& type = it.second; auto &type = it.second;
if (type.def.detailed_name[0]) if (type.def.detailed_name[0])
r.types_def_update.emplace_back(it.first, type.def); r.types_def_update.emplace_back(it.first, type.def);
r.types_declarations[type.usr].second = std::move(type.declarations); r.types_declarations[type.usr].second = std::move(type.declarations);
@ -215,15 +214,15 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
}; };
r.vars_hint = current->usr2var.size() - previous->usr2var.size(); r.vars_hint = current->usr2var.size() - previous->usr2var.size();
for (auto& it : previous->usr2var) { for (auto &it : previous->usr2var) {
auto& var = it.second; auto &var = it.second;
if (var.def.detailed_name[0]) if (var.def.detailed_name[0])
r.vars_removed.push_back(var.usr); r.vars_removed.push_back(var.usr);
r.vars_declarations[var.usr].first = std::move(var.declarations); r.vars_declarations[var.usr].first = std::move(var.declarations);
r.vars_uses[var.usr].first = std::move(var.uses); r.vars_uses[var.usr].first = std::move(var.uses);
} }
for (auto& it : current->usr2var) { for (auto &it : current->usr2var) {
auto& var = it.second; auto &var = it.second;
if (var.def.detailed_name[0]) if (var.def.detailed_name[0])
r.vars_def_update.emplace_back(it.first, var.def); r.vars_def_update.emplace_back(it.first, var.def);
r.vars_declarations[var.usr].second = std::move(var.declarations); r.vars_declarations[var.usr].second = std::move(var.declarations);
@ -233,51 +232,53 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
return r; return r;
} }
void DB::RemoveUsrs(SymbolKind kind, void DB::RemoveUsrs(SymbolKind kind, int file_id,
int file_id, const std::vector<Usr> &to_remove) {
const std::vector<Usr>& to_remove) {
switch (kind) { switch (kind) {
case SymbolKind::Func: { case SymbolKind::Func: {
for (Usr usr : to_remove) { for (Usr usr : to_remove) {
// FIXME // FIXME
if (!HasFunc(usr)) continue; if (!HasFunc(usr))
QueryFunc& func = Func(usr); continue;
auto it = llvm::find_if(func.def, [=](const QueryFunc::Def& def) { QueryFunc &func = Func(usr);
return def.file_id == file_id; auto it = llvm::find_if(func.def, [=](const QueryFunc::Def &def) {
}); return def.file_id == file_id;
if (it != func.def.end()) });
func.def.erase(it); if (it != func.def.end())
} func.def.erase(it);
break;
} }
case SymbolKind::Type: { break;
for (Usr usr : to_remove) { }
// FIXME case SymbolKind::Type: {
if (!HasType(usr)) continue; for (Usr usr : to_remove) {
QueryType& type = Type(usr); // FIXME
auto it = llvm::find_if(type.def, [=](const QueryType::Def& def) { if (!HasType(usr))
return def.file_id == file_id; continue;
}); QueryType &type = Type(usr);
if (it != type.def.end()) auto it = llvm::find_if(type.def, [=](const QueryType::Def &def) {
type.def.erase(it); return def.file_id == file_id;
} });
break; if (it != type.def.end())
type.def.erase(it);
} }
case SymbolKind::Var: { break;
for (Usr usr : to_remove) { }
// FIXME case SymbolKind::Var: {
if (!HasVar(usr)) continue; for (Usr usr : to_remove) {
QueryVar& var = Var(usr); // FIXME
auto it = llvm::find_if(var.def, [=](const QueryVar::Def& def) { if (!HasVar(usr))
return def.file_id == file_id; continue;
}); QueryVar &var = Var(usr);
if (it != var.def.end()) auto it = llvm::find_if(var.def, [=](const QueryVar::Def &def) {
var.def.erase(it); return def.file_id == file_id;
} });
break; if (it != var.def.end())
var.def.erase(it);
} }
default: break;
break; }
default:
break;
} }
} }
@ -295,9 +296,9 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
} }
std::unordered_map<int, int> prev_lid2file_id, lid2file_id; std::unordered_map<int, int> prev_lid2file_id, lid2file_id;
for (auto & [ lid, path ] : u->prev_lid2path) for (auto &[lid, path] : u->prev_lid2path)
prev_lid2file_id[lid] = GetFileId(path); prev_lid2file_id[lid] = GetFileId(path);
for (auto & [ lid, path ] : u->lid2path) for (auto &[lid, path] : u->lid2path)
lid2file_id[lid] = GetFileId(path); lid2file_id[lid] = GetFileId(path);
auto UpdateUses = [&](Usr usr, SymbolKind kind, auto UpdateUses = [&](Usr usr, SymbolKind kind,
@ -347,7 +348,7 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
Update(lid2file_id, u->file_id, std::move(u->funcs_def_update)); Update(lid2file_id, u->file_id, std::move(u->funcs_def_update));
REMOVE_ADD(func, declarations); REMOVE_ADD(func, declarations);
REMOVE_ADD(func, derived); REMOVE_ADD(func, derived);
for (auto & [ usr, p ] : u->funcs_uses) for (auto &[usr, p] : u->funcs_uses)
UpdateUses(usr, SymbolKind::Func, func_usr, funcs, p); UpdateUses(usr, SymbolKind::Func, func_usr, funcs, p);
if ((t = types.size() + u->types_hint) > types.capacity()) { if ((t = types.size() + u->types_hint) > types.capacity()) {
@ -360,7 +361,7 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
REMOVE_ADD(type, declarations); REMOVE_ADD(type, declarations);
REMOVE_ADD(type, derived); REMOVE_ADD(type, derived);
REMOVE_ADD(type, instances); REMOVE_ADD(type, instances);
for (auto & [ usr, p ] : u->types_uses) for (auto &[usr, p] : u->types_uses)
UpdateUses(usr, SymbolKind::Type, type_usr, types, p); UpdateUses(usr, SymbolKind::Type, type_usr, types, p);
if ((t = vars.size() + u->vars_hint) > vars.capacity()) { if ((t = vars.size() + u->vars_hint) > vars.capacity()) {
@ -371,13 +372,13 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed); RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed);
Update(lid2file_id, u->file_id, std::move(u->vars_def_update)); Update(lid2file_id, u->file_id, std::move(u->vars_def_update));
REMOVE_ADD(var, declarations); REMOVE_ADD(var, declarations);
for (auto & [ usr, p ] : u->vars_uses) for (auto &[usr, p] : u->vars_uses)
UpdateUses(usr, SymbolKind::Var, var_usr, vars, p); UpdateUses(usr, SymbolKind::Var, var_usr, vars, p);
#undef REMOVE_ADD #undef REMOVE_ADD
} }
int DB::GetFileId(const std::string& path) { int DB::GetFileId(const std::string &path) {
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(path)); auto it = name2file_id.try_emplace(LowerPathIfInsensitive(path));
if (it.second) { if (it.second) {
int id = files.size(); int id = files.size();
@ -386,7 +387,7 @@ int DB::GetFileId(const std::string& path) {
return it.first->second; return it.first->second;
} }
int DB::Update(QueryFile::DefUpdate&& u) { int DB::Update(QueryFile::DefUpdate &&u) {
int file_id = GetFileId(u.first.path); int file_id = GetFileId(u.first.path);
files[file_id].def = u.first; files[file_id].def = u.first;
return file_id; return file_id;
@ -395,7 +396,7 @@ int DB::Update(QueryFile::DefUpdate&& u) {
void DB::Update(const Lid2file_id &lid2file_id, int file_id, void DB::Update(const Lid2file_id &lid2file_id, int file_id,
std::vector<std::pair<Usr, QueryFunc::Def>> &&us) { std::vector<std::pair<Usr, QueryFunc::Def>> &&us) {
for (auto &u : us) { for (auto &u : us) {
auto& def = u.second; auto &def = u.second;
assert(def.detailed_name[0]); assert(def.detailed_name[0]);
u.second.file_id = file_id; u.second.file_id = file_id;
AssignFileId(lid2file_id, file_id, def.spell); AssignFileId(lid2file_id, file_id, def.spell);
@ -404,7 +405,7 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
auto R = func_usr.try_emplace({u.first}, func_usr.size()); auto R = func_usr.try_emplace({u.first}, func_usr.size());
if (R.second) if (R.second)
funcs.emplace_back(); funcs.emplace_back();
QueryFunc& existing = funcs[R.first->second]; QueryFunc &existing = funcs[R.first->second];
existing.usr = u.first; existing.usr = u.first;
if (!TryReplaceDef(existing.def, std::move(def))) if (!TryReplaceDef(existing.def, std::move(def)))
existing.def.push_back(std::move(def)); existing.def.push_back(std::move(def));
@ -414,7 +415,7 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
void DB::Update(const Lid2file_id &lid2file_id, int file_id, void DB::Update(const Lid2file_id &lid2file_id, int file_id,
std::vector<std::pair<Usr, QueryType::Def>> &&us) { std::vector<std::pair<Usr, QueryType::Def>> &&us) {
for (auto &u : us) { for (auto &u : us) {
auto& def = u.second; auto &def = u.second;
assert(def.detailed_name[0]); assert(def.detailed_name[0]);
u.second.file_id = file_id; u.second.file_id = file_id;
AssignFileId(lid2file_id, file_id, def.spell); AssignFileId(lid2file_id, file_id, def.spell);
@ -422,7 +423,7 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
auto R = type_usr.try_emplace({u.first}, type_usr.size()); auto R = type_usr.try_emplace({u.first}, type_usr.size());
if (R.second) if (R.second)
types.emplace_back(); types.emplace_back();
QueryType& existing = types[R.first->second]; QueryType &existing = types[R.first->second];
existing.usr = u.first; existing.usr = u.first;
if (!TryReplaceDef(existing.def, std::move(def))) if (!TryReplaceDef(existing.def, std::move(def)))
existing.def.push_back(std::move(def)); existing.def.push_back(std::move(def));
@ -432,7 +433,7 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
void DB::Update(const Lid2file_id &lid2file_id, int file_id, void DB::Update(const Lid2file_id &lid2file_id, int file_id,
std::vector<std::pair<Usr, QueryVar::Def>> &&us) { std::vector<std::pair<Usr, QueryVar::Def>> &&us) {
for (auto &u : us) { for (auto &u : us) {
auto& def = u.second; auto &def = u.second;
assert(def.detailed_name[0]); assert(def.detailed_name[0]);
u.second.file_id = file_id; u.second.file_id = file_id;
AssignFileId(lid2file_id, file_id, def.spell); AssignFileId(lid2file_id, file_id, def.spell);
@ -440,7 +441,7 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
auto R = var_usr.try_emplace({u.first}, var_usr.size()); auto R = var_usr.try_emplace({u.first}, var_usr.size());
if (R.second) if (R.second)
vars.emplace_back(); vars.emplace_back();
QueryVar& existing = vars[R.first->second]; QueryVar &existing = vars[R.first->second];
existing.usr = u.first; existing.usr = u.first;
if (!TryReplaceDef(existing.def, std::move(def))) if (!TryReplaceDef(existing.def, std::move(def)))
existing.def.push_back(std::move(def)); existing.def.push_back(std::move(def));
@ -450,24 +451,24 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) { std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) {
Usr usr = sym.usr; Usr usr = sym.usr;
switch (sym.kind) { switch (sym.kind) {
default: default:
break; break;
case SymbolKind::File: case SymbolKind::File:
if (files[usr].def) if (files[usr].def)
return files[usr].def->path; return files[usr].def->path;
break; break;
case SymbolKind::Func: case SymbolKind::Func:
if (const auto* def = Func(usr).AnyDef()) if (const auto *def = Func(usr).AnyDef())
return def->Name(qualified); return def->Name(qualified);
break; break;
case SymbolKind::Type: case SymbolKind::Type:
if (const auto* def = Type(usr).AnyDef()) if (const auto *def = Type(usr).AnyDef())
return def->Name(qualified); return def->Name(qualified);
break; break;
case SymbolKind::Var: case SymbolKind::Var:
if (const auto* def = Var(usr).AnyDef()) if (const auto *def = Var(usr).AnyDef())
return def->Name(qualified); return def->Name(qualified);
break; break;
} }
return ""; return "";
} }

View File

@ -30,19 +30,20 @@ struct QueryFile {
std::unordered_map<SymbolRef, int> symbol2refcnt; std::unordered_map<SymbolRef, int> symbol2refcnt;
}; };
template <typename Q, typename QDef> template <typename Q, typename QDef> struct QueryEntity {
struct QueryEntity {
using Def = QDef; using Def = QDef;
Def* AnyDef() { Def *AnyDef() {
Def* ret = nullptr; Def *ret = nullptr;
for (auto& i : static_cast<Q*>(this)->def) { for (auto &i : static_cast<Q *>(this)->def) {
ret = &i; ret = &i;
if (i.spell) if (i.spell)
break; break;
} }
return ret; return ret;
} }
const Def* AnyDef() const { return const_cast<QueryEntity*>(this)->AnyDef(); } const Def *AnyDef() const {
return const_cast<QueryEntity *>(this)->AnyDef();
}
}; };
using UseUpdate = using UseUpdate =
@ -77,8 +78,7 @@ struct QueryVar : QueryEntity<QueryVar, VarDef> {
struct IndexUpdate { struct IndexUpdate {
// Creates a new IndexUpdate based on the delta from previous to current. If // Creates a new IndexUpdate based on the delta from previous to current. If
// no delta computation should be done just pass null for previous. // no delta computation should be done just pass null for previous.
static IndexUpdate CreateDelta(IndexFile* previous, static IndexUpdate CreateDelta(IndexFile *previous, IndexFile *current);
IndexFile* current);
int file_id; int file_id;
@ -120,8 +120,7 @@ struct IndexUpdate {
struct WrappedUsr { struct WrappedUsr {
Usr usr; Usr usr;
}; };
template <> template <> struct llvm::DenseMapInfo<WrappedUsr> {
struct llvm::DenseMapInfo<WrappedUsr> {
static inline WrappedUsr getEmptyKey() { return {0}; } static inline WrappedUsr getEmptyKey() { return {0}; }
static inline WrappedUsr getTombstoneKey() { return {~0ULL}; } static inline WrappedUsr getTombstoneKey() { return {~0ULL}; }
static unsigned getHashValue(WrappedUsr w) { return w.usr; } static unsigned getHashValue(WrappedUsr w) { return w.usr; }
@ -140,11 +139,12 @@ struct DB {
std::vector<QueryType> types; std::vector<QueryType> types;
std::vector<QueryVar> vars; std::vector<QueryVar> vars;
void RemoveUsrs(SymbolKind kind, int file_id, const std::vector<Usr>& to_remove); void RemoveUsrs(SymbolKind kind, int file_id,
const std::vector<Usr> &to_remove);
// Insert the contents of |update| into |db|. // Insert the contents of |update| into |db|.
void ApplyIndexUpdate(IndexUpdate* update); void ApplyIndexUpdate(IndexUpdate *update);
int GetFileId(const std::string& path); int GetFileId(const std::string &path);
int Update(QueryFile::DefUpdate&& u); int Update(QueryFile::DefUpdate &&u);
void Update(const Lid2file_id &, int file_id, void Update(const Lid2file_id &, int file_id,
std::vector<std::pair<Usr, QueryType::Def>> &&us); std::vector<std::pair<Usr, QueryType::Def>> &&us);
void Update(const Lid2file_id &, int file_id, void Update(const Lid2file_id &, int file_id,
@ -157,12 +157,12 @@ struct DB {
bool HasType(Usr usr) const { return type_usr.count({usr}); } bool HasType(Usr usr) const { return type_usr.count({usr}); }
bool HasVar(Usr usr) const { return var_usr.count({usr}); } bool HasVar(Usr usr) const { return var_usr.count({usr}); }
QueryFunc& Func(Usr usr) { return funcs[func_usr[{usr}]]; } QueryFunc &Func(Usr usr) { return funcs[func_usr[{usr}]]; }
QueryType& Type(Usr usr) { return types[type_usr[{usr}]]; } QueryType &Type(Usr usr) { return types[type_usr[{usr}]]; }
QueryVar& Var(Usr usr) { return vars[var_usr[{usr}]]; } QueryVar &Var(Usr usr) { return vars[var_usr[{usr}]]; }
QueryFile& GetFile(SymbolIdx ref) { return files[ref.usr]; } QueryFile &GetFile(SymbolIdx ref) { return files[ref.usr]; }
QueryFunc& GetFunc(SymbolIdx ref) { return Func(ref.usr); } QueryFunc &GetFunc(SymbolIdx ref) { return Func(ref.usr); }
QueryType& GetType(SymbolIdx ref) { return Type(ref.usr); } QueryType &GetType(SymbolIdx ref) { return Type(ref.usr); }
QueryVar& GetVar(SymbolIdx ref) { return Var(ref.usr); } QueryVar &GetVar(SymbolIdx ref) { return Var(ref.usr); }
}; };

View File

@ -8,22 +8,22 @@
namespace { namespace {
// Computes roughly how long |range| is. // Computes roughly how long |range| is.
int ComputeRangeSize(const Range& range) { int ComputeRangeSize(const Range &range) {
if (range.start.line != range.end.line) if (range.start.line != range.end.line)
return INT_MAX; return INT_MAX;
return range.end.column - range.start.column; return range.end.column - range.start.column;
} }
template <typename Q> template <typename Q>
std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int>& entity_usr, std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int> &entity_usr,
std::vector<Q>& entities, std::vector<Q> &entities,
const std::vector<Usr>& usrs) { const std::vector<Usr> &usrs) {
std::vector<Use> ret; std::vector<Use> ret;
ret.reserve(usrs.size()); ret.reserve(usrs.size());
for (Usr usr : usrs) { for (Usr usr : usrs) {
Q& entity = entities[entity_usr[{usr}]]; Q &entity = entities[entity_usr[{usr}]];
bool has_def = false; bool has_def = false;
for (auto& def : entity.def) for (auto &def : entity.def)
if (def.spell) { if (def.spell) {
ret.push_back(*def.spell); ret.push_back(*def.spell);
has_def = true; has_def = true;
@ -35,39 +35,38 @@ std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int>& entity_usr,
return ret; return ret;
} }
} // namespace } // namespace
Maybe<Use> GetDefinitionSpell(DB* db, SymbolIdx sym) { Maybe<Use> GetDefinitionSpell(DB *db, SymbolIdx sym) {
Maybe<Use> ret; Maybe<Use> ret;
EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); }); EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.spell); });
return ret; return ret;
} }
Maybe<Use> GetDefinitionExtent(DB* db, SymbolIdx sym) { Maybe<Use> GetDefinitionExtent(DB *db, SymbolIdx sym) {
// Used to jump to file. // Used to jump to file.
if (sym.kind == SymbolKind::File) if (sym.kind == SymbolKind::File)
return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None}, return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None},
int(sym.usr)}; int(sym.usr)};
Maybe<Use> ret; Maybe<Use> ret;
EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.extent); }); EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.extent); });
return ret; return ret;
} }
std::vector<Use> GetFuncDeclarations(DB* db, const std::vector<Usr>& usrs) { std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
return GetDeclarations(db->func_usr, db->funcs, usrs); return GetDeclarations(db->func_usr, db->funcs, usrs);
} }
std::vector<Use> GetTypeDeclarations(DB* db, const std::vector<Usr>& usrs) { std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
return GetDeclarations(db->type_usr, db->types, usrs); return GetDeclarations(db->type_usr, db->types, usrs);
} }
std::vector<Use> GetVarDeclarations(DB* db, std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
const std::vector<Usr>& usrs,
unsigned kind) { unsigned kind) {
std::vector<Use> ret; std::vector<Use> ret;
ret.reserve(usrs.size()); ret.reserve(usrs.size());
for (Usr usr : usrs) { for (Usr usr : usrs) {
QueryVar& var = db->Var(usr); QueryVar &var = db->Var(usr);
bool has_def = false; bool has_def = false;
for (auto& def : var.def) for (auto &def : var.def)
if (def.spell) { if (def.spell) {
has_def = true; has_def = true;
// See messages/ccls_vars.cc // See messages/ccls_vars.cc
@ -90,29 +89,29 @@ std::vector<Use> GetVarDeclarations(DB* db,
return ret; return ret;
} }
std::vector<Use> GetNonDefDeclarations(DB* db, SymbolIdx sym) { std::vector<Use> GetNonDefDeclarations(DB *db, SymbolIdx sym) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Func: case SymbolKind::Func:
return db->GetFunc(sym).declarations; return db->GetFunc(sym).declarations;
case SymbolKind::Type: case SymbolKind::Type:
return db->GetType(sym).declarations; return db->GetType(sym).declarations;
case SymbolKind::Var: case SymbolKind::Var:
return db->GetVar(sym).declarations; return db->GetVar(sym).declarations;
default: default:
return {}; return {};
} }
} }
std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root) { std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
std::vector<Use> ret; std::vector<Use> ret;
std::vector<QueryFunc*> stack{&root}; std::vector<QueryFunc *> stack{&root};
std::unordered_set<Usr> seen; std::unordered_set<Usr> seen;
seen.insert(root.usr); seen.insert(root.usr);
while (!stack.empty()) { while (!stack.empty()) {
QueryFunc& func = *stack.back(); QueryFunc &func = *stack.back();
stack.pop_back(); stack.pop_back();
if (auto* def = func.AnyDef()) { if (auto *def = func.AnyDef()) {
EachDefinedFunc(db, def->bases, [&](QueryFunc& func1) { EachDefinedFunc(db, def->bases, [&](QueryFunc &func1) {
if (!seen.count(func1.usr)) { if (!seen.count(func1.usr)) {
seen.insert(func1.usr); seen.insert(func1.usr);
stack.push_back(&func1); stack.push_back(&func1);
@ -125,15 +124,15 @@ std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root) {
return ret; return ret;
} }
std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root) { std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
std::vector<Use> ret; std::vector<Use> ret;
std::vector<QueryFunc*> stack{&root}; std::vector<QueryFunc *> stack{&root};
std::unordered_set<Usr> seen; std::unordered_set<Usr> seen;
seen.insert(root.usr); seen.insert(root.usr);
while (!stack.empty()) { while (!stack.empty()) {
QueryFunc& func = *stack.back(); QueryFunc &func = *stack.back();
stack.pop_back(); stack.pop_back();
EachDefinedFunc(db, func.derived, [&](QueryFunc& func1) { EachDefinedFunc(db, func.derived, [&](QueryFunc &func1) {
if (!seen.count(func1.usr)) { if (!seen.count(func1.usr)) {
seen.insert(func1.usr); seen.insert(func1.usr);
stack.push_back(&func1); stack.push_back(&func1);
@ -145,8 +144,8 @@ std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root) {
return ret; return ret;
} }
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file, std::optional<lsPosition> GetLsPosition(WorkingFile *working_file,
const Position& position) { const Position &position) {
if (!working_file) if (!working_file)
return lsPosition{position.line, position.column}; return lsPosition{position.line, position.column};
@ -157,8 +156,8 @@ std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
return std::nullopt; return std::nullopt;
} }
std::optional<lsRange> GetLsRange(WorkingFile* working_file, std::optional<lsRange> GetLsRange(WorkingFile *working_file,
const Range& location) { const Range &location) {
if (!working_file) { if (!working_file) {
return lsRange{lsPosition{location.start.line, location.start.column}, return lsRange{lsPosition{location.start.line, location.start.column},
lsPosition{location.end.line, location.end.column}}; lsPosition{location.end.line, location.end.column}};
@ -187,8 +186,8 @@ std::optional<lsRange> GetLsRange(WorkingFile* working_file,
lsPosition{*end, end_column}}; lsPosition{*end, end_column}};
} }
lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path) { lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path) {
QueryFile& file = db->files[file_id]; QueryFile &file = db->files[file_id];
if (file.def) { if (file.def) {
*path = file.def->path; *path = file.def->path;
return lsDocumentUri::FromPath(*path); return lsDocumentUri::FromPath(*path);
@ -198,8 +197,8 @@ lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path) {
} }
} }
lsDocumentUri GetLsDocumentUri(DB* db, int file_id) { lsDocumentUri GetLsDocumentUri(DB *db, int file_id) {
QueryFile& file = db->files[file_id]; QueryFile &file = db->files[file_id];
if (file.def) { if (file.def) {
return lsDocumentUri::FromPath(file.def->path); return lsDocumentUri::FromPath(file.def->path);
} else { } else {
@ -207,8 +206,7 @@ lsDocumentUri GetLsDocumentUri(DB* db, int file_id) {
} }
} }
std::optional<lsLocation> GetLsLocation(DB* db, std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
WorkingFiles* working_files,
Use use) { Use use) {
std::string path; std::string path;
lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path); lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
@ -219,10 +217,8 @@ std::optional<lsLocation> GetLsLocation(DB* db,
return lsLocation{uri, *range}; return lsLocation{uri, *range};
} }
std::optional<lsLocationEx> GetLsLocationEx(DB* db, std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
WorkingFiles* working_files, Use use, bool container) {
Use use,
bool container) {
std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use); std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use);
if (!ls_loc) if (!ls_loc)
return std::nullopt; return std::nullopt;
@ -230,7 +226,7 @@ std::optional<lsLocationEx> GetLsLocationEx(DB* db,
ret.lsLocation::operator=(*ls_loc); ret.lsLocation::operator=(*ls_loc);
if (container) { if (container) {
ret.role = uint16_t(use.role); ret.role = uint16_t(use.role);
EachEntityDef(db, use, [&](const auto& def) { EachEntityDef(db, use, [&](const auto &def) {
ret.containerName = std::string_view(def.detailed_name); ret.containerName = std::string_view(def.detailed_name);
return false; return false;
}); });
@ -238,9 +234,8 @@ std::optional<lsLocationEx> GetLsLocationEx(DB* db,
return ret; return ret;
} }
std::vector<lsLocationEx> GetLsLocationExs(DB* db, std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
WorkingFiles* working_files, const std::vector<Use> &uses) {
const std::vector<Use>& uses) {
std::vector<lsLocationEx> ret; std::vector<lsLocationEx> ret;
for (Use use : uses) for (Use use : uses)
if (auto loc = if (auto loc =
@ -253,14 +248,14 @@ std::vector<lsLocationEx> GetLsLocationExs(DB* db,
return ret; return ret;
} }
lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym) { lsSymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
lsSymbolKind ret; lsSymbolKind ret;
if (sym.kind == SymbolKind::File) if (sym.kind == SymbolKind::File)
ret = lsSymbolKind::File; ret = lsSymbolKind::File;
else { else {
ret = lsSymbolKind::Unknown; ret = lsSymbolKind::Unknown;
WithEntity(db, sym, [&](const auto& entity) { WithEntity(db, sym, [&](const auto &entity) {
for (auto& def : entity.def) { for (auto &def : entity.def) {
ret = def.kind; ret = def.kind;
break; break;
} }
@ -270,44 +265,44 @@ lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym) {
} }
// Returns a symbol. The symbol will have *NOT* have a location assigned. // Returns a symbol. The symbol will have *NOT* have a location assigned.
std::optional<lsSymbolInformation> GetSymbolInfo(DB* db, std::optional<lsSymbolInformation> GetSymbolInfo(DB *db,
WorkingFiles* working_files, WorkingFiles *working_files,
SymbolIdx sym, SymbolIdx sym,
bool detailed_name) { bool detailed_name) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Invalid: case SymbolKind::Invalid:
break;
case SymbolKind::File: {
QueryFile &file = db->GetFile(sym);
if (!file.def)
break; break;
case SymbolKind::File: {
QueryFile& file = db->GetFile(sym);
if (!file.def)
break;
lsSymbolInformation info; lsSymbolInformation info;
info.name = file.def->path; info.name = file.def->path;
info.kind = lsSymbolKind::File; info.kind = lsSymbolKind::File;
return info; return info;
} }
default: { default: {
lsSymbolInformation info; lsSymbolInformation info;
EachEntityDef(db, sym, [&](const auto& def) { EachEntityDef(db, sym, [&](const auto &def) {
if (detailed_name) if (detailed_name)
info.name = def.detailed_name; info.name = def.detailed_name;
else else
info.name = def.Name(true); info.name = def.Name(true);
info.kind = def.kind; info.kind = def.kind;
info.containerName = def.detailed_name; info.containerName = def.detailed_name;
return false; return false;
}); });
return info; return info;
} }
} }
return std::nullopt; return std::nullopt;
} }
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file, std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
QueryFile* file, QueryFile *file,
lsPosition& ls_pos) { lsPosition &ls_pos) {
std::vector<SymbolRef> symbols; std::vector<SymbolRef> symbols;
if (working_file) { if (working_file) {
if (auto line = working_file->GetIndexPosFromBufferPos( if (auto line = working_file->GetIndexPosFromBufferPos(
@ -322,7 +317,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
for (SymbolRef sym : file->def->all_symbols) for (SymbolRef sym : file->def->all_symbols)
if (sym.range.Contains(ls_pos.line, ls_pos.character)) if (sym.range.Contains(ls_pos.line, ls_pos.character))
symbols.push_back(sym); symbols.push_back(sym);
for (auto[sym, refcnt] : file->symbol2refcnt) for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character)) if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character))
symbols.push_back(sym); symbols.push_back(sym);
@ -337,22 +332,23 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
// //
// Then order functions before other types, which makes goto definition work // Then order functions before other types, which makes goto definition work
// better on constructors. // better on constructors.
std::sort(symbols.begin(), symbols.end(), std::sort(
[](const SymbolRef& a, const SymbolRef& b) { symbols.begin(), symbols.end(),
int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range); [](const SymbolRef &a, const SymbolRef &b) {
if (t) int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
return t < 0; if (t)
// MacroExpansion return t < 0;
if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic))) // MacroExpansion
return t > 0; if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic)))
if ((t = (a.role & Role::Definition) - (b.role & Role::Definition))) return t > 0;
return t > 0; if ((t = (a.role & Role::Definition) - (b.role & Role::Definition)))
// operator> orders Var/Func before Type. return t > 0;
t = static_cast<int>(a.kind) - static_cast<int>(b.kind); // operator> orders Var/Func before Type.
if (t) t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
return t > 0; if (t)
return a.usr < b.usr; return t > 0;
}); return a.usr < b.usr;
});
return symbols; return symbols;
} }

View File

@ -5,81 +5,75 @@
#include <optional> #include <optional>
Maybe<Use> GetDefinitionSpell(DB* db, SymbolIdx sym); Maybe<Use> GetDefinitionSpell(DB *db, SymbolIdx sym);
Maybe<Use> GetDefinitionExtent(DB* db, SymbolIdx sym); Maybe<Use> GetDefinitionExtent(DB *db, SymbolIdx sym);
// Get defining declaration (if exists) or an arbitrary declaration (otherwise) // Get defining declaration (if exists) or an arbitrary declaration (otherwise)
// for each id. // for each id.
std::vector<Use> GetFuncDeclarations(DB*, const std::vector<Usr>&); std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> GetTypeDeclarations(DB*, const std::vector<Usr>&); std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> GetVarDeclarations(DB*, const std::vector<Usr>&, unsigned); std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
// Get non-defining declarations. // Get non-defining declarations.
std::vector<Use> GetNonDefDeclarations(DB* db, SymbolIdx sym); std::vector<Use> GetNonDefDeclarations(DB *db, SymbolIdx sym);
std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root); std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root);
std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root); std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root);
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file, std::optional<lsPosition> GetLsPosition(WorkingFile *working_file,
const Position& position); const Position &position);
std::optional<lsRange> GetLsRange(WorkingFile* working_file, std::optional<lsRange> GetLsRange(WorkingFile *working_file,
const Range& location); const Range &location);
lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path); lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
lsDocumentUri GetLsDocumentUri(DB* db, int file_id); lsDocumentUri GetLsDocumentUri(DB *db, int file_id);
std::optional<lsLocation> GetLsLocation(DB* db, std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
WorkingFiles* working_files,
Use use); Use use);
std::optional<lsLocationEx> GetLsLocationEx(DB* db, std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
WorkingFiles* working_files, Use use, bool container);
Use use, std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
bool container); const std::vector<Use> &refs);
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
WorkingFiles* working_files,
const std::vector<Use>& refs);
// Returns a symbol. The symbol will have *NOT* have a location assigned. // Returns a symbol. The symbol will have *NOT* have a location assigned.
std::optional<lsSymbolInformation> GetSymbolInfo(DB* db, std::optional<lsSymbolInformation> GetSymbolInfo(DB *db,
WorkingFiles* working_files, WorkingFiles *working_files,
SymbolIdx sym, SymbolIdx sym,
bool detailed_name); bool detailed_name);
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file, std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
QueryFile* file, QueryFile *file,
lsPosition& ls_pos); lsPosition &ls_pos);
template <typename Fn> template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
void WithEntity(DB* db, SymbolIdx sym, Fn&& fn) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Invalid: case SymbolKind::Invalid:
case SymbolKind::File: case SymbolKind::File:
break; break;
case SymbolKind::Func: case SymbolKind::Func:
fn(db->GetFunc(sym)); fn(db->GetFunc(sym));
break; break;
case SymbolKind::Type: case SymbolKind::Type:
fn(db->GetType(sym)); fn(db->GetType(sym));
break; break;
case SymbolKind::Var: case SymbolKind::Var:
fn(db->GetVar(sym)); fn(db->GetVar(sym));
break; break;
} }
} }
template <typename Fn> template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
void EachEntityDef(DB* db, SymbolIdx sym, Fn&& fn) { WithEntity(db, sym, [&](const auto &entity) {
WithEntity(db, sym, [&](const auto& entity) { for (auto &def : entity.def)
for (auto& def : entity.def)
if (!fn(def)) if (!fn(def))
break; break;
}); });
} }
template <typename Fn> template <typename Fn>
void EachOccurrence(DB* db, SymbolIdx sym, bool include_decl, Fn&& fn) { void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
WithEntity(db, sym, [&](const auto& entity) { WithEntity(db, sym, [&](const auto &entity) {
for (Use use : entity.uses) for (Use use : entity.uses)
fn(use); fn(use);
if (include_decl) { if (include_decl) {
for (auto& def : entity.def) for (auto &def : entity.def)
if (def.spell) if (def.spell)
fn(*def.spell); fn(*def.spell);
for (Use use : entity.declarations) for (Use use : entity.declarations)
@ -88,31 +82,30 @@ void EachOccurrence(DB* db, SymbolIdx sym, bool include_decl, Fn&& fn) {
}); });
} }
lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym); lsSymbolKind GetSymbolKind(DB *db, SymbolIdx sym);
template <typename Fn> template <typename Fn>
void EachDefinedFunc(DB* db, const std::vector<Usr>& usrs, Fn&& fn) { void EachDefinedFunc(DB *db, const std::vector<Usr> &usrs, Fn &&fn) {
for (Usr usr : usrs) { for (Usr usr : usrs) {
auto& obj = db->Func(usr); auto &obj = db->Func(usr);
if (!obj.def.empty())
fn(obj);
}
}
template <typename Fn>
void EachDefinedType(DB* db, const std::vector<Usr>& usrs, Fn&& fn) {
for (Usr usr : usrs) {
auto& obj = db->Type(usr);
if (!obj.def.empty()) if (!obj.def.empty())
fn(obj); fn(obj);
} }
} }
template <typename Fn> template <typename Fn>
void EachDefinedVar(DB* db, const std::vector<Usr>& usrs, Fn&& fn) { void EachDefinedType(DB *db, const std::vector<Usr> &usrs, Fn &&fn) {
for (Usr usr : usrs) { for (Usr usr : usrs) {
auto& obj = db->Var(usr); auto &obj = db->Type(usr);
if (!obj.def.empty())
fn(obj);
}
}
template <typename Fn>
void EachDefinedVar(DB *db, const std::vector<Usr> &usrs, Fn &&fn) {
for (Usr usr : usrs) {
auto &obj = db->Var(usr);
if (!obj.def.empty()) if (!obj.def.empty())
fn(obj); fn(obj);
} }

View File

@ -18,143 +18,115 @@ bool gTestOutputMode = false;
//// Elementary types //// Elementary types
void Reflect(Reader& visitor, uint8_t& value) { void Reflect(Reader &visitor, uint8_t &value) { value = visitor.GetUInt8(); }
value = visitor.GetUInt8(); void Reflect(Writer &visitor, uint8_t &value) { visitor.UInt8(value); }
}
void Reflect(Writer& visitor, uint8_t& value) {
visitor.UInt8(value);
}
void Reflect(Reader& visitor, short& value) { void Reflect(Reader &visitor, short &value) {
if (!visitor.IsInt()) if (!visitor.IsInt())
throw std::invalid_argument("short"); throw std::invalid_argument("short");
value = (short)visitor.GetInt(); value = (short)visitor.GetInt();
} }
void Reflect(Writer& visitor, short& value) { void Reflect(Writer &visitor, short &value) { visitor.Int(value); }
visitor.Int(value);
}
void Reflect(Reader& visitor, unsigned short& value) { void Reflect(Reader &visitor, unsigned short &value) {
if (!visitor.IsInt()) if (!visitor.IsInt())
throw std::invalid_argument("unsigned short"); throw std::invalid_argument("unsigned short");
value = (unsigned short)visitor.GetInt(); value = (unsigned short)visitor.GetInt();
} }
void Reflect(Writer& visitor, unsigned short& value) { void Reflect(Writer &visitor, unsigned short &value) { visitor.Int(value); }
visitor.Int(value);
}
void Reflect(Reader& visitor, int& value) { void Reflect(Reader &visitor, int &value) {
if (!visitor.IsInt()) if (!visitor.IsInt())
throw std::invalid_argument("int"); throw std::invalid_argument("int");
value = visitor.GetInt(); value = visitor.GetInt();
} }
void Reflect(Writer& visitor, int& value) { void Reflect(Writer &visitor, int &value) { visitor.Int(value); }
visitor.Int(value);
}
void Reflect(Reader& visitor, unsigned& value) { void Reflect(Reader &visitor, unsigned &value) {
if (!visitor.IsUInt64()) if (!visitor.IsUInt64())
throw std::invalid_argument("unsigned"); throw std::invalid_argument("unsigned");
value = visitor.GetUInt32(); value = visitor.GetUInt32();
} }
void Reflect(Writer& visitor, unsigned& value) { void Reflect(Writer &visitor, unsigned &value) { visitor.UInt32(value); }
visitor.UInt32(value);
}
void Reflect(Reader& visitor, long& value) { void Reflect(Reader &visitor, long &value) {
if (!visitor.IsInt64()) if (!visitor.IsInt64())
throw std::invalid_argument("long"); throw std::invalid_argument("long");
value = long(visitor.GetInt64()); value = long(visitor.GetInt64());
} }
void Reflect(Writer& visitor, long& value) { void Reflect(Writer &visitor, long &value) { visitor.Int64(value); }
visitor.Int64(value);
}
void Reflect(Reader& visitor, unsigned long& value) { void Reflect(Reader &visitor, unsigned long &value) {
if (!visitor.IsUInt64()) if (!visitor.IsUInt64())
throw std::invalid_argument("unsigned long"); throw std::invalid_argument("unsigned long");
value = (unsigned long)visitor.GetUInt64(); value = (unsigned long)visitor.GetUInt64();
} }
void Reflect(Writer& visitor, unsigned long& value) { void Reflect(Writer &visitor, unsigned long &value) { visitor.UInt64(value); }
visitor.UInt64(value);
}
void Reflect(Reader& visitor, long long& value) { void Reflect(Reader &visitor, long long &value) {
if (!visitor.IsInt64()) if (!visitor.IsInt64())
throw std::invalid_argument("long long"); throw std::invalid_argument("long long");
value = visitor.GetInt64(); value = visitor.GetInt64();
} }
void Reflect(Writer& visitor, long long& value) { void Reflect(Writer &visitor, long long &value) { visitor.Int64(value); }
visitor.Int64(value);
}
void Reflect(Reader& visitor, unsigned long long& value) { void Reflect(Reader &visitor, unsigned long long &value) {
if (!visitor.IsUInt64()) if (!visitor.IsUInt64())
throw std::invalid_argument("unsigned long long"); throw std::invalid_argument("unsigned long long");
value = visitor.GetUInt64(); value = visitor.GetUInt64();
} }
void Reflect(Writer& visitor, unsigned long long& value) { void Reflect(Writer &visitor, unsigned long long &value) {
visitor.UInt64(value); visitor.UInt64(value);
} }
void Reflect(Reader& visitor, double& value) { void Reflect(Reader &visitor, double &value) {
if (!visitor.IsDouble()) if (!visitor.IsDouble())
throw std::invalid_argument("double"); throw std::invalid_argument("double");
value = visitor.GetDouble(); value = visitor.GetDouble();
} }
void Reflect(Writer& visitor, double& value) { void Reflect(Writer &visitor, double &value) { visitor.Double(value); }
visitor.Double(value);
}
void Reflect(Reader& visitor, bool& value) { void Reflect(Reader &visitor, bool &value) {
if (!visitor.IsBool()) if (!visitor.IsBool())
throw std::invalid_argument("bool"); throw std::invalid_argument("bool");
value = visitor.GetBool(); value = visitor.GetBool();
} }
void Reflect(Writer& visitor, bool& value) { void Reflect(Writer &visitor, bool &value) { visitor.Bool(value); }
visitor.Bool(value);
}
void Reflect(Reader& visitor, std::string& value) { void Reflect(Reader &visitor, std::string &value) {
if (!visitor.IsString()) if (!visitor.IsString())
throw std::invalid_argument("std::string"); throw std::invalid_argument("std::string");
value = visitor.GetString(); value = visitor.GetString();
} }
void Reflect(Writer& visitor, std::string& value) { void Reflect(Writer &visitor, std::string &value) {
visitor.String(value.c_str(), (rapidjson::SizeType)value.size()); visitor.String(value.c_str(), (rapidjson::SizeType)value.size());
} }
void Reflect(Reader&, std::string_view&) { void Reflect(Reader &, std::string_view &) { assert(0); }
assert(0); void Reflect(Writer &visitor, std::string_view &data) {
}
void Reflect(Writer& visitor, std::string_view& data) {
if (data.empty()) if (data.empty())
visitor.String(""); visitor.String("");
else else
visitor.String(&data[0], (rapidjson::SizeType)data.size()); visitor.String(&data[0], (rapidjson::SizeType)data.size());
} }
void Reflect(Reader& vis, const char*& v) { void Reflect(Reader &vis, const char *&v) {
const char* str = vis.GetString(); const char *str = vis.GetString();
v = ccls::Intern(str); v = ccls::Intern(str);
} }
void Reflect(Writer& vis, const char*& v) { void Reflect(Writer &vis, const char *&v) { vis.String(v); }
vis.String(v);
}
void Reflect(Reader& visitor, JsonNull& value) { void Reflect(Reader &visitor, JsonNull &value) {
assert(visitor.Format() == SerializeFormat::Json); assert(visitor.Format() == SerializeFormat::Json);
visitor.GetNull(); visitor.GetNull();
} }
void Reflect(Writer& visitor, JsonNull& value) { void Reflect(Writer &visitor, JsonNull &value) { visitor.Null(); }
visitor.Null();
}
// std::unordered_map // std::unordered_map
template <typename V> template <typename V>
void Reflect(Reader& visitor, std::unordered_map<Usr, V>& map) { void Reflect(Reader &visitor, std::unordered_map<Usr, V> &map) {
visitor.IterArray([&](Reader& entry) { visitor.IterArray([&](Reader &entry) {
V val; V val;
Reflect(entry, val); Reflect(entry, val);
auto usr = val.usr; auto usr = val.usr;
@ -162,20 +134,20 @@ void Reflect(Reader& visitor, std::unordered_map<Usr, V>& map) {
}); });
} }
template <typename V> template <typename V>
void Reflect(Writer& visitor, std::unordered_map<Usr, V>& map) { void Reflect(Writer &visitor, std::unordered_map<Usr, V> &map) {
std::vector<std::pair<uint64_t, V>> xs(map.begin(), map.end()); std::vector<std::pair<uint64_t, V>> xs(map.begin(), map.end());
std::sort(xs.begin(), xs.end(), std::sort(xs.begin(), xs.end(),
[](const auto& a, const auto& b) { return a.first < b.first; }); [](const auto &a, const auto &b) { return a.first < b.first; });
visitor.StartArray(xs.size()); visitor.StartArray(xs.size());
for (auto& it : xs) for (auto &it : xs)
Reflect(visitor, it.second); Reflect(visitor, it.second);
visitor.EndArray(); visitor.EndArray();
} }
// Used by IndexFile::dependencies. Timestamps are emitted for Binary. // Used by IndexFile::dependencies. Timestamps are emitted for Binary.
void Reflect(Reader& visitor, StringMap<int64_t>& map) { void Reflect(Reader &visitor, StringMap<int64_t> &map) {
visitor.IterArray([&](Reader& entry) { visitor.IterArray([&](Reader &entry) {
std::string name; std::string name;
Reflect(entry, name); Reflect(entry, name);
if (visitor.Format() == SerializeFormat::Binary) if (visitor.Format() == SerializeFormat::Binary)
Reflect(entry, map[name]); Reflect(entry, map[name]);
@ -183,9 +155,9 @@ void Reflect(Reader& visitor, StringMap<int64_t>& map) {
map[name] = 0; map[name] = 0;
}); });
} }
void Reflect(Writer& visitor, StringMap<int64_t>& map) { void Reflect(Writer &visitor, StringMap<int64_t> &map) {
visitor.StartArray(map.size()); visitor.StartArray(map.size());
for (auto& it : map) { for (auto &it : map) {
std::string key = it.first(); std::string key = it.first();
Reflect(visitor, key); Reflect(visitor, key);
if (visitor.Format() == SerializeFormat::Binary) if (visitor.Format() == SerializeFormat::Binary)
@ -195,13 +167,13 @@ void Reflect(Writer& visitor, StringMap<int64_t>& map) {
} }
// TODO: Move this to indexer.cc // TODO: Move this to indexer.cc
void Reflect(Reader& visitor, IndexInclude& value) { void Reflect(Reader &visitor, IndexInclude &value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(line); REFLECT_MEMBER(line);
REFLECT_MEMBER(resolved_path); REFLECT_MEMBER(resolved_path);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
void Reflect(Writer& visitor, IndexInclude& value) { void Reflect(Writer &visitor, IndexInclude &value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(line); REFLECT_MEMBER(line);
if (gTestOutputMode) { if (gTestOutputMode) {
@ -216,13 +188,13 @@ void Reflect(Writer& visitor, IndexInclude& value) {
} }
template <typename Def> template <typename Def>
void ReflectHoverAndComments(Reader& visitor, Def& def) { void ReflectHoverAndComments(Reader &visitor, Def &def) {
ReflectMember(visitor, "hover", def.hover); ReflectMember(visitor, "hover", def.hover);
ReflectMember(visitor, "comments", def.comments); ReflectMember(visitor, "comments", def.comments);
} }
template <typename Def> template <typename Def>
void ReflectHoverAndComments(Writer& visitor, Def& def) { void ReflectHoverAndComments(Writer &visitor, Def &def) {
// Don't emit empty hover and comments in JSON test mode. // Don't emit empty hover and comments in JSON test mode.
if (!gTestOutputMode || def.hover[0]) if (!gTestOutputMode || def.hover[0])
ReflectMember(visitor, "hover", def.hover); ReflectMember(visitor, "hover", def.hover);
@ -230,12 +202,12 @@ void ReflectHoverAndComments(Writer& visitor, Def& def) {
ReflectMember(visitor, "comments", def.comments); ReflectMember(visitor, "comments", def.comments);
} }
template <typename Def> template <typename Def> void ReflectShortName(Reader &visitor, Def &def) {
void ReflectShortName(Reader& visitor, Def& def) {
if (gTestOutputMode) { if (gTestOutputMode) {
std::string short_name; std::string short_name;
ReflectMember(visitor, "short_name", short_name); ReflectMember(visitor, "short_name", short_name);
def.short_name_offset = std::string_view(def.detailed_name).find(short_name); def.short_name_offset =
std::string_view(def.detailed_name).find(short_name);
assert(def.short_name_offset != std::string::npos); assert(def.short_name_offset != std::string::npos);
def.short_name_size = short_name.size(); def.short_name_size = short_name.size();
} else { } else {
@ -244,8 +216,7 @@ void ReflectShortName(Reader& visitor, Def& def) {
} }
} }
template <typename Def> template <typename Def> void ReflectShortName(Writer &visitor, Def &def) {
void ReflectShortName(Writer& visitor, Def& def) {
if (gTestOutputMode) { if (gTestOutputMode) {
std::string_view short_name(def.detailed_name + def.short_name_offset, std::string_view short_name(def.detailed_name + def.short_name_offset,
def.short_name_size); def.short_name_size);
@ -256,8 +227,7 @@ void ReflectShortName(Writer& visitor, Def& def) {
} }
} }
template <typename TVisitor> template <typename TVisitor> void Reflect(TVisitor &visitor, IndexType &value) {
void Reflect(TVisitor& visitor, IndexType& value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER2("usr", value.usr); REFLECT_MEMBER2("usr", value.usr);
REFLECT_MEMBER2("detailed_name", value.def.detailed_name); REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
@ -279,8 +249,7 @@ void Reflect(TVisitor& visitor, IndexType& value) {
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
template <typename TVisitor> template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFunc &value) {
void Reflect(TVisitor& visitor, IndexFunc& value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER2("usr", value.usr); REFLECT_MEMBER2("usr", value.usr);
REFLECT_MEMBER2("detailed_name", value.def.detailed_name); REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
@ -300,8 +269,7 @@ void Reflect(TVisitor& visitor, IndexFunc& value) {
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
template <typename TVisitor> template <typename TVisitor> void Reflect(TVisitor &visitor, IndexVar &value) {
void Reflect(TVisitor& visitor, IndexVar& value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER2("usr", value.usr); REFLECT_MEMBER2("usr", value.usr);
REFLECT_MEMBER2("detailed_name", value.def.detailed_name); REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
@ -319,12 +287,11 @@ void Reflect(TVisitor& visitor, IndexVar& value) {
} }
// IndexFile // IndexFile
bool ReflectMemberStart(Writer& visitor, IndexFile& value) { bool ReflectMemberStart(Writer &visitor, IndexFile &value) {
visitor.StartObject(); visitor.StartObject();
return true; return true;
} }
template <typename TVisitor> template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFile &value) {
void Reflect(TVisitor& visitor, IndexFile& value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
if (!gTestOutputMode) { if (!gTestOutputMode) {
REFLECT_MEMBER(last_write_time); REFLECT_MEMBER(last_write_time);
@ -342,19 +309,19 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
void Reflect(Reader& visitor, SerializeFormat& value) { void Reflect(Reader &visitor, SerializeFormat &value) {
std::string fmt = visitor.GetString(); std::string fmt = visitor.GetString();
value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json; value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json;
} }
void Reflect(Writer& visitor, SerializeFormat& value) { void Reflect(Writer &visitor, SerializeFormat &value) {
switch (value) { switch (value) {
case SerializeFormat::Binary: case SerializeFormat::Binary:
visitor.String("binary"); visitor.String("binary");
break; break;
case SerializeFormat::Json: case SerializeFormat::Json:
visitor.String("json"); visitor.String("json");
break; break;
} }
} }
@ -363,8 +330,9 @@ static BumpPtrAllocator Alloc;
static DenseSet<StringRef> Strings; static DenseSet<StringRef> Strings;
static std::mutex AllocMutex; static std::mutex AllocMutex;
const char* Intern(const std::string& str) { const char *Intern(const std::string &str) {
if (str.empty()) return ""; if (str.empty())
return "";
StringRef Str(str.data(), str.size() + 1); StringRef Str(str.data(), str.size() + 1);
std::lock_guard lock(AllocMutex); std::lock_guard lock(AllocMutex);
auto R = Strings.insert(Str); auto R = Strings.insert(Str);
@ -373,100 +341,98 @@ const char* Intern(const std::string& str) {
return R.first->data(); return R.first->data();
} }
std::string Serialize(SerializeFormat format, IndexFile& file) { std::string Serialize(SerializeFormat format, IndexFile &file) {
switch (format) { switch (format) {
case SerializeFormat::Binary: { case SerializeFormat::Binary: {
BinaryWriter writer; BinaryWriter writer;
int major = IndexFile::kMajorVersion; int major = IndexFile::kMajorVersion;
int minor = IndexFile::kMinorVersion; int minor = IndexFile::kMinorVersion;
Reflect(writer, major); Reflect(writer, major);
Reflect(writer, minor); Reflect(writer, minor);
Reflect(writer, file); Reflect(writer, file);
return writer.Take(); return writer.Take();
} }
case SerializeFormat::Json: { case SerializeFormat::Json: {
rapidjson::StringBuffer output; rapidjson::StringBuffer output;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output); rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
writer.SetFormatOptions( writer.SetFormatOptions(
rapidjson::PrettyFormatOptions::kFormatSingleLineArray); rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
writer.SetIndent(' ', 2); writer.SetIndent(' ', 2);
JsonWriter json_writer(&writer); JsonWriter json_writer(&writer);
if (!gTestOutputMode) { if (!gTestOutputMode) {
std::string version = std::to_string(IndexFile::kMajorVersion); std::string version = std::to_string(IndexFile::kMajorVersion);
for (char c : version) for (char c : version)
output.Put(c); output.Put(c);
output.Put('\n'); output.Put('\n');
}
Reflect(json_writer, file);
return output.GetString();
} }
Reflect(json_writer, file);
return output.GetString();
}
} }
return ""; return "";
} }
std::unique_ptr<IndexFile> Deserialize( std::unique_ptr<IndexFile>
SerializeFormat format, Deserialize(SerializeFormat format, const std::string &path,
const std::string& path, const std::string &serialized_index_content,
const std::string& serialized_index_content, const std::string &file_content,
const std::string& file_content, std::optional<int> expected_version) {
std::optional<int> expected_version) {
if (serialized_index_content.empty()) if (serialized_index_content.empty())
return nullptr; return nullptr;
std::unique_ptr<IndexFile> file; std::unique_ptr<IndexFile> file;
switch (format) { switch (format) {
case SerializeFormat::Binary: { case SerializeFormat::Binary: {
try { try {
int major, minor; int major, minor;
if (serialized_index_content.size() < 8) if (serialized_index_content.size() < 8)
throw std::invalid_argument("Invalid"); throw std::invalid_argument("Invalid");
BinaryReader reader(serialized_index_content); BinaryReader reader(serialized_index_content);
Reflect(reader, major); Reflect(reader, major);
Reflect(reader, minor); Reflect(reader, minor);
if (major != IndexFile::kMajorVersion || if (major != IndexFile::kMajorVersion ||
minor != IndexFile::kMinorVersion) minor != IndexFile::kMinorVersion)
throw std::invalid_argument("Invalid version"); throw std::invalid_argument("Invalid version");
file = std::make_unique<IndexFile>(sys::fs::UniqueID(0, 0), path,
file_content);
Reflect(reader, *file);
} catch (std::invalid_argument& e) {
LOG_S(INFO) << "failed to deserialize '" << path
<< "': " << e.what();
return nullptr;
}
break;
}
case SerializeFormat::Json: {
rapidjson::Document reader;
if (gTestOutputMode || !expected_version) {
reader.Parse(serialized_index_content.c_str());
} else {
const char* p = strchr(serialized_index_content.c_str(), '\n');
if (!p)
return nullptr;
if (atoi(serialized_index_content.c_str()) != *expected_version)
return nullptr;
reader.Parse(p + 1);
}
if (reader.HasParseError())
return nullptr;
file = std::make_unique<IndexFile>(sys::fs::UniqueID(0, 0), path, file = std::make_unique<IndexFile>(sys::fs::UniqueID(0, 0), path,
file_content); file_content);
JsonReader json_reader{&reader}; Reflect(reader, *file);
try { } catch (std::invalid_argument &e) {
Reflect(json_reader, *file); LOG_S(INFO) << "failed to deserialize '" << path << "': " << e.what();
} catch (std::invalid_argument& e) { return nullptr;
LOG_S(INFO) << "'" << path << "': failed to deserialize "
<< json_reader.GetPath() << "." << e.what();
return nullptr;
}
break;
} }
break;
}
case SerializeFormat::Json: {
rapidjson::Document reader;
if (gTestOutputMode || !expected_version) {
reader.Parse(serialized_index_content.c_str());
} else {
const char *p = strchr(serialized_index_content.c_str(), '\n');
if (!p)
return nullptr;
if (atoi(serialized_index_content.c_str()) != *expected_version)
return nullptr;
reader.Parse(p + 1);
}
if (reader.HasParseError())
return nullptr;
file = std::make_unique<IndexFile>(sys::fs::UniqueID(0, 0), path,
file_content);
JsonReader json_reader{&reader};
try {
Reflect(json_reader, *file);
} catch (std::invalid_argument &e) {
LOG_S(INFO) << "'" << path << "': failed to deserialize "
<< json_reader.GetPath() << "." << e.what();
return nullptr;
}
break;
}
} }
// Restore non-serialized state. // Restore non-serialized state.
file->path = path; file->path = path;
return file; return file;
} }
} } // namespace ccls

View File

@ -21,7 +21,7 @@ struct JsonNull {};
struct mandatory_optional_tag {}; struct mandatory_optional_tag {};
class Reader { class Reader {
public: public:
virtual ~Reader() {} virtual ~Reader() {}
virtual SerializeFormat Format() const = 0; virtual SerializeFormat Format() const = 0;
@ -41,17 +41,17 @@ class Reader {
virtual int64_t GetInt64() = 0; virtual int64_t GetInt64() = 0;
virtual uint64_t GetUInt64() = 0; virtual uint64_t GetUInt64() = 0;
virtual double GetDouble() = 0; virtual double GetDouble() = 0;
virtual const char* GetString() = 0; virtual const char *GetString() = 0;
virtual bool HasMember(const char* x) = 0; virtual bool HasMember(const char *x) = 0;
virtual std::unique_ptr<Reader> operator[](const char* x) = 0; virtual std::unique_ptr<Reader> operator[](const char *x) = 0;
virtual void IterArray(std::function<void(Reader&)> fn) = 0; virtual void IterArray(std::function<void(Reader &)> fn) = 0;
virtual void Member(const char* name, std::function<void()> fn) = 0; virtual void Member(const char *name, std::function<void()> fn) = 0;
}; };
class Writer { class Writer {
public: public:
virtual ~Writer() {} virtual ~Writer() {}
virtual SerializeFormat Format() const = 0; virtual SerializeFormat Format() const = 0;
@ -63,13 +63,13 @@ class Writer {
virtual void UInt32(uint32_t x) = 0; virtual void UInt32(uint32_t x) = 0;
virtual void UInt64(uint64_t x) = 0; virtual void UInt64(uint64_t x) = 0;
virtual void Double(double x) = 0; virtual void Double(double x) = 0;
virtual void String(const char* x) = 0; virtual void String(const char *x) = 0;
virtual void String(const char* x, size_t len) = 0; virtual void String(const char *x, size_t len) = 0;
virtual void StartArray(size_t) = 0; virtual void StartArray(size_t) = 0;
virtual void EndArray() = 0; virtual void EndArray() = 0;
virtual void StartObject() = 0; virtual void StartObject() = 0;
virtual void EndObject() = 0; virtual void EndObject() = 0;
virtual void Key(const char* name) = 0; virtual void Key(const char *name) = 0;
}; };
struct IndexFile; struct IndexFile;
@ -77,48 +77,45 @@ struct IndexFile;
#define REFLECT_MEMBER_START() ReflectMemberStart(visitor) #define REFLECT_MEMBER_START() ReflectMemberStart(visitor)
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor); #define REFLECT_MEMBER_END() ReflectMemberEnd(visitor);
#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name) #define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name)
#define REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \ #define REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \
ReflectMember(visitor, #name, value.name, mandatory_optional_tag{}) ReflectMember(visitor, #name, value.name, mandatory_optional_tag{})
#define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value) #define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value)
#define MAKE_REFLECT_TYPE_PROXY(type_name) \ #define MAKE_REFLECT_TYPE_PROXY(type_name) \
MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t<type_name>) MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t<type_name>)
#define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \ #define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \
LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \ LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader &visitor, type &value) { \
as_type value0; \ as_type value0; \
::Reflect(visitor, value0); \ ::Reflect(visitor, value0); \
value = static_cast<type>(value0); \ value = static_cast<type>(value0); \
} \ } \
LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer& visitor, type& value) { \ LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer &visitor, type &value) { \
auto value0 = static_cast<as_type>(value); \ auto value0 = static_cast<as_type>(value); \
::Reflect(visitor, value0); \ ::Reflect(visitor, value0); \
} }
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name); #define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
#define _MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \ #define _MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \
REFLECT_MEMBER_MANDATORY_OPTIONAL(name); REFLECT_MEMBER_MANDATORY_OPTIONAL(name);
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \ #define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
template <typename TVisitor> \ template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
void Reflect(TVisitor& visitor, type& value) { \ REFLECT_MEMBER_START(); \
REFLECT_MEMBER_START(); \ REFLECT_MEMBER_END(); \
REFLECT_MEMBER_END(); \
} }
#define MAKE_REFLECT_STRUCT(type, ...) \ #define MAKE_REFLECT_STRUCT(type, ...) \
template <typename TVisitor> \ template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
void Reflect(TVisitor& visitor, type& value) { \ REFLECT_MEMBER_START(); \
REFLECT_MEMBER_START(); \ MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \ REFLECT_MEMBER_END(); \
REFLECT_MEMBER_END(); \
} }
#define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...) \ #define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...) \
template <typename TVisitor> \ template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
void Reflect(TVisitor& visitor, type& value) { \ REFLECT_MEMBER_START(); \
REFLECT_MEMBER_START(); \ MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__) \
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__) \ REFLECT_MEMBER_END(); \
REFLECT_MEMBER_END(); \
} }
// clang-format off // clang-format off
@ -131,71 +128,70 @@ struct IndexFile;
// Reflects the struct so it is serialized as an array instead of an object. // Reflects the struct so it is serialized as an array instead of an object.
// This currently only supports writers. // This currently only supports writers.
#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \ #define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \
inline void Reflect(Writer& visitor, type& value) { \ inline void Reflect(Writer &visitor, type &value) { \
visitor.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \ visitor.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \
MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \ MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \
visitor.EndArray(); \ visitor.EndArray(); \
} }
//// Elementary types //// Elementary types
void Reflect(Reader& visitor, uint8_t& value); void Reflect(Reader &visitor, uint8_t &value);
void Reflect(Writer& visitor, uint8_t& value); void Reflect(Writer &visitor, uint8_t &value);
void Reflect(Reader& visitor, short& value); void Reflect(Reader &visitor, short &value);
void Reflect(Writer& visitor, short& value); void Reflect(Writer &visitor, short &value);
void Reflect(Reader& visitor, unsigned short& value); void Reflect(Reader &visitor, unsigned short &value);
void Reflect(Writer& visitor, unsigned short& value); void Reflect(Writer &visitor, unsigned short &value);
void Reflect(Reader& visitor, int& value); void Reflect(Reader &visitor, int &value);
void Reflect(Writer& visitor, int& value); void Reflect(Writer &visitor, int &value);
void Reflect(Reader& visitor, unsigned& value); void Reflect(Reader &visitor, unsigned &value);
void Reflect(Writer& visitor, unsigned& value); void Reflect(Writer &visitor, unsigned &value);
void Reflect(Reader& visitor, long& value); void Reflect(Reader &visitor, long &value);
void Reflect(Writer& visitor, long& value); void Reflect(Writer &visitor, long &value);
void Reflect(Reader& visitor, unsigned long& value); void Reflect(Reader &visitor, unsigned long &value);
void Reflect(Writer& visitor, unsigned long& value); void Reflect(Writer &visitor, unsigned long &value);
void Reflect(Reader& visitor, long long& value); void Reflect(Reader &visitor, long long &value);
void Reflect(Writer& visitor, long long& value); void Reflect(Writer &visitor, long long &value);
void Reflect(Reader& visitor, unsigned long long& value); void Reflect(Reader &visitor, unsigned long long &value);
void Reflect(Writer& visitor, unsigned long long& value); void Reflect(Writer &visitor, unsigned long long &value);
void Reflect(Reader& visitor, double& value); void Reflect(Reader &visitor, double &value);
void Reflect(Writer& visitor, double& value); void Reflect(Writer &visitor, double &value);
void Reflect(Reader& visitor, bool& value); void Reflect(Reader &visitor, bool &value);
void Reflect(Writer& visitor, bool& value); void Reflect(Writer &visitor, bool &value);
void Reflect(Reader& visitor, std::string& value); void Reflect(Reader &visitor, std::string &value);
void Reflect(Writer& visitor, std::string& value); void Reflect(Writer &visitor, std::string &value);
void Reflect(Reader& visitor, std::string_view& view); void Reflect(Reader &visitor, std::string_view &view);
void Reflect(Writer& visitor, std::string_view& view); void Reflect(Writer &visitor, std::string_view &view);
void Reflect(Reader& vis, const char*& v); void Reflect(Reader &vis, const char *&v);
void Reflect(Writer& vis, const char*& v); void Reflect(Writer &vis, const char *&v);
void Reflect(Reader& visitor, JsonNull& value); void Reflect(Reader &visitor, JsonNull &value);
void Reflect(Writer& visitor, JsonNull& value); void Reflect(Writer &visitor, JsonNull &value);
void Reflect(Reader& visitor, SerializeFormat& value); void Reflect(Reader &visitor, SerializeFormat &value);
void Reflect(Writer& visitor, SerializeFormat& value); void Reflect(Writer &visitor, SerializeFormat &value);
//// Type constructors //// Type constructors
// ReflectMember std::optional<T> is used to represent TypeScript optional properties // ReflectMember std::optional<T> is used to represent TypeScript optional
// (in `key: value` context). // properties (in `key: value` context). Reflect std::optional<T> is used for a
// Reflect std::optional<T> is used for a different purpose, whether an object is // different purpose, whether an object is nullable (possibly in `value`
// nullable (possibly in `value` context). // context).
template <typename T> template <typename T> void Reflect(Reader &visitor, std::optional<T> &value) {
void Reflect(Reader& visitor, std::optional<T>& value) {
if (visitor.IsNull()) { if (visitor.IsNull()) {
visitor.GetNull(); visitor.GetNull();
return; return;
@ -204,8 +200,7 @@ void Reflect(Reader& visitor, std::optional<T>& value) {
Reflect(visitor, real_value); Reflect(visitor, real_value);
value = std::move(real_value); value = std::move(real_value);
} }
template <typename T> template <typename T> void Reflect(Writer &visitor, std::optional<T> &value) {
void Reflect(Writer& visitor, std::optional<T>& value) {
if (value) { if (value) {
if (visitor.Format() != SerializeFormat::Json) if (visitor.Format() != SerializeFormat::Json)
visitor.UInt8(1); visitor.UInt8(1);
@ -215,8 +210,7 @@ void Reflect(Writer& visitor, std::optional<T>& value) {
} }
// The same as std::optional // The same as std::optional
template <typename T> template <typename T> void Reflect(Reader &visitor, Maybe<T> &value) {
void Reflect(Reader& visitor, Maybe<T>& value) {
if (visitor.IsNull()) { if (visitor.IsNull()) {
visitor.GetNull(); visitor.GetNull();
return; return;
@ -225,8 +219,7 @@ void Reflect(Reader& visitor, Maybe<T>& value) {
Reflect(visitor, real_value); Reflect(visitor, real_value);
value = std::move(real_value); value = std::move(real_value);
} }
template <typename T> template <typename T> void Reflect(Writer &visitor, Maybe<T> &value) {
void Reflect(Writer& visitor, Maybe<T>& value) {
if (value) { if (value) {
if (visitor.Format() != SerializeFormat::Json) if (visitor.Format() != SerializeFormat::Json)
visitor.UInt8(1); visitor.UInt8(1);
@ -236,7 +229,7 @@ void Reflect(Writer& visitor, Maybe<T>& value) {
} }
template <typename T> template <typename T>
void ReflectMember(Writer& visitor, const char* name, std::optional<T>& value) { void ReflectMember(Writer &visitor, const char *name, std::optional<T> &value) {
// For TypeScript std::optional property key?: value in the spec, // For TypeScript std::optional property key?: value in the spec,
// We omit both key and value if value is std::nullopt (null) for JsonWriter // We omit both key and value if value is std::nullopt (null) for JsonWriter
// to reduce output. But keep it for other serialization formats. // to reduce output. But keep it for other serialization formats.
@ -248,7 +241,7 @@ void ReflectMember(Writer& visitor, const char* name, std::optional<T>& value) {
// The same as std::optional // The same as std::optional
template <typename T> template <typename T>
void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) { void ReflectMember(Writer &visitor, const char *name, Maybe<T> &value) {
if (value.Valid() || visitor.Format() != SerializeFormat::Json) { if (value.Valid() || visitor.Format() != SerializeFormat::Json) {
visitor.Key(name); visitor.Key(name);
Reflect(visitor, value); Reflect(visitor, value);
@ -256,21 +249,19 @@ void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) {
} }
template <typename T> template <typename T>
void ReflectMember(Writer& visitor, void ReflectMember(Writer &visitor, const char *name, T &value,
const char* name,
T& value,
mandatory_optional_tag) { mandatory_optional_tag) {
visitor.Key(name); visitor.Key(name);
Reflect(visitor, value); Reflect(visitor, value);
} }
template <typename L, typename R> template <typename L, typename R>
void Reflect(Reader& vis, std::pair<L, R>& v) { void Reflect(Reader &vis, std::pair<L, R> &v) {
vis.Member("L", [&]() { Reflect(vis, v.first); }); vis.Member("L", [&]() { Reflect(vis, v.first); });
vis.Member("R", [&]() { Reflect(vis, v.second); }); vis.Member("R", [&]() { Reflect(vis, v.second); });
} }
template <typename L, typename R> template <typename L, typename R>
void Reflect(Writer& vis, std::pair<L, R>& v) { void Reflect(Writer &vis, std::pair<L, R> &v) {
vis.StartObject(); vis.StartObject();
ReflectMember(vis, "L", v.first); ReflectMember(vis, "L", v.first);
ReflectMember(vis, "R", v.second); ReflectMember(vis, "R", v.second);
@ -278,43 +269,35 @@ void Reflect(Writer& vis, std::pair<L, R>& v) {
} }
// std::vector // std::vector
template <typename T> template <typename T> void Reflect(Reader &visitor, std::vector<T> &values) {
void Reflect(Reader& visitor, std::vector<T>& values) { visitor.IterArray([&](Reader &entry) {
visitor.IterArray([&](Reader& entry) {
T entry_value; T entry_value;
Reflect(entry, entry_value); Reflect(entry, entry_value);
values.push_back(std::move(entry_value)); values.push_back(std::move(entry_value));
}); });
} }
template <typename T> template <typename T> void Reflect(Writer &visitor, std::vector<T> &values) {
void Reflect(Writer& visitor, std::vector<T>& values) {
visitor.StartArray(values.size()); visitor.StartArray(values.size());
for (auto& value : values) for (auto &value : values)
Reflect(visitor, value); Reflect(visitor, value);
visitor.EndArray(); visitor.EndArray();
} }
// ReflectMember // ReflectMember
inline bool ReflectMemberStart(Reader& vis) { inline bool ReflectMemberStart(Reader &vis) { return false; }
return false; inline bool ReflectMemberStart(Writer &vis) {
}
inline bool ReflectMemberStart(Writer& vis) {
vis.StartObject(); vis.StartObject();
return true; return true;
} }
inline void ReflectMemberEnd(Reader& vis) {} inline void ReflectMemberEnd(Reader &vis) {}
inline void ReflectMemberEnd(Writer& vis) { inline void ReflectMemberEnd(Writer &vis) { vis.EndObject(); }
vis.EndObject();
}
template <typename T> template <typename T> void ReflectMember(Reader &vis, const char *name, T &v) {
void ReflectMember(Reader& vis, const char* name, T& v) {
vis.Member(name, [&]() { Reflect(vis, v); }); vis.Member(name, [&]() { Reflect(vis, v); });
} }
template <typename T> template <typename T> void ReflectMember(Writer &vis, const char *name, T &v) {
void ReflectMember(Writer& vis, const char* name, T& v) {
vis.Key(name); vis.Key(name);
Reflect(vis, v); Reflect(vis, v);
} }
@ -322,12 +305,11 @@ void ReflectMember(Writer& vis, const char* name, T& v) {
// API // API
namespace ccls { namespace ccls {
const char* Intern(const std::string& str); const char *Intern(const std::string &str);
std::string Serialize(SerializeFormat format, IndexFile& file); std::string Serialize(SerializeFormat format, IndexFile &file);
std::unique_ptr<IndexFile> Deserialize( std::unique_ptr<IndexFile>
SerializeFormat format, Deserialize(SerializeFormat format, const std::string &path,
const std::string& path, const std::string &serialized_index_content,
const std::string& serialized_index_content, const std::string &file_content,
const std::string& file_content, std::optional<int> expected_version);
std::optional<int> expected_version); } // namespace ccls
}

View File

@ -5,17 +5,16 @@
#include <assert.h> #include <assert.h>
class BinaryReader : public Reader { class BinaryReader : public Reader {
const char* p_; const char *p_;
template <typename T> template <typename T> T Get() {
T Get() { auto ret = *reinterpret_cast<const T *>(p_);
auto ret = *reinterpret_cast<const T*>(p_);
p_ += sizeof(T); p_ += sizeof(T);
return ret; return ret;
} }
uint64_t VarUInt() { uint64_t VarUInt() {
auto x = *reinterpret_cast<const uint8_t*>(p_++); auto x = *reinterpret_cast<const uint8_t *>(p_++);
if (x < 253) if (x < 253)
return x; return x;
if (x == 253) if (x == 253)
@ -29,11 +28,9 @@ class BinaryReader : public Reader {
return int64_t(x >> 1 ^ -(x & 1)); return int64_t(x >> 1 ^ -(x & 1));
} }
public: public:
BinaryReader(std::string_view buf) : p_(buf.data()) {} BinaryReader(std::string_view buf) : p_(buf.data()) {}
SerializeFormat Format() const override { SerializeFormat Format() const override { return SerializeFormat::Binary; }
return SerializeFormat::Binary;
}
bool IsBool() override { return true; } bool IsBool() override { return true; }
// Abuse how the function is called in serializer.h // Abuse how the function is called in serializer.h
@ -52,35 +49,32 @@ class BinaryReader : public Reader {
uint32_t GetUInt32() override { return VarUInt(); } uint32_t GetUInt32() override { return VarUInt(); }
uint64_t GetUInt64() override { return VarUInt(); } uint64_t GetUInt64() override { return VarUInt(); }
double GetDouble() override { return Get<double>(); } double GetDouble() override { return Get<double>(); }
const char* GetString() override { const char *GetString() override {
const char* ret = p_; const char *ret = p_;
while (*p_) while (*p_)
p_++; p_++;
p_++; p_++;
return ret; return ret;
} }
bool HasMember(const char* x) override { return true; } bool HasMember(const char *x) override { return true; }
std::unique_ptr<Reader> operator[](const char* x) override { return {}; } std::unique_ptr<Reader> operator[](const char *x) override { return {}; }
void IterArray(std::function<void(Reader&)> fn) override { void IterArray(std::function<void(Reader &)> fn) override {
for (auto n = VarUInt(); n; n--) for (auto n = VarUInt(); n; n--)
fn(*this); fn(*this);
} }
void Member(const char*, std::function<void()> fn) override { void Member(const char *, std::function<void()> fn) override { fn(); }
fn();
}
}; };
class BinaryWriter : public Writer { class BinaryWriter : public Writer {
std::string buf_; std::string buf_;
template <typename T> template <typename T> void Pack(T x) {
void Pack(T x) {
auto i = buf_.size(); auto i = buf_.size();
buf_.resize(i + sizeof(x)); buf_.resize(i + sizeof(x));
*reinterpret_cast<T*>(buf_.data() + i) = x; *reinterpret_cast<T *>(buf_.data() + i) = x;
} }
void VarUInt(uint64_t n) { void VarUInt(uint64_t n) {
@ -97,14 +91,10 @@ class BinaryWriter : public Writer {
Pack<uint64_t>(n); Pack<uint64_t>(n);
} }
} }
void VarInt(int64_t n) { void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); }
VarUInt(uint64_t(n) << 1 ^ n >> 63);
}
public: public:
SerializeFormat Format() const override { SerializeFormat Format() const override { return SerializeFormat::Binary; }
return SerializeFormat::Binary;
}
std::string Take() { return std::move(buf_); } std::string Take() { return std::move(buf_); }
void Null() override { Pack(uint8_t(0)); } void Null() override { Pack(uint8_t(0)); }
@ -115,8 +105,8 @@ class BinaryWriter : public Writer {
void UInt32(uint32_t x) override { VarUInt(x); } void UInt32(uint32_t x) override { VarUInt(x); }
void UInt64(uint64_t x) override { VarUInt(x); } void UInt64(uint64_t x) override { VarUInt(x); }
void Double(double x) override { Pack(x); } void Double(double x) override { Pack(x); }
void String(const char* x) override { String(x, strlen(x)); } void String(const char *x) override { String(x, strlen(x)); }
void String(const char* x, size_t len) override { void String(const char *x, size_t len) override {
auto i = buf_.size(); auto i = buf_.size();
buf_.resize(i + len + 1); buf_.resize(i + len + 1);
memcpy(buf_.data() + i, x, len); memcpy(buf_.data() + i, x, len);
@ -125,5 +115,5 @@ class BinaryWriter : public Writer {
void EndArray() override {} void EndArray() override {}
void StartObject() override {} void StartObject() override {}
void EndObject() override {} void EndObject() override {}
void Key(const char* name) override {} void Key(const char *name) override {}
}; };

View File

@ -6,11 +6,11 @@
#include <rapidjson/prettywriter.h> #include <rapidjson/prettywriter.h>
class JsonReader : public Reader { class JsonReader : public Reader {
rapidjson::GenericValue<rapidjson::UTF8<>>* m_; rapidjson::GenericValue<rapidjson::UTF8<>> *m_;
std::vector<const char*> path_; std::vector<const char *> path_;
public: public:
JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>>* m) : m_(m) {} JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>> *m) : m_(m) {}
SerializeFormat Format() const override { return SerializeFormat::Json; } SerializeFormat Format() const override { return SerializeFormat::Json; }
bool IsBool() override { return m_->IsBool(); } bool IsBool() override { return m_->IsBool(); }
@ -29,20 +29,20 @@ class JsonReader : public Reader {
uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); } uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); }
uint64_t GetUInt64() override { return m_->GetUint64(); } uint64_t GetUInt64() override { return m_->GetUint64(); }
double GetDouble() override { return m_->GetDouble(); } double GetDouble() override { return m_->GetDouble(); }
const char* GetString() override { return m_->GetString(); } const char *GetString() override { return m_->GetString(); }
bool HasMember(const char* x) override { return m_->HasMember(x); } bool HasMember(const char *x) override { return m_->HasMember(x); }
std::unique_ptr<Reader> operator[](const char* x) override { std::unique_ptr<Reader> operator[](const char *x) override {
auto& sub = (*m_)[x]; auto &sub = (*m_)[x];
return std::unique_ptr<JsonReader>(new JsonReader(&sub)); return std::unique_ptr<JsonReader>(new JsonReader(&sub));
} }
void IterArray(std::function<void(Reader&)> fn) override { void IterArray(std::function<void(Reader &)> fn) override {
if (!m_->IsArray()) if (!m_->IsArray())
throw std::invalid_argument("array"); throw std::invalid_argument("array");
// Use "0" to indicate any element for now. // Use "0" to indicate any element for now.
path_.push_back("0"); path_.push_back("0");
for (auto& entry : m_->GetArray()) { for (auto &entry : m_->GetArray()) {
auto saved = m_; auto saved = m_;
m_ = &entry; m_ = &entry;
fn(*this); fn(*this);
@ -51,7 +51,7 @@ class JsonReader : public Reader {
path_.pop_back(); path_.pop_back();
} }
void Member(const char* name, std::function<void()> fn) override { void Member(const char *name, std::function<void()> fn) override {
path_.push_back(name); path_.push_back(name);
auto it = m_->FindMember(name); auto it = m_->FindMember(name);
if (it != m_->MemberEnd()) { if (it != m_->MemberEnd()) {
@ -65,7 +65,7 @@ class JsonReader : public Reader {
std::string GetPath() const { std::string GetPath() const {
std::string ret; std::string ret;
for (auto& t : path_) { for (auto &t : path_) {
ret += '/'; ret += '/';
ret += t; ret += t;
} }
@ -75,10 +75,10 @@ class JsonReader : public Reader {
}; };
class JsonWriter : public Writer { class JsonWriter : public Writer {
rapidjson::Writer<rapidjson::StringBuffer>* m_; rapidjson::Writer<rapidjson::StringBuffer> *m_;
public: public:
JsonWriter(rapidjson::Writer<rapidjson::StringBuffer>* m) : m_(m) {} JsonWriter(rapidjson::Writer<rapidjson::StringBuffer> *m) : m_(m) {}
SerializeFormat Format() const override { return SerializeFormat::Json; } SerializeFormat Format() const override { return SerializeFormat::Json; }
void Null() override { m_->Null(); } void Null() override { m_->Null(); }
@ -89,11 +89,11 @@ class JsonWriter : public Writer {
void UInt32(uint32_t x) override { m_->Uint64(x); } void UInt32(uint32_t x) override { m_->Uint64(x); }
void UInt64(uint64_t x) override { m_->Uint64(x); } void UInt64(uint64_t x) override { m_->Uint64(x); }
void Double(double x) override { m_->Double(x); } void Double(double x) override { m_->Double(x); }
void String(const char* x) override { m_->String(x); } void String(const char *x) override { m_->String(x); }
void String(const char* x, size_t len) override { m_->String(x, len); } void String(const char *x, size_t len) override { m_->String(x, len); }
void StartArray(size_t) override { m_->StartArray(); } void StartArray(size_t) override { m_->StartArray(); }
void EndArray() override { m_->EndArray(); } void EndArray() override { m_->EndArray(); }
void StartObject() override { m_->StartObject(); } void StartObject() override { m_->StartObject(); }
void EndObject() override { m_->EndObject(); } void EndObject() override { m_->EndObject(); }
void Key(const char* name) override { m_->Key(name); } void Key(const char *name) override { m_->Key(name); }
}; };

View File

@ -13,9 +13,9 @@
#include <rapidjson/stringbuffer.h> #include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h> #include <rapidjson/writer.h>
#include <fstream>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fstream>
// The 'diff' utility is available and we can use dprintf(3). // The 'diff' utility is available and we can use dprintf(3).
#if _POSIX_C_SOURCE >= 200809L #if _POSIX_C_SOURCE >= 200809L
@ -25,7 +25,7 @@
extern bool gTestOutputMode; extern bool gTestOutputMode;
std::string ToString(const rapidjson::Document& document) { std::string ToString(const rapidjson::Document &document) {
rapidjson::StringBuffer buffer; rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
writer.SetFormatOptions( writer.SetFormatOptions(
@ -45,18 +45,18 @@ struct TextReplacer {
std::vector<Replacement> replacements; std::vector<Replacement> replacements;
std::string Apply(const std::string& content) { std::string Apply(const std::string &content) {
std::string result = content; std::string result = content;
for (const Replacement& replacement : replacements) { for (const Replacement &replacement : replacements) {
while (true) { while (true) {
size_t idx = result.find(replacement.from); size_t idx = result.find(replacement.from);
if (idx == std::string::npos) if (idx == std::string::npos)
break; break;
result.replace(result.begin() + idx, result.replace(result.begin() + idx,
result.begin() + idx + replacement.from.size(), result.begin() + idx + replacement.from.size(),
replacement.to); replacement.to);
} }
} }
@ -65,11 +65,10 @@ struct TextReplacer {
}; };
void ParseTestExpectation( void ParseTestExpectation(
const std::string& filename, const std::string &filename,
const std::vector<std::string>& lines_with_endings, const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
TextReplacer* replacer, std::vector<std::string> *flags,
std::vector<std::string>* flags, std::unordered_map<std::string, std::string> *output_sections) {
std::unordered_map<std::string, std::string>* output_sections) {
// Scan for EXTRA_FLAGS: // Scan for EXTRA_FLAGS:
{ {
bool in_output = false; bool in_output = false;
@ -129,9 +128,9 @@ void ParseTestExpectation(
} }
} }
void UpdateTestExpectation(const std::string& filename, void UpdateTestExpectation(const std::string &filename,
const std::string& expectation, const std::string &expectation,
const std::string& actual) { const std::string &actual) {
// Read the entire file into a string. // Read the entire file into a string.
std::ifstream in(filename); std::ifstream in(filename);
std::string str; std::string str;
@ -148,10 +147,8 @@ void UpdateTestExpectation(const std::string& filename,
WriteToFile(filename, str); WriteToFile(filename, str);
} }
void DiffDocuments(std::string path, void DiffDocuments(std::string path, std::string path_section,
std::string path_section, rapidjson::Document &expected, rapidjson::Document &actual) {
rapidjson::Document& expected,
rapidjson::Document& actual) {
std::string joined_actual_output = ToString(actual); std::string joined_actual_output = ToString(actual);
std::string joined_expected_output = ToString(expected); std::string joined_expected_output = ToString(expected);
printf("[FAILED] %s (section %s)\n", path.c_str(), path_section.c_str()); printf("[FAILED] %s (section %s)\n", path.c_str(), path_section.c_str());
@ -190,7 +187,7 @@ void DiffDocuments(std::string path,
path_section.c_str(), joined_actual_output.c_str()); path_section.c_str(), joined_actual_output.c_str());
} }
void VerifySerializeToFrom(IndexFile* file) { void VerifySerializeToFrom(IndexFile *file) {
std::string expected = file->ToString(); std::string expected = file->ToString();
std::string serialized = ccls::Serialize(SerializeFormat::Json, *file); std::string serialized = ccls::Serialize(SerializeFormat::Json, *file);
std::unique_ptr<IndexFile> result = std::unique_ptr<IndexFile> result =
@ -199,14 +196,14 @@ void VerifySerializeToFrom(IndexFile* file) {
std::string actual = result->ToString(); std::string actual = result->ToString();
if (expected != actual) { if (expected != actual) {
fprintf(stderr, "Serialization failure\n"); fprintf(stderr, "Serialization failure\n");
//assert(false); // assert(false);
} }
} }
std::string FindExpectedOutputForFilename( std::string FindExpectedOutputForFilename(
std::string filename, std::string filename,
const std::unordered_map<std::string, std::string>& expected) { const std::unordered_map<std::string, std::string> &expected) {
for (const auto& entry : expected) { for (const auto &entry : expected) {
if (EndsWith(entry.first, filename)) if (EndsWith(entry.first, filename))
return entry.second; return entry.second;
} }
@ -217,17 +214,17 @@ std::string FindExpectedOutputForFilename(
return "{}"; return "{}";
} }
IndexFile* FindDbForPathEnding( IndexFile *
const std::string& path, FindDbForPathEnding(const std::string &path,
const std::vector<std::unique_ptr<IndexFile>>& dbs) { const std::vector<std::unique_ptr<IndexFile>> &dbs) {
for (auto& db : dbs) { for (auto &db : dbs) {
if (EndsWith(db->path, path)) if (EndsWith(db->path, path))
return db.get(); return db.get();
} }
return nullptr; return nullptr;
} }
bool RunIndexTests(const std::string& filter_path, bool enable_update) { bool RunIndexTests(const std::string &filter_path, bool enable_update) {
gTestOutputMode = true; gTestOutputMode = true;
std::string version = LLVM_VERSION_STRING; std::string version = LLVM_VERSION_STRING;
@ -248,7 +245,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
// this can be done by constructing ClangIndex index(1, 1); // this can be done by constructing ClangIndex index(1, 1);
GetFilesInFolder( GetFilesInFolder(
"index_tests", true /*recursive*/, true /*add_folder_to_path*/, "index_tests", true /*recursive*/, true /*add_folder_to_path*/,
[&](const std::string& path) { [&](const std::string &path) {
bool is_fail_allowed = false; bool is_fail_allowed = false;
if (EndsWithAny(path, {".m", ".mm"})) { if (EndsWithAny(path, {".m", ".mm"})) {
@ -291,13 +288,13 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
VFS vfs; VFS vfs;
auto dbs = ccls::idx::Index(&vfs, "", path, flags, {}); auto dbs = ccls::idx::Index(&vfs, "", path, flags, {});
for (const auto& entry : all_expected_output) { for (const auto &entry : all_expected_output) {
const std::string& expected_path = entry.first; const std::string &expected_path = entry.first;
std::string expected_output = text_replacer.Apply(entry.second); std::string expected_output = text_replacer.Apply(entry.second);
// FIXME: promote to utils, find and remove duplicates (ie, // FIXME: promote to utils, find and remove duplicates (ie,
// ccls_call_tree.cc, maybe something in project.cc). // ccls_call_tree.cc, maybe something in project.cc).
auto basename = [](const std::string& path) -> std::string { auto basename = [](const std::string &path) -> std::string {
size_t last_index = path.find_last_of('/'); size_t last_index = path.find_last_of('/');
if (last_index == std::string::npos) if (last_index == std::string::npos)
return path; return path;
@ -305,10 +302,10 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
}; };
// Get output from index operation. // Get output from index operation.
IndexFile* db = FindDbForPathEnding(expected_path, dbs); IndexFile *db = FindDbForPathEnding(expected_path, dbs);
if (db && !db->diagnostics_.empty()) { if (db && !db->diagnostics_.empty()) {
printf("For %s\n", path.c_str()); printf("For %s\n", path.c_str());
for (const lsDiagnostic& diagnostic : db->diagnostics_) { for (const lsDiagnostic &diagnostic : db->diagnostics_) {
printf(" "); printf(" ");
if (diagnostic.severity) if (diagnostic.severity)
switch (*diagnostic.severity) { switch (*diagnostic.severity) {
@ -353,9 +350,8 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
DiffDocuments(path, expected_path, expected, actual); DiffDocuments(path, expected_path, expected, actual);
puts("\n"); puts("\n");
if (enable_update) { if (enable_update) {
printf( printf("[Enter to continue - type u to update test, a to update "
"[Enter to continue - type u to update test, a to update " "all]");
"all]");
char c = 'u'; char c = 'u';
if (!update_all) { if (!update_all) {
c = getchar(); c = getchar();

View File

@ -2,4 +2,4 @@
#include <string> #include <string>
bool RunIndexTests(const std::string& filter_path, bool enable_update); bool RunIndexTests(const std::string &filter_path, bool enable_update);

View File

@ -18,27 +18,21 @@ struct BaseThreadQueue {
// std::lock accepts two or more arguments. We define an overload for one // std::lock accepts two or more arguments. We define an overload for one
// argument. // argument.
namespace std { namespace std {
template <typename Lockable> template <typename Lockable> void lock(Lockable &l) { l.lock(); }
void lock(Lockable& l) { } // namespace std
l.lock();
}
} // namespace std
template <typename... Queue> template <typename... Queue> struct MultiQueueLock {
struct MultiQueueLock {
MultiQueueLock(Queue... lockable) : tuple_{lockable...} { lock(); } MultiQueueLock(Queue... lockable) : tuple_{lockable...} { lock(); }
~MultiQueueLock() { unlock(); } ~MultiQueueLock() { unlock(); }
void lock() { lock_impl(typename std::index_sequence_for<Queue...>{}); } void lock() { lock_impl(typename std::index_sequence_for<Queue...>{}); }
void unlock() { unlock_impl(typename std::index_sequence_for<Queue...>{}); } void unlock() { unlock_impl(typename std::index_sequence_for<Queue...>{}); }
private: private:
template <size_t... Is> template <size_t... Is> void lock_impl(std::index_sequence<Is...>) {
void lock_impl(std::index_sequence<Is...>) {
std::lock(std::get<Is>(tuple_)->mutex_...); std::lock(std::get<Is>(tuple_)->mutex_...);
} }
template <size_t... Is> template <size_t... Is> void unlock_impl(std::index_sequence<Is...>) {
void unlock_impl(std::index_sequence<Is...>) {
(void)std::initializer_list<int>{ (void)std::initializer_list<int>{
(std::get<Is>(tuple_)->mutex_.unlock(), 0)...}; (std::get<Is>(tuple_)->mutex_.unlock(), 0)...};
} }
@ -49,16 +43,15 @@ struct MultiQueueLock {
struct MultiQueueWaiter { struct MultiQueueWaiter {
std::condition_variable_any cv; std::condition_variable_any cv;
static bool HasState(std::initializer_list<BaseThreadQueue*> queues) { static bool HasState(std::initializer_list<BaseThreadQueue *> queues) {
for (BaseThreadQueue* queue : queues) { for (BaseThreadQueue *queue : queues) {
if (!queue->IsEmpty()) if (!queue->IsEmpty())
return true; return true;
} }
return false; return false;
} }
template <typename... BaseThreadQueue> template <typename... BaseThreadQueue> void Wait(BaseThreadQueue... queues) {
void Wait(BaseThreadQueue... queues) {
MultiQueueLock<BaseThreadQueue...> l(queues...); MultiQueueLock<BaseThreadQueue...> l(queues...);
while (!HasState({queues...})) while (!HasState({queues...}))
cv.wait(l); cv.wait(l);
@ -66,21 +59,19 @@ struct MultiQueueWaiter {
}; };
// A threadsafe-queue. http://stackoverflow.com/a/16075550 // A threadsafe-queue. http://stackoverflow.com/a/16075550
template <class T> template <class T> struct ThreadedQueue : public BaseThreadQueue {
struct ThreadedQueue : public BaseThreadQueue { public:
public:
ThreadedQueue() { ThreadedQueue() {
owned_waiter_ = std::make_unique<MultiQueueWaiter>(); owned_waiter_ = std::make_unique<MultiQueueWaiter>();
waiter_ = owned_waiter_.get(); waiter_ = owned_waiter_.get();
} }
explicit ThreadedQueue(MultiQueueWaiter* waiter) : waiter_(waiter) {} explicit ThreadedQueue(MultiQueueWaiter *waiter) : waiter_(waiter) {}
// Returns the number of elements in the queue. This is lock-free. // Returns the number of elements in the queue. This is lock-free.
size_t Size() const { return total_count_; } size_t Size() const { return total_count_; }
// Add an element to the queue. // Add an element to the queue.
template <void (std::deque<T>::*push)(T&&)> template <void (std::deque<T>::*push)(T &&)> void Push(T &&t, bool priority) {
void Push(T&& t, bool priority) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
if (priority) if (priority)
(priority_.*push)(std::move(t)); (priority_.*push)(std::move(t));
@ -90,7 +81,7 @@ struct ThreadedQueue : public BaseThreadQueue {
waiter_->cv.notify_one(); waiter_->cv.notify_one();
} }
void PushBack(T&& t, bool priority = false) { void PushBack(T &&t, bool priority = false) {
Push<&std::deque<T>::push_back>(std::move(t), priority); Push<&std::deque<T>::push_back>(std::move(t), priority);
} }
@ -123,7 +114,7 @@ struct ThreadedQueue : public BaseThreadQueue {
waiter_->cv.wait(lock, waiter_->cv.wait(lock,
[&]() { return !priority_.empty() || !queue_.empty(); }); [&]() { return !priority_.empty() || !queue_.empty(); });
auto execute = [&](std::deque<T>* q) { auto execute = [&](std::deque<T> *q) {
auto val = std::move(q->front()); auto val = std::move(q->front());
q->pop_front(); q->pop_front();
--total_count_; --total_count_;
@ -138,7 +129,7 @@ struct ThreadedQueue : public BaseThreadQueue {
// value if the queue is empty. // value if the queue is empty.
std::optional<T> TryPopFront() { std::optional<T> TryPopFront() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto execute = [&](std::deque<T>* q) { auto execute = [&](std::deque<T> *q) {
auto val = std::move(q->front()); auto val = std::move(q->front());
q->pop_front(); q->pop_front();
--total_count_; --total_count_;
@ -151,21 +142,20 @@ struct ThreadedQueue : public BaseThreadQueue {
return std::nullopt; return std::nullopt;
} }
template <typename Fn> template <typename Fn> void Iterate(Fn fn) {
void Iterate(Fn fn) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
for (auto& entry : priority_) for (auto &entry : priority_)
fn(entry); fn(entry);
for (auto& entry : queue_) for (auto &entry : queue_)
fn(entry); fn(entry);
} }
mutable std::mutex mutex_; mutable std::mutex mutex_;
private: private:
std::atomic<int> total_count_{0}; std::atomic<int> total_count_{0};
std::deque<T> priority_; std::deque<T> priority_;
std::deque<T> queue_; std::deque<T> queue_;
MultiQueueWaiter* waiter_; MultiQueueWaiter *waiter_;
std::unique_ptr<MultiQueueWaiter> owned_waiter_; std::unique_ptr<MultiQueueWaiter> owned_waiter_;
}; };

View File

@ -7,16 +7,16 @@ using namespace llvm;
#include <siphash.h> #include <siphash.h>
#include <algorithm>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include <algorithm>
#include <functional> #include <functional>
#include <string.h>
#include <unordered_map> #include <unordered_map>
using namespace std::placeholders; using namespace std::placeholders;
void TrimInPlace(std::string& s) { void TrimInPlace(std::string &s) {
auto f = [](char c) { return !isspace(c); }; auto f = [](char c) { return !isspace(c); };
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f)); s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end()); s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
@ -34,7 +34,8 @@ uint64_t HashUsr(std::string_view s) {
// k is an arbitrary key. Don't change it. // k is an arbitrary key. Don't change it.
const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52,
0x61, 0x79, 0xea, 0x70, 0xca, 0x70, 0xf0, 0x0d}; 0x61, 0x79, 0xea, 0x70, 0xca, 0x70, 0xf0, 0x0d};
(void)siphash(reinterpret_cast<const uint8_t*>(s.data()), s.size(), k, out, 8); (void)siphash(reinterpret_cast<const uint8_t *>(s.data()), s.size(), k, out,
8);
return ret; return ret;
} }
@ -52,20 +53,20 @@ bool StartsWith(std::string_view s, std::string_view prefix) {
std::equal(prefix.begin(), prefix.end(), s.begin()); std::equal(prefix.begin(), prefix.end(), s.begin());
} }
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss) { bool EndsWithAny(std::string_view s, const std::vector<std::string> &ss) {
return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1)); return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1));
} }
bool FindAnyPartial(const std::string& value, bool FindAnyPartial(const std::string &value,
const std::vector<std::string>& values) { const std::vector<std::string> &values) {
return std::any_of(std::begin(values), std::end(values), return std::any_of(std::begin(values), std::end(values),
[&value](const std::string& v) { [&value](const std::string &v) {
return value.find(v) != std::string::npos; return value.find(v) != std::string::npos;
}); });
} }
std::vector<std::string> SplitString(const std::string& str, std::vector<std::string> SplitString(const std::string &str,
const std::string& delimiter) { const std::string &delimiter) {
// http://stackoverflow.com/a/13172514 // http://stackoverflow.com/a/13172514
std::vector<std::string> strings; std::vector<std::string> strings;
@ -82,10 +83,10 @@ std::vector<std::string> SplitString(const std::string& str,
return strings; return strings;
} }
std::string LowerPathIfInsensitive(const std::string& path) { std::string LowerPathIfInsensitive(const std::string &path) {
#if defined(_WIN32) #if defined(_WIN32)
std::string ret = path; std::string ret = path;
for (char& c : ret) for (char &c : ret)
c = tolower(c); c = tolower(c);
return ret; return ret;
#else #else
@ -93,14 +94,14 @@ std::string LowerPathIfInsensitive(const std::string& path) {
#endif #endif
} }
void EnsureEndsInSlash(std::string& path) { void EnsureEndsInSlash(std::string &path) {
if (path.empty() || path[path.size() - 1] != '/') if (path.empty() || path[path.size() - 1] != '/')
path += '/'; path += '/';
} }
std::string EscapeFileName(std::string path) { std::string EscapeFileName(std::string path) {
bool slash = path.size() && path.back() == '/'; bool slash = path.size() && path.back() == '/';
for (char& c : path) for (char &c : path)
if (c == '\\' || c == '/' || c == ':') if (c == '\\' || c == '/' || c == ':')
c = '@'; c = '@';
if (slash) if (slash)
@ -108,11 +109,12 @@ std::string EscapeFileName(std::string path) {
return path; return path;
} }
std::optional<std::string> ReadContent(const std::string& filename) { std::optional<std::string> ReadContent(const std::string &filename) {
char buf[4096]; char buf[4096];
std::string ret; std::string ret;
FILE* f = fopen(filename.c_str(), "rb"); FILE *f = fopen(filename.c_str(), "rb");
if (!f) return {}; if (!f)
return {};
size_t n; size_t n;
while ((n = fread(buf, 1, sizeof buf, f)) > 0) while ((n = fread(buf, 1, sizeof buf, f)) > 0)
ret.append(buf, n); ret.append(buf, n);
@ -120,8 +122,8 @@ std::optional<std::string> ReadContent(const std::string& filename) {
return ret; return ret;
} }
void WriteToFile(const std::string& filename, const std::string& content) { void WriteToFile(const std::string &filename, const std::string &content) {
FILE* f = fopen(filename.c_str(), "wb"); FILE *f = fopen(filename.c_str(), "wb");
if (!f || if (!f ||
(content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) { (content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) {
LOG_S(ERROR) << "failed to write to " << filename << ' ' << strerror(errno); LOG_S(ERROR) << "failed to write to " << filename << ' ' << strerror(errno);
@ -130,7 +132,7 @@ void WriteToFile(const std::string& filename, const std::string& content) {
fclose(f); fclose(f);
} }
std::optional<int64_t> LastWriteTime(const std::string& filename) { std::optional<int64_t> LastWriteTime(const std::string &filename) {
sys::fs::file_status Status; sys::fs::file_status Status;
if (sys::fs::status(filename, Status)) if (sys::fs::status(filename, Status))
return {}; return {};
@ -139,8 +141,7 @@ std::optional<int64_t> LastWriteTime(const std::string& filename) {
// Find discontinous |search| in |content|. // Find discontinous |search| in |content|.
// Return |found| and the count of skipped chars before found. // Return |found| and the count of skipped chars before found.
int ReverseSubseqMatch(std::string_view pat, int ReverseSubseqMatch(std::string_view pat, std::string_view text,
std::string_view text,
int case_sensitivity) { int case_sensitivity) {
if (case_sensitivity == 1) if (case_sensitivity == 1)
case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0; case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
@ -155,6 +156,4 @@ int ReverseSubseqMatch(std::string_view pat,
return -1; return -1;
} }
std::string GetDefaultResourceDirectory() { std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; }
return DEFAULT_RESOURCE_DIRECTORY;
}

View File

@ -13,7 +13,7 @@ namespace llvm {
class StringRef; class StringRef;
} }
void TrimInPlace(std::string& s); void TrimInPlace(std::string &s);
std::string Trim(std::string s); std::string Trim(std::string s);
uint64_t HashUsr(std::string_view s); uint64_t HashUsr(std::string_view s);
@ -22,22 +22,21 @@ uint64_t HashUsr(llvm::StringRef s);
// Returns true if |value| starts/ends with |start| or |ending|. // Returns true if |value| starts/ends with |start| or |ending|.
bool StartsWith(std::string_view value, std::string_view start); bool StartsWith(std::string_view value, std::string_view start);
bool EndsWith(std::string_view value, std::string_view ending); bool EndsWith(std::string_view value, std::string_view ending);
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss); bool EndsWithAny(std::string_view s, const std::vector<std::string> &ss);
bool FindAnyPartial(const std::string& value, bool FindAnyPartial(const std::string &value,
const std::vector<std::string>& values); const std::vector<std::string> &values);
std::vector<std::string> SplitString(const std::string& str, std::vector<std::string> SplitString(const std::string &str,
const std::string& delimiter); const std::string &delimiter);
std::string LowerPathIfInsensitive(const std::string& path); std::string LowerPathIfInsensitive(const std::string &path);
template <typename TValues, typename TMap> template <typename TValues, typename TMap>
std::string StringJoinMap(const TValues& values, std::string StringJoinMap(const TValues &values, const TMap &map,
const TMap& map, const std::string &sep = ", ") {
const std::string& sep = ", ") {
std::string result; std::string result;
bool first = true; bool first = true;
for (auto& entry : values) { for (auto &entry : values) {
if (!first) if (!first)
result += sep; result += sep;
first = false; first = false;
@ -47,24 +46,23 @@ std::string StringJoinMap(const TValues& values,
} }
template <typename TValues> template <typename TValues>
std::string StringJoin(const TValues& values, const std::string& sep = ", ") { std::string StringJoin(const TValues &values, const std::string &sep = ", ") {
return StringJoinMap(values, [](const std::string& entry) { return entry; }, return StringJoinMap(values, [](const std::string &entry) { return entry; },
sep); sep);
} }
// Ensures that |path| ends in a slash. // Ensures that |path| ends in a slash.
void EnsureEndsInSlash(std::string& path); void EnsureEndsInSlash(std::string &path);
// Converts a file path to one that can be used as filename. // Converts a file path to one that can be used as filename.
// e.g. foo/bar.c => foo_bar.c // e.g. foo/bar.c => foo_bar.c
std::string EscapeFileName(std::string path); std::string EscapeFileName(std::string path);
std::optional<std::string> ReadContent(const std::string& filename); std::optional<std::string> ReadContent(const std::string &filename);
void WriteToFile(const std::string& filename, const std::string& content); void WriteToFile(const std::string &filename, const std::string &content);
std::optional<int64_t> LastWriteTime(const std::string& filename); std::optional<int64_t> LastWriteTime(const std::string &filename);
int ReverseSubseqMatch(std::string_view pat, int ReverseSubseqMatch(std::string_view pat, std::string_view text,
std::string_view text,
int case_sensitivity); int case_sensitivity);
// http://stackoverflow.com/a/38140932 // http://stackoverflow.com/a/38140932
@ -76,25 +74,24 @@ int ReverseSubseqMatch(std::string_view pat,
// }; // };
// MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3) // MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)
inline void hash_combine(std::size_t& seed) {} inline void hash_combine(std::size_t &seed) {}
template <typename T, typename... Rest> template <typename T, typename... Rest>
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { inline void hash_combine(std::size_t &seed, const T &v, Rest... rest) {
std::hash<T> hasher; std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
hash_combine(seed, rest...); hash_combine(seed, rest...);
} }
#define MAKE_HASHABLE(type, ...) \ #define MAKE_HASHABLE(type, ...) \
namespace std { \ namespace std { \
template <> \ template <> struct hash<type> { \
struct hash<type> { \ std::size_t operator()(const type &t) const { \
std::size_t operator()(const type& t) const { \ std::size_t ret = 0; \
std::size_t ret = 0; \ hash_combine(ret, __VA_ARGS__); \
hash_combine(ret, __VA_ARGS__); \ return ret; \
return ret; \ } \
} \ }; \
}; \
} }
std::string GetDefaultResourceDirectory(); std::string GetDefaultResourceDirectory();

View File

@ -17,7 +17,7 @@ constexpr int kMaxDiff = 20;
// |kMaxColumnAlignSize|. // |kMaxColumnAlignSize|.
constexpr int kMaxColumnAlignSize = 200; constexpr int kMaxColumnAlignSize = 200;
lsPosition GetPositionForOffset(const std::string& content, int offset) { lsPosition GetPositionForOffset(const std::string &content, int offset) {
if (offset >= content.size()) if (offset >= content.size())
offset = (int)content.size() - 1; offset = (int)content.size() - 1;
@ -32,7 +32,7 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
return {line, col}; return {line, col};
} }
std::vector<std::string> ToLines(const std::string& content) { std::vector<std::string> ToLines(const std::string &content) {
std::vector<std::string> result; std::vector<std::string> result;
std::istringstream lines(content); std::istringstream lines(content);
std::string line; std::string line;
@ -45,7 +45,7 @@ std::vector<std::string> ToLines(const std::string& content) {
// Myers' O(ND) diff algorithm. // Myers' O(ND) diff algorithm.
// Costs: insertion=1, deletion=1, no substitution. // Costs: insertion=1, deletion=1, no substitution.
// If the distance is larger than threshold, returns threshould + 1. // If the distance is larger than threshold, returns threshould + 1.
int MyersDiff(const char* a, int la, const char* b, int lb, int threshold) { int MyersDiff(const char *a, int la, const char *b, int lb, int threshold) {
assert(threshold <= kMaxDiff); assert(threshold <= kMaxDiff);
static int v_static[2 * kMaxColumnAlignSize + 2]; static int v_static[2 * kMaxColumnAlignSize + 2];
const char *ea = a + la, *eb = b + lb; const char *ea = a + la, *eb = b + lb;
@ -61,7 +61,7 @@ int MyersDiff(const char* a, int la, const char* b, int lb, int threshold) {
if (la + lb > 2 * kMaxColumnAlignSize) if (la + lb > 2 * kMaxColumnAlignSize)
return std::min(abs(la - lb), threshold + 1); return std::min(abs(la - lb), threshold + 1);
int* v = v_static + lb; int *v = v_static + lb;
v[1] = 0; v[1] = 0;
for (int di = 0; di <= threshold; di++) { for (int di = 0; di <= threshold; di++) {
int low = -di + 2 * std::max(0, di - lb), int low = -di + 2 * std::max(0, di - lb),
@ -80,7 +80,7 @@ int MyersDiff(const char* a, int la, const char* b, int lb, int threshold) {
return threshold + 1; return threshold + 1;
} }
int MyersDiff(const std::string& a, const std::string& b, int threshold) { int MyersDiff(const std::string &a, const std::string &b, int threshold) {
return MyersDiff(a.data(), a.size(), b.data(), b.size(), threshold); return MyersDiff(a.data(), a.size(), b.data(), b.size(), threshold);
} }
@ -107,7 +107,7 @@ std::vector<int> EditDistanceVector(std::string a, std::string b) {
// Find matching position of |a[column]| in |b|. // Find matching position of |a[column]| in |b|.
// This is actually a single step of Hirschberg's sequence alignment algorithm. // This is actually a single step of Hirschberg's sequence alignment algorithm.
int AlignColumn(const std::string& a, int column, std::string b, bool is_end) { int AlignColumn(const std::string &a, int column, std::string b, bool is_end) {
int head = 0, tail = 0; int head = 0, tail = 0;
while (head < (int)a.size() && head < (int)b.size() && a[head] == b[head]) while (head < (int)a.size() && head < (int)b.size() && a[head] == b[head])
head++; head++;
@ -149,12 +149,10 @@ int AlignColumn(const std::string& a, int column, std::string b, bool is_end) {
// Find matching buffer line of index_lines[line]. // Find matching buffer line of index_lines[line].
// By symmetry, this can also be used to find matching index line of a buffer // By symmetry, this can also be used to find matching index line of a buffer
// line. // line.
std::optional<int> FindMatchingLine(const std::vector<std::string>& index_lines, std::optional<int>
const std::vector<int>& index_to_buffer, FindMatchingLine(const std::vector<std::string> &index_lines,
int line, const std::vector<int> &index_to_buffer, int line, int *column,
int* column, const std::vector<std::string> &buffer_lines, bool is_end) {
const std::vector<std::string>& buffer_lines,
bool is_end) {
// If this is a confident mapping, returns. // If this is a confident mapping, returns.
if (index_to_buffer[line] >= 0) { if (index_to_buffer[line] >= 0) {
int ret = index_to_buffer[line]; int ret = index_to_buffer[line];
@ -179,7 +177,7 @@ std::optional<int> FindMatchingLine(const std::vector<std::string>& index_lines,
// Search for lines [up,down] and use Myers's diff algorithm to find the best // Search for lines [up,down] and use Myers's diff algorithm to find the best
// match (least edit distance). // match (least edit distance).
int best = up, best_dist = kMaxDiff + 1; int best = up, best_dist = kMaxDiff + 1;
const std::string& needle = index_lines[line]; const std::string &needle = index_lines[line];
for (int i = up; i <= down; i++) { for (int i = up; i <= down; i++) {
int dist = MyersDiff(needle, buffer_lines[i], kMaxDiff); int dist = MyersDiff(needle, buffer_lines[i], kMaxDiff);
if (dist < best_dist) { if (dist < best_dist) {
@ -193,17 +191,17 @@ std::optional<int> FindMatchingLine(const std::vector<std::string>& index_lines,
return best; return best;
} }
} // namespace } // namespace
WorkingFile::WorkingFile(const std::string& filename, WorkingFile::WorkingFile(const std::string &filename,
const std::string& buffer_content) const std::string &buffer_content)
: filename(filename), buffer_content(buffer_content) { : filename(filename), buffer_content(buffer_content) {
OnBufferContentUpdated(); OnBufferContentUpdated();
// SetIndexContent gets called when the file is opened. // SetIndexContent gets called when the file is opened.
} }
void WorkingFile::SetIndexContent(const std::string& index_content) { void WorkingFile::SetIndexContent(const std::string &index_content) {
index_lines = ToLines(index_content); index_lines = ToLines(index_content);
index_to_buffer.clear(); index_to_buffer.clear();
@ -234,7 +232,7 @@ void WorkingFile::ComputeLineMapping() {
// For index line i, set index_to_buffer[i] to -1 if line i is duplicated. // For index line i, set index_to_buffer[i] to -1 if line i is duplicated.
int i = 0; int i = 0;
for (auto& line : index_lines) { for (auto &line : index_lines) {
uint64_t h = HashUsr(line); uint64_t h = HashUsr(line);
auto it = hash_to_unique.find(h); auto it = hash_to_unique.find(h);
if (it == hash_to_unique.end()) { if (it == hash_to_unique.end()) {
@ -251,7 +249,7 @@ void WorkingFile::ComputeLineMapping() {
// For buffer line i, set buffer_to_index[i] to -1 if line i is duplicated. // For buffer line i, set buffer_to_index[i] to -1 if line i is duplicated.
i = 0; i = 0;
hash_to_unique.clear(); hash_to_unique.clear();
for (auto& line : buffer_lines) { for (auto &line : buffer_lines) {
uint64_t h = HashUsr(line); uint64_t h = HashUsr(line);
auto it = hash_to_unique.find(h); auto it = hash_to_unique.find(h);
if (it == hash_to_unique.end()) { if (it == hash_to_unique.end()) {
@ -300,9 +298,8 @@ void WorkingFile::ComputeLineMapping() {
buffer_to_index[index_to_buffer[i]] = i; buffer_to_index[index_to_buffer[i]] = i;
} }
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
int* column, bool is_end) {
bool is_end) {
if (line < 0 || line >= (int)index_lines.size()) { if (line < 0 || line >= (int)index_lines.size()) {
LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, " LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, "
<< index_lines.size() << ")) in " << filename; << index_lines.size() << ")) in " << filename;
@ -315,9 +312,8 @@ std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line,
buffer_lines, is_end); buffer_lines, is_end);
} }
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, int *column,
int* column, bool is_end) {
bool is_end) {
// See GetBufferLineFromIndexLine for additional comments. // See GetBufferLineFromIndexLine for additional comments.
if (line < 0 || line >= (int)buffer_lines.size()) if (line < 0 || line >= (int)buffer_lines.size())
return std::nullopt; return std::nullopt;
@ -329,9 +325,8 @@ std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line,
} }
std::string WorkingFile::FindClosestCallNameInBuffer( std::string WorkingFile::FindClosestCallNameInBuffer(
lsPosition position, lsPosition position, int *active_parameter,
int* active_parameter, lsPosition *completion_position) const {
lsPosition* completion_position) const {
*active_parameter = 0; *active_parameter = 0;
int offset = GetOffsetForPosition(position, buffer_content); int offset = GetOffsetForPosition(position, buffer_content);
@ -378,10 +373,8 @@ std::string WorkingFile::FindClosestCallNameInBuffer(
} }
lsPosition WorkingFile::FindStableCompletionSource( lsPosition WorkingFile::FindStableCompletionSource(
lsPosition position, lsPosition position, bool *is_global_completion,
bool* is_global_completion, std::string *existing_completion, lsPosition *replace_end_pos) const {
std::string* existing_completion,
lsPosition* replace_end_pos) const {
*is_global_completion = true; *is_global_completion = true;
int start_offset = GetOffsetForPosition(position, buffer_content); int start_offset = GetOffsetForPosition(position, buffer_content);
@ -410,7 +403,8 @@ lsPosition WorkingFile::FindStableCompletionSource(
*replace_end_pos = position; *replace_end_pos = position;
for (int i = start_offset; i < buffer_content.size(); i++) { for (int i = start_offset; i < buffer_content.size(); i++) {
char c = buffer_content[i]; char c = buffer_content[i];
if (!isalnum(c) && c != '_') break; if (!isalnum(c) && c != '_')
break;
// We know that replace_end_pos and position are on the same line. // We know that replace_end_pos and position are on the same line.
replace_end_pos->character++; replace_end_pos->character++;
} }
@ -419,41 +413,41 @@ lsPosition WorkingFile::FindStableCompletionSource(
return GetPositionForOffset(buffer_content, offset); return GetPositionForOffset(buffer_content, offset);
} }
WorkingFile* WorkingFiles::GetFileByFilename(const std::string& filename) { WorkingFile *WorkingFiles::GetFileByFilename(const std::string &filename) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
return GetFileByFilenameNoLock(filename); return GetFileByFilenameNoLock(filename);
} }
WorkingFile* WorkingFiles::GetFileByFilenameNoLock( WorkingFile *
const std::string& filename) { WorkingFiles::GetFileByFilenameNoLock(const std::string &filename) {
for (auto& file : files) { for (auto &file : files) {
if (file->filename == filename) if (file->filename == filename)
return file.get(); return file.get();
} }
return nullptr; return nullptr;
} }
void WorkingFiles::DoAction(const std::function<void()>& action) { void WorkingFiles::DoAction(const std::function<void()> &action) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
action(); action();
} }
void WorkingFiles::DoActionOnFile( void WorkingFiles::DoActionOnFile(
const std::string& filename, const std::string &filename,
const std::function<void(WorkingFile* file)>& action) { const std::function<void(WorkingFile *file)> &action) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
WorkingFile* file = GetFileByFilenameNoLock(filename); WorkingFile *file = GetFileByFilenameNoLock(filename);
action(file); action(file);
} }
WorkingFile* WorkingFiles::OnOpen(const lsTextDocumentItem& open) { WorkingFile *WorkingFiles::OnOpen(const lsTextDocumentItem &open) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
std::string filename = open.uri.GetPath(); std::string filename = open.uri.GetPath();
std::string content = open.text; std::string content = open.text;
// The file may already be open. // The file may already be open.
if (WorkingFile* file = GetFileByFilenameNoLock(filename)) { if (WorkingFile *file = GetFileByFilenameNoLock(filename)) {
file->version = open.version; file->version = open.version;
file->buffer_content = content; file->buffer_content = content;
file->OnBufferContentUpdated(); file->OnBufferContentUpdated();
@ -464,11 +458,11 @@ WorkingFile* WorkingFiles::OnOpen(const lsTextDocumentItem& open) {
return files[files.size() - 1].get(); return files[files.size() - 1].get();
} }
void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) { void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams &change) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
std::string filename = change.textDocument.uri.GetPath(); std::string filename = change.textDocument.uri.GetPath();
WorkingFile* file = GetFileByFilenameNoLock(filename); WorkingFile *file = GetFileByFilenameNoLock(filename);
if (!file) { if (!file) {
LOG_S(WARNING) << "Could not change " << filename LOG_S(WARNING) << "Could not change " << filename
<< " because it was not open"; << " because it was not open";
@ -479,7 +473,7 @@ void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) {
if (change.textDocument.version) if (change.textDocument.version)
file->version = *change.textDocument.version; file->version = *change.textDocument.version;
for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) { for (const lsTextDocumentContentChangeEvent &diff : change.contentChanges) {
// Per the spec replace everything if the rangeLength and range are not set. // Per the spec replace everything if the rangeLength and range are not set.
// See https://github.com/Microsoft/language-server-protocol/issues/9. // See https://github.com/Microsoft/language-server-protocol/issues/9.
if (!diff.range) { if (!diff.range) {
@ -500,7 +494,7 @@ void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) {
} }
} }
void WorkingFiles::OnClose(const lsTextDocumentIdentifier& close) { void WorkingFiles::OnClose(const lsTextDocumentIdentifier &close) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
std::string filename = close.uri.GetPath(); std::string filename = close.uri.GetPath();
@ -516,13 +510,13 @@ void WorkingFiles::OnClose(const lsTextDocumentIdentifier& close) {
<< " because it was not open"; << " because it was not open";
} }
WorkingFiles::Snapshot WorkingFiles::AsSnapshot( WorkingFiles::Snapshot
const std::vector<std::string>& filter_paths) { WorkingFiles::AsSnapshot(const std::vector<std::string> &filter_paths) {
std::lock_guard<std::mutex> lock(files_mutex); std::lock_guard<std::mutex> lock(files_mutex);
Snapshot result; Snapshot result;
result.files.reserve(files.size()); result.files.reserve(files.size());
for (const auto& file : files) { for (const auto &file : files) {
if (filter_paths.empty() || FindAnyPartial(file->filename, filter_paths)) if (filter_paths.empty() || FindAnyPartial(file->filename, filter_paths))
result.files.push_back({file->filename, file->buffer_content}); result.files.push_back({file->filename, file->buffer_content});
} }

View File

@ -29,10 +29,10 @@ struct WorkingFile {
// lock! // lock!
std::vector<lsDiagnostic> diagnostics_; std::vector<lsDiagnostic> diagnostics_;
WorkingFile(const std::string& filename, const std::string& buffer_content); WorkingFile(const std::string &filename, const std::string &buffer_content);
// This should be called when the indexed content has changed. // This should be called when the indexed content has changed.
void SetIndexContent(const std::string& index_content); void SetIndexContent(const std::string &index_content);
// This should be called whenever |buffer_content| has changed. // This should be called whenever |buffer_content| has changed.
void OnBufferContentUpdated(); void OnBufferContentUpdated();
@ -40,10 +40,12 @@ struct WorkingFile {
// Also resolves |column| if not NULL. // Also resolves |column| if not NULL.
// When resolving a range, use is_end = false for begin() and is_end = // When resolving a range, use is_end = false for begin() and is_end =
// true for end() to get a better alignment of |column|. // true for end() to get a better alignment of |column|.
std::optional<int> GetBufferPosFromIndexPos(int line, int* column, bool is_end); std::optional<int> GetBufferPosFromIndexPos(int line, int *column,
bool is_end);
// Finds the index line number which maps to buffer line number |line|. // Finds the index line number which maps to buffer line number |line|.
// Also resolves |column| if not NULL. // Also resolves |column| if not NULL.
std::optional<int> GetIndexPosFromBufferPos(int line, int* column, bool is_end); std::optional<int> GetIndexPosFromBufferPos(int line, int *column,
bool is_end);
// TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into // TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into
// lex_utils.h/cc // lex_utils.h/cc
@ -53,10 +55,9 @@ struct WorkingFile {
// //
// |completion_position| will be point to a good code completion location to // |completion_position| will be point to a good code completion location to
// for fetching signatures. // for fetching signatures.
std::string FindClosestCallNameInBuffer( std::string
lsPosition position, FindClosestCallNameInBuffer(lsPosition position, int *active_parameter,
int* active_parameter, lsPosition *completion_position = nullptr) const;
lsPosition* completion_position = nullptr) const;
// Returns a relatively stable completion position (it jumps back until there // Returns a relatively stable completion position (it jumps back until there
// is a non-alphanumeric character). // is a non-alphanumeric character).
@ -66,11 +67,11 @@ struct WorkingFile {
// The out param |existing_completion| is set to any existing completion // The out param |existing_completion| is set to any existing completion
// content the user has entered. // content the user has entered.
lsPosition FindStableCompletionSource(lsPosition position, lsPosition FindStableCompletionSource(lsPosition position,
bool* is_global_completion, bool *is_global_completion,
std::string* existing_completion, std::string *existing_completion,
lsPosition* replace_end_pos) const; lsPosition *replace_end_pos) const;
private: private:
// Compute index_to_buffer and buffer_to_index. // Compute index_to_buffer and buffer_to_index.
void ComputeLineMapping(); void ComputeLineMapping();
}; };
@ -90,29 +91,29 @@ struct WorkingFiles {
// //
// Find the file with the given filename. // Find the file with the given filename.
WorkingFile* GetFileByFilename(const std::string& filename); WorkingFile *GetFileByFilename(const std::string &filename);
WorkingFile* GetFileByFilenameNoLock(const std::string& filename); WorkingFile *GetFileByFilenameNoLock(const std::string &filename);
// Run |action| under the lock. // Run |action| under the lock.
void DoAction(const std::function<void()>& action); void DoAction(const std::function<void()> &action);
// Run |action| on the file identified by |filename|. This executes under the // Run |action| on the file identified by |filename|. This executes under the
// lock. // lock.
void DoActionOnFile(const std::string& filename, void DoActionOnFile(const std::string &filename,
const std::function<void(WorkingFile* file)>& action); const std::function<void(WorkingFile *file)> &action);
WorkingFile* OnOpen(const lsTextDocumentItem& open); WorkingFile *OnOpen(const lsTextDocumentItem &open);
void OnChange(const lsTextDocumentDidChangeParams& change); void OnChange(const lsTextDocumentDidChangeParams &change);
void OnClose(const lsTextDocumentIdentifier& close); void OnClose(const lsTextDocumentIdentifier &close);
// If |filter_paths| is non-empty, only files which contain any of the given // If |filter_paths| is non-empty, only files which contain any of the given
// strings. For example, {"foo", "bar"} means that every result has either the // strings. For example, {"foo", "bar"} means that every result has either the
// string "foo" or "bar" contained within it. // string "foo" or "bar" contained within it.
Snapshot AsSnapshot(const std::vector<std::string>& filter_paths); Snapshot AsSnapshot(const std::vector<std::string> &filter_paths);
// Use unique_ptrs so we can handout WorkingFile ptrs and not have them // Use unique_ptrs so we can handout WorkingFile ptrs and not have them
// invalidated if we resize files. // invalidated if we resize files.
std::vector<std::unique_ptr<WorkingFile>> files; std::vector<std::unique_ptr<WorkingFile>> files;
std::mutex files_mutex; // Protects |files|. std::mutex files_mutex; // Protects |files|.
}; };
int GetOffsetForPosition(lsPosition position, std::string_view content); int GetOffsetForPosition(lsPosition position, std::string_view content);