mirror of
https://github.com/MaskRay/ccls.git
synced 2025-05-06 08:26:15 +00:00
clang-format
DEF CON 26 CTF
This commit is contained in:
parent
344ade0420
commit
8cbb317dc2
@ -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() {
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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";
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
52
src/config.h
52
src/config.h
@ -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;
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
250
src/indexer.cc
250
src/indexer.cc
@ -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 ¶m;
|
||||||
|
|
||||||
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 ¶m) : 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 ¶m;
|
||||||
|
|
||||||
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 ¶m;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IndexFrontendAction(IndexParam& param) : param(param) {}
|
IndexFrontendAction(IndexParam ¶m) : 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
src/indexer.h
101
src/indexer.h
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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);
|
||||||
|
15
src/log.cc
15
src/log.cc
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
43
src/lsp.cc
43
src/lsp.cc
@ -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) {
|
||||||
|
75
src/lsp.h
75
src/lsp.h
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
24
src/main.cc
24
src/main.cc
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
src/match.cc
34
src/match.cc
@ -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 + "\"";
|
||||||
|
12
src/match.h
12
src/match.h
@ -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;
|
||||||
|
33
src/maybe.h
33
src/maybe.h
@ -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); }
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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);
|
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = request->params;
|
const auto ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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 ¶meter : 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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms = 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
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
14
src/method.h
14
src/method.h
@ -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();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
116
src/pipeline.cc
116
src/pipeline.cc
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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 "";
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
|
110
src/project.cc
110
src/project.cc
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
213
src/query.cc
213
src/query.cc
@ -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 "";
|
||||||
}
|
}
|
||||||
|
42
src/query.h
42
src/query.h
@ -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); }
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
226
src/serializer.h
226
src/serializer.h
@ -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
|
||||||
}
|
|
||||||
|
@ -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 {}
|
||||||
};
|
};
|
||||||
|
@ -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); }
|
||||||
};
|
};
|
||||||
|
68
src/test.cc
68
src/test.cc
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
49
src/utils.cc
49
src/utils.cc
@ -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;
|
|
||||||
}
|
|
||||||
|
59
src/utils.h
59
src/utils.h
@ -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();
|
||||||
|
@ -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});
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user