mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-21 23:25:07 +00:00
clang-format
DEF CON 26 CTF
This commit is contained in:
parent
87f36a4a96
commit
39787d2851
@ -20,7 +20,7 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string StripFileType(const std::string& path) {
|
||||
std::string StripFileType(const std::string &path) {
|
||||
SmallString<128> Ret;
|
||||
sys::path::append(Ret, sys::path::parent_path(path), sys::path::stem(path));
|
||||
return Ret.str();
|
||||
@ -41,93 +41,93 @@ unsigned GetCompletionPriority(const CodeCompletionString &CCS,
|
||||
|
||||
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
||||
switch (cursor_kind) {
|
||||
case CXCursor_UnexposedDecl:
|
||||
return lsCompletionItemKind::Text;
|
||||
case CXCursor_UnexposedDecl:
|
||||
return lsCompletionItemKind::Text;
|
||||
|
||||
case CXCursor_StructDecl:
|
||||
case CXCursor_UnionDecl:
|
||||
return lsCompletionItemKind::Struct;
|
||||
case CXCursor_ClassDecl:
|
||||
return lsCompletionItemKind::Class;
|
||||
case CXCursor_EnumDecl:
|
||||
return lsCompletionItemKind::Enum;
|
||||
case CXCursor_FieldDecl:
|
||||
return lsCompletionItemKind::Field;
|
||||
case CXCursor_EnumConstantDecl:
|
||||
return lsCompletionItemKind::EnumMember;
|
||||
case CXCursor_FunctionDecl:
|
||||
return lsCompletionItemKind::Function;
|
||||
case CXCursor_VarDecl:
|
||||
case CXCursor_ParmDecl:
|
||||
return lsCompletionItemKind::Variable;
|
||||
case CXCursor_ObjCInterfaceDecl:
|
||||
return lsCompletionItemKind::Interface;
|
||||
case CXCursor_StructDecl:
|
||||
case CXCursor_UnionDecl:
|
||||
return lsCompletionItemKind::Struct;
|
||||
case CXCursor_ClassDecl:
|
||||
return lsCompletionItemKind::Class;
|
||||
case CXCursor_EnumDecl:
|
||||
return lsCompletionItemKind::Enum;
|
||||
case CXCursor_FieldDecl:
|
||||
return lsCompletionItemKind::Field;
|
||||
case CXCursor_EnumConstantDecl:
|
||||
return lsCompletionItemKind::EnumMember;
|
||||
case CXCursor_FunctionDecl:
|
||||
return lsCompletionItemKind::Function;
|
||||
case CXCursor_VarDecl:
|
||||
case CXCursor_ParmDecl:
|
||||
return lsCompletionItemKind::Variable;
|
||||
case CXCursor_ObjCInterfaceDecl:
|
||||
return lsCompletionItemKind::Interface;
|
||||
|
||||
case CXCursor_ObjCInstanceMethodDecl:
|
||||
case CXCursor_CXXMethod:
|
||||
case CXCursor_ObjCClassMethodDecl:
|
||||
return lsCompletionItemKind::Method;
|
||||
case CXCursor_ObjCInstanceMethodDecl:
|
||||
case CXCursor_CXXMethod:
|
||||
case CXCursor_ObjCClassMethodDecl:
|
||||
return lsCompletionItemKind::Method;
|
||||
|
||||
case CXCursor_FunctionTemplate:
|
||||
return lsCompletionItemKind::Function;
|
||||
case CXCursor_FunctionTemplate:
|
||||
return lsCompletionItemKind::Function;
|
||||
|
||||
case CXCursor_Constructor:
|
||||
case CXCursor_Destructor:
|
||||
case CXCursor_ConversionFunction:
|
||||
return lsCompletionItemKind::Constructor;
|
||||
case CXCursor_Constructor:
|
||||
case CXCursor_Destructor:
|
||||
case CXCursor_ConversionFunction:
|
||||
return lsCompletionItemKind::Constructor;
|
||||
|
||||
case CXCursor_ObjCIvarDecl:
|
||||
return lsCompletionItemKind::Variable;
|
||||
case CXCursor_ObjCIvarDecl:
|
||||
return lsCompletionItemKind::Variable;
|
||||
|
||||
case CXCursor_ClassTemplate:
|
||||
case CXCursor_ClassTemplatePartialSpecialization:
|
||||
case CXCursor_UsingDeclaration:
|
||||
case CXCursor_TypedefDecl:
|
||||
case CXCursor_TypeAliasDecl:
|
||||
case CXCursor_TypeAliasTemplateDecl:
|
||||
case CXCursor_ObjCCategoryDecl:
|
||||
case CXCursor_ObjCProtocolDecl:
|
||||
case CXCursor_ObjCImplementationDecl:
|
||||
case CXCursor_ObjCCategoryImplDecl:
|
||||
return lsCompletionItemKind::Class;
|
||||
case CXCursor_ClassTemplate:
|
||||
case CXCursor_ClassTemplatePartialSpecialization:
|
||||
case CXCursor_UsingDeclaration:
|
||||
case CXCursor_TypedefDecl:
|
||||
case CXCursor_TypeAliasDecl:
|
||||
case CXCursor_TypeAliasTemplateDecl:
|
||||
case CXCursor_ObjCCategoryDecl:
|
||||
case CXCursor_ObjCProtocolDecl:
|
||||
case CXCursor_ObjCImplementationDecl:
|
||||
case CXCursor_ObjCCategoryImplDecl:
|
||||
return lsCompletionItemKind::Class;
|
||||
|
||||
case CXCursor_ObjCPropertyDecl:
|
||||
return lsCompletionItemKind::Property;
|
||||
case CXCursor_ObjCPropertyDecl:
|
||||
return lsCompletionItemKind::Property;
|
||||
|
||||
case CXCursor_MacroInstantiation:
|
||||
case CXCursor_MacroDefinition:
|
||||
return lsCompletionItemKind::Interface;
|
||||
case CXCursor_MacroInstantiation:
|
||||
case CXCursor_MacroDefinition:
|
||||
return lsCompletionItemKind::Interface;
|
||||
|
||||
case CXCursor_Namespace:
|
||||
case CXCursor_NamespaceAlias:
|
||||
case CXCursor_NamespaceRef:
|
||||
return lsCompletionItemKind::Module;
|
||||
case CXCursor_Namespace:
|
||||
case CXCursor_NamespaceAlias:
|
||||
case CXCursor_NamespaceRef:
|
||||
return lsCompletionItemKind::Module;
|
||||
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_TypeRef:
|
||||
case CXCursor_ObjCSuperClassRef:
|
||||
case CXCursor_ObjCProtocolRef:
|
||||
case CXCursor_ObjCClassRef:
|
||||
return lsCompletionItemKind::Reference;
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_TypeRef:
|
||||
case CXCursor_ObjCSuperClassRef:
|
||||
case CXCursor_ObjCProtocolRef:
|
||||
case CXCursor_ObjCClassRef:
|
||||
return lsCompletionItemKind::Reference;
|
||||
|
||||
// return lsCompletionItemKind::Unit;
|
||||
// return lsCompletionItemKind::Value;
|
||||
// return lsCompletionItemKind::Keyword;
|
||||
// return lsCompletionItemKind::Snippet;
|
||||
// return lsCompletionItemKind::Color;
|
||||
// return lsCompletionItemKind::File;
|
||||
// return lsCompletionItemKind::Unit;
|
||||
// return lsCompletionItemKind::Value;
|
||||
// return lsCompletionItemKind::Keyword;
|
||||
// return lsCompletionItemKind::Snippet;
|
||||
// return lsCompletionItemKind::Color;
|
||||
// return lsCompletionItemKind::File;
|
||||
|
||||
case CXCursor_NotImplemented:
|
||||
case CXCursor_OverloadCandidate:
|
||||
return lsCompletionItemKind::Text;
|
||||
case CXCursor_NotImplemented:
|
||||
case CXCursor_OverloadCandidate:
|
||||
return lsCompletionItemKind::Text;
|
||||
|
||||
case CXCursor_TemplateTypeParameter:
|
||||
case CXCursor_TemplateTemplateParameter:
|
||||
return lsCompletionItemKind::TypeParameter;
|
||||
case CXCursor_TemplateTypeParameter:
|
||||
case CXCursor_TemplateTemplateParameter:
|
||||
return lsCompletionItemKind::TypeParameter;
|
||||
|
||||
default:
|
||||
LOG_S(WARNING) << "Unhandled completion kind " << cursor_kind;
|
||||
return lsCompletionItemKind::Text;
|
||||
default:
|
||||
LOG_S(WARNING) << "Unhandled completion kind " << cursor_kind;
|
||||
return lsCompletionItemKind::Text;
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,50 +144,50 @@ void BuildCompletionItemTexts(std::vector<lsCompletionItem> &out,
|
||||
CodeCompletionString::ChunkKind Kind = Chunk.Kind;
|
||||
std::string text;
|
||||
switch (Kind) {
|
||||
case CodeCompletionString::CK_TypedText:
|
||||
case CodeCompletionString::CK_Text:
|
||||
case CodeCompletionString::CK_Placeholder:
|
||||
case CodeCompletionString::CK_Informative:
|
||||
if (Chunk.Text)
|
||||
text = Chunk.Text;
|
||||
for (auto i = out_first; i < out.size(); i++) {
|
||||
// first TypedText is used for filtering
|
||||
if (Kind == CodeCompletionString::CK_TypedText && !out[i].filterText)
|
||||
out[i].filterText = text;
|
||||
if (Kind == CodeCompletionString::CK_Placeholder)
|
||||
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;
|
||||
case CodeCompletionString::CK_TypedText:
|
||||
case CodeCompletionString::CK_Text:
|
||||
case CodeCompletionString::CK_Placeholder:
|
||||
case CodeCompletionString::CK_Informative:
|
||||
if (Chunk.Text)
|
||||
text = Chunk.Text;
|
||||
for (auto i = out_first; i < out.size(); i++) {
|
||||
// first TypedText is used for filtering
|
||||
if (Kind == CodeCompletionString::CK_TypedText && !out[i].filterText)
|
||||
out[i].filterText = text;
|
||||
if (Kind == CodeCompletionString::CK_Placeholder)
|
||||
out[i].parameters_.push_back(text);
|
||||
}
|
||||
// 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
|
||||
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
|
||||
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)
|
||||
@ -197,8 +197,9 @@ void BuildCompletionItemTexts(std::vector<lsCompletionItem> &out,
|
||||
continue;
|
||||
|
||||
if (Kind == CodeCompletionString::CK_Placeholder) {
|
||||
out[i].insertText +=
|
||||
"${" + std::to_string(out[i].parameters_.size()) + ":" + text + "}";
|
||||
out[i].insertText += "${" +
|
||||
std::to_string(out[i].parameters_.size()) + ":" +
|
||||
text + "}";
|
||||
out[i].insertTextFormat = lsInsertTextFormat::Snippet;
|
||||
} else {
|
||||
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) {
|
||||
const CodeCompletionString::Chunk &Chunk = CCS[i];
|
||||
CodeCompletionString::ChunkKind Kind = Chunk.Kind;
|
||||
const char* text = nullptr;
|
||||
const char *text = nullptr;
|
||||
switch (Kind) {
|
||||
case CodeCompletionString::CK_TypedText:
|
||||
item.label = Chunk.Text;
|
||||
@ -238,7 +239,8 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
|
||||
item.detail += Chunk.Text;
|
||||
// Add parameter declarations as snippets if enabled
|
||||
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;
|
||||
} else
|
||||
do_insert = false;
|
||||
@ -250,8 +252,8 @@ void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
|
||||
case CodeCompletionString::CK_Optional: {
|
||||
// Do not add text to insert string if we're in angle brackets.
|
||||
bool should_insert = do_insert && angle_stack == 0;
|
||||
BuildDetailString(*Chunk.Optional, item, should_insert,
|
||||
parameters, include_snippets, angle_stack);
|
||||
BuildDetailString(*Chunk.Optional, item, should_insert, parameters,
|
||||
include_snippets, angle_stack);
|
||||
break;
|
||||
}
|
||||
case CodeCompletionString::CK_ResultType:
|
||||
@ -298,10 +300,9 @@ public:
|
||||
Alloc(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
|
||||
CCTUInfo(Alloc) {}
|
||||
|
||||
void ProcessCodeCompleteResults(Sema &S,
|
||||
CodeCompletionContext Context,
|
||||
CodeCompletionResult *Results,
|
||||
unsigned NumResults) override {
|
||||
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
|
||||
CodeCompletionResult *Results,
|
||||
unsigned NumResults) override {
|
||||
ls_items.reserve(NumResults);
|
||||
for (unsigned i = 0; i != NumResults; i++) {
|
||||
CodeCompletionString *CCS = Results[i].CreateCodeCompletionString(
|
||||
@ -312,7 +313,7 @@ public:
|
||||
|
||||
lsCompletionItem ls_item;
|
||||
ls_item.kind = GetCompletionKind(Results[i].CursorKind);
|
||||
if (const char* brief = CCS->getBriefComment())
|
||||
if (const char *brief = CCS->getBriefComment())
|
||||
ls_item.documentation = brief;
|
||||
|
||||
// label/detail/filterText/insertText/priority
|
||||
@ -334,8 +335,7 @@ public:
|
||||
} else {
|
||||
bool do_insert = true;
|
||||
int angle_stack = 0;
|
||||
BuildDetailString(*CCS, ls_item, do_insert,
|
||||
&ls_item.parameters_,
|
||||
BuildDetailString(*CCS, ls_item, do_insert, &ls_item.parameters_,
|
||||
g_config->client.snippetSupport, angle_stack);
|
||||
if (g_config->client.snippetSupport &&
|
||||
ls_item.insertTextFormat == lsInsertTextFormat::Snippet)
|
||||
@ -353,7 +353,7 @@ public:
|
||||
|
||||
CodeCompletionAllocator &getAllocator() override { return *Alloc; }
|
||||
|
||||
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo;}
|
||||
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
|
||||
};
|
||||
|
||||
void TryEnsureDocumentParsed(ClangCompleteManager *manager,
|
||||
@ -374,7 +374,7 @@ void TryEnsureDocumentParsed(ClangCompleteManager *manager,
|
||||
diagnostic);
|
||||
}
|
||||
|
||||
void CompletionPreloadMain(ClangCompleteManager* completion_manager) {
|
||||
void CompletionPreloadMain(ClangCompleteManager *completion_manager) {
|
||||
while (true) {
|
||||
// Fetching the completion request blocks until we have a request.
|
||||
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
|
||||
// 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
|
||||
// reparsing.
|
||||
@ -407,7 +407,7 @@ void CompletionPreloadMain(ClangCompleteManager* completion_manager) {
|
||||
}
|
||||
}
|
||||
|
||||
void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||
void CompletionQueryMain(ClangCompleteManager *completion_manager) {
|
||||
while (true) {
|
||||
// Fetching the completion request blocks until we have a request.
|
||||
std::unique_ptr<ClangCompleteManager::CompletionRequest> request =
|
||||
@ -427,11 +427,12 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||
true /*create_if_needed*/);
|
||||
|
||||
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
|
||||
// |TryEnsureDocumentParsed|.
|
||||
if (ClangTranslationUnit* tu = session->completion.tu.get()) {
|
||||
if (ClangTranslationUnit *tu = session->completion.tu.get()) {
|
||||
WorkingFiles::Snapshot snapshot =
|
||||
completion_manager->working_files_->AsSnapshot({StripFileType(path)});
|
||||
IntrusiveRefCntPtr<FileManager> FileMgr(&tu->Unit->getFileManager());
|
||||
@ -464,7 +465,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||
capture, tu->PCHCO, *Diag, LangOpts, *SrcMgr,
|
||||
*FileMgr, Diagnostics, TemporaryBuffers);
|
||||
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
|
||||
// |TryEnsureDocumentParsed|.
|
||||
ClangTranslationUnit* tu = session->diagnostics.tu.get();
|
||||
ClangTranslationUnit *tu = session->diagnostics.tu.get();
|
||||
if (!tu)
|
||||
continue;
|
||||
|
||||
@ -509,7 +511,8 @@ void DiagnosticQueryMain(ClangCompleteManager *manager) {
|
||||
if (!FLoc.isValid()) // why?
|
||||
continue;
|
||||
const FileEntry *FE = FLoc.getFileEntry();
|
||||
if (!FE || FileName(*FE) != path) continue;
|
||||
if (!FE || FileName(*FE) != path)
|
||||
continue;
|
||||
const auto &SM = FLoc.getManager();
|
||||
SourceRange R;
|
||||
for (const auto &CR : I->getRanges()) {
|
||||
@ -553,45 +556,46 @@ void DiagnosticQueryMain(ClangCompleteManager *manager) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
ClangCompleteManager::ClangCompleteManager(Project* project,
|
||||
WorkingFiles* working_files,
|
||||
ClangCompleteManager::ClangCompleteManager(Project *project,
|
||||
WorkingFiles *working_files,
|
||||
OnDiagnostic on_diagnostic,
|
||||
OnDropped on_dropped)
|
||||
: project_(project),
|
||||
working_files_(working_files),
|
||||
on_diagnostic_(on_diagnostic),
|
||||
on_dropped_(on_dropped),
|
||||
: project_(project), working_files_(working_files),
|
||||
on_diagnostic_(on_diagnostic), on_dropped_(on_dropped),
|
||||
preloaded_sessions_(kMaxPreloadedSessions),
|
||||
completion_sessions_(kMaxCompletionSessions) {
|
||||
std::thread([&]() {
|
||||
set_thread_name("comp-query");
|
||||
CompletionQueryMain(this);
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
std::thread([&]() {
|
||||
set_thread_name("comp-preload");
|
||||
CompletionPreloadMain(this);
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
std::thread([&]() {
|
||||
set_thread_name("diag-query");
|
||||
DiagnosticQueryMain(this);
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
void ClangCompleteManager::CodeComplete(
|
||||
const lsRequestId& id,
|
||||
const lsTextDocumentPositionParams& completion_location,
|
||||
const OnComplete& on_complete) {
|
||||
const lsRequestId &id,
|
||||
const lsTextDocumentPositionParams &completion_location,
|
||||
const OnComplete &on_complete) {
|
||||
completion_request_.PushBack(std::make_unique<CompletionRequest>(
|
||||
id, completion_location.textDocument, completion_location.position,
|
||||
on_complete));
|
||||
}
|
||||
|
||||
void ClangCompleteManager::DiagnosticsUpdate(
|
||||
const lsTextDocumentIdentifier& document) {
|
||||
const lsTextDocumentIdentifier &document) {
|
||||
bool has = false;
|
||||
diagnostic_request_.Iterate([&](const DiagnosticRequest& request) {
|
||||
diagnostic_request_.Iterate([&](const DiagnosticRequest &request) {
|
||||
if (request.document.uri == document.uri)
|
||||
has = true;
|
||||
});
|
||||
@ -600,7 +604,7 @@ void ClangCompleteManager::DiagnosticsUpdate(
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
||||
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
|
||||
// moving the CompletionSession instance from preloaded to completion
|
||||
@ -622,7 +626,7 @@ void ClangCompleteManager::NotifyEdit(const std::string& filename) {
|
||||
NotifyView(filename);
|
||||
}
|
||||
|
||||
void ClangCompleteManager::NotifySave(const std::string& filename) {
|
||||
void ClangCompleteManager::NotifySave(const std::string &filename) {
|
||||
//
|
||||
// On save, always reparse.
|
||||
//
|
||||
@ -631,7 +635,7 @@ void ClangCompleteManager::NotifySave(const std::string& filename) {
|
||||
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.
|
||||
//
|
||||
@ -652,7 +656,7 @@ void ClangCompleteManager::NotifyClose(const std::string& filename) {
|
||||
}
|
||||
|
||||
bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
|
||||
const std::string& filename) {
|
||||
const std::string &filename) {
|
||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||
|
||||
// Check for an existing CompletionSession.
|
||||
@ -668,10 +672,10 @@ bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
|
||||
const std::string& filename,
|
||||
bool mark_as_completion,
|
||||
bool create_if_needed) {
|
||||
std::shared_ptr<CompletionSession>
|
||||
ClangCompleteManager::TryGetSession(const std::string &filename,
|
||||
bool mark_as_completion,
|
||||
bool create_if_needed) {
|
||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||
|
||||
// Try to find a preloaded session.
|
||||
@ -701,11 +705,11 @@ std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
|
||||
return completion_session;
|
||||
}
|
||||
|
||||
void ClangCompleteManager::FlushSession(const std::string& filename) {
|
||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||
void ClangCompleteManager::FlushSession(const std::string &filename) {
|
||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||
|
||||
preloaded_sessions_.TryTake(filename);
|
||||
completion_sessions_.TryTake(filename);
|
||||
preloaded_sessions_.TryTake(filename);
|
||||
completion_sessions_.TryTake(filename);
|
||||
}
|
||||
|
||||
void ClangCompleteManager::FlushAllSessions() {
|
||||
|
@ -26,39 +26,34 @@ struct CompletionSession
|
||||
};
|
||||
|
||||
Project::Entry file;
|
||||
WorkingFiles* working_files;
|
||||
WorkingFiles *working_files;
|
||||
|
||||
Tu completion;
|
||||
Tu diagnostics;
|
||||
|
||||
CompletionSession(const Project::Entry& file, WorkingFiles* wfiles)
|
||||
CompletionSession(const Project::Entry &file, WorkingFiles *wfiles)
|
||||
: file(file), working_files(wfiles) {}
|
||||
};
|
||||
|
||||
struct ClangCompleteManager {
|
||||
using OnDiagnostic =
|
||||
std::function<void(std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics)>;
|
||||
using OnComplete =
|
||||
std::function<void(const std::vector<lsCompletionItem>& results,
|
||||
bool is_cached_result)>;
|
||||
using OnDiagnostic = std::function<void(
|
||||
std::string path, std::vector<lsDiagnostic> diagnostics)>;
|
||||
using OnComplete = std::function<void(
|
||||
const std::vector<lsCompletionItem> &results, bool is_cached_result)>;
|
||||
using OnDropped = std::function<void(lsRequestId request_id)>;
|
||||
|
||||
struct PreloadRequest {
|
||||
PreloadRequest(const std::string& path)
|
||||
PreloadRequest(const std::string &path)
|
||||
: request_time(std::chrono::high_resolution_clock::now()), path(path) {}
|
||||
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
|
||||
std::string path;
|
||||
};
|
||||
struct CompletionRequest {
|
||||
CompletionRequest(const lsRequestId& id,
|
||||
const lsTextDocumentIdentifier& document,
|
||||
const lsPosition& position,
|
||||
const OnComplete& on_complete)
|
||||
: id(id),
|
||||
document(document),
|
||||
position(position),
|
||||
CompletionRequest(const lsRequestId &id,
|
||||
const lsTextDocumentIdentifier &document,
|
||||
const lsPosition &position, const OnComplete &on_complete)
|
||||
: id(id), document(document), position(position),
|
||||
on_complete(on_complete) {}
|
||||
|
||||
lsRequestId id;
|
||||
@ -70,42 +65,40 @@ struct ClangCompleteManager {
|
||||
lsTextDocumentIdentifier document;
|
||||
};
|
||||
|
||||
ClangCompleteManager(Project* project,
|
||||
WorkingFiles* working_files,
|
||||
OnDiagnostic on_diagnostic,
|
||||
OnDropped on_dropped);
|
||||
ClangCompleteManager(Project *project, WorkingFiles *working_files,
|
||||
OnDiagnostic on_diagnostic, OnDropped on_dropped);
|
||||
|
||||
// Start a code completion at the given location. |on_complete| will run when
|
||||
// completion results are available. |on_complete| may run on any thread.
|
||||
void CodeComplete(const lsRequestId& request_id,
|
||||
const lsTextDocumentPositionParams& completion_location,
|
||||
const OnComplete& on_complete);
|
||||
void CodeComplete(const lsRequestId &request_id,
|
||||
const lsTextDocumentPositionParams &completion_location,
|
||||
const OnComplete &on_complete);
|
||||
// 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
|
||||
// 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.
|
||||
void NotifyEdit(const std::string& filename);
|
||||
void NotifyEdit(const std::string &filename);
|
||||
// Notify the completion manager that |filename| has been saved. This
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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 create_if_needed);
|
||||
|
||||
// Flushes all saved sessions with the supplied filename
|
||||
void FlushSession(const std::string& filename);
|
||||
void FlushSession(const std::string &filename);
|
||||
// Flushes all saved sessions
|
||||
void FlushAllSessions(void);
|
||||
|
||||
@ -114,8 +107,8 @@ struct ClangCompleteManager {
|
||||
const int kMaxCompletionSessions = 5;
|
||||
|
||||
// Global state.
|
||||
Project* project_;
|
||||
WorkingFiles* working_files_;
|
||||
Project *project_;
|
||||
WorkingFiles *working_files_;
|
||||
OnDiagnostic on_diagnostic_;
|
||||
OnDropped on_dropped_;
|
||||
|
||||
|
@ -68,7 +68,7 @@ std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
|
||||
const std::string &filepath, const std::vector<std::string> &args,
|
||||
const WorkingFiles::Snapshot &snapshot, bool diagnostic) {
|
||||
std::vector<const char *> Args;
|
||||
for (auto& arg : args)
|
||||
for (auto &arg : args)
|
||||
Args.push_back(arg.c_str());
|
||||
Args.push_back("-fallow-editor-placeholders");
|
||||
if (!diagnostic)
|
||||
@ -103,9 +103,8 @@ std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
|
||||
ret->PCHCO->getRawReader().getFormat(), &ErrUnit));
|
||||
};
|
||||
if (!CRC.RunSafely(parse)) {
|
||||
LOG_S(ERROR)
|
||||
<< "clang crashed for " << filepath << "\n"
|
||||
<< StringJoin(args, " ") + " -fsyntax-only";
|
||||
LOG_S(ERROR) << "clang crashed for " << filepath << "\n"
|
||||
<< StringJoin(args, " ") + " -fsyntax-only";
|
||||
return {};
|
||||
}
|
||||
if (!Unit && !ErrUnit)
|
||||
|
@ -7,9 +7,9 @@
|
||||
#include <llvm/Support/CrashRecoveryContext.h>
|
||||
|
||||
#include <memory>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
std::vector<clang::ASTUnit::RemappedFile>
|
||||
GetRemapped(const WorkingFiles::Snapshot &snapshot);
|
||||
@ -19,12 +19,12 @@ Range FromCharSourceRange(const clang::SourceManager &SM,
|
||||
clang::CharSourceRange R,
|
||||
llvm::sys::fs::UniqueID *UniqueID = nullptr);
|
||||
|
||||
Range FromCharRange(const clang::SourceManager &SM, const clang::LangOptions &LangOpts,
|
||||
clang::SourceRange R,
|
||||
Range FromCharRange(const clang::SourceManager &SM,
|
||||
const clang::LangOptions &LangOpts, clang::SourceRange R,
|
||||
llvm::sys::fs::UniqueID *UniqueID = nullptr);
|
||||
|
||||
Range FromTokenRange(const clang::SourceManager &SM, const clang::LangOptions &LangOpts,
|
||||
clang::SourceRange R,
|
||||
Range FromTokenRange(const clang::SourceManager &SM,
|
||||
const clang::LangOptions &LangOpts, clang::SourceRange R,
|
||||
llvm::sys::fs::UniqueID *UniqueID = nullptr);
|
||||
|
||||
struct ClangTranslationUnit {
|
||||
|
@ -10,7 +10,7 @@
|
||||
using namespace clang;
|
||||
using namespace llvm;
|
||||
|
||||
std::string FileName(const FileEntry& file) {
|
||||
std::string FileName(const FileEntry &file) {
|
||||
StringRef Name = file.tryGetRealPathName();
|
||||
if (Name.empty())
|
||||
Name = file.getName();
|
||||
@ -25,7 +25,7 @@ std::string FileName(const FileEntry& file) {
|
||||
}
|
||||
|
||||
// clang::BuiltinType::getName without PrintingPolicy
|
||||
const char* ClangBuiltinTypeName(int kind) {
|
||||
const char *ClangBuiltinTypeName(int kind) {
|
||||
switch (BuiltinType::Kind(kind)) {
|
||||
case BuiltinType::Void:
|
||||
return "void";
|
||||
|
@ -5,6 +5,6 @@
|
||||
#include <string>
|
||||
|
||||
// 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"
|
||||
|
||||
Config* g_config;
|
||||
Config *g_config;
|
||||
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::ClientCapability, snippetSupport);
|
||||
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
|
||||
MAKE_REFLECT_STRUCT(Config::Completion,
|
||||
caseSensitivity,
|
||||
dropOldRequests,
|
||||
detailedLabel,
|
||||
filterAndSort,
|
||||
includeBlacklist,
|
||||
includeMaxPathSize,
|
||||
includeSuffixWhitelist,
|
||||
MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, dropOldRequests,
|
||||
detailedLabel, filterAndSort, includeBlacklist,
|
||||
includeMaxPathSize, includeSuffixWhitelist,
|
||||
includeWhitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::Diagnostics,
|
||||
blacklist,
|
||||
frequencyMs,
|
||||
onParse,
|
||||
onType,
|
||||
whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onParse,
|
||||
onType, whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Index,
|
||||
attributeMakeCallsToCtor,
|
||||
blacklist,
|
||||
comments,
|
||||
enabled,
|
||||
onDidChange,
|
||||
reparseForDependency,
|
||||
threads,
|
||||
whitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::Index, attributeMakeCallsToCtor, blacklist,
|
||||
comments, enabled, onDidChange, reparseForDependency,
|
||||
threads, whitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
|
||||
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
|
||||
MAKE_REFLECT_STRUCT(Config,
|
||||
compilationDatabaseCommand,
|
||||
compilationDatabaseDirectory,
|
||||
cacheDirectory,
|
||||
cacheFormat,
|
||||
MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,
|
||||
compilationDatabaseDirectory, cacheDirectory, cacheFormat,
|
||||
|
||||
clang,
|
||||
client,
|
||||
codeLens,
|
||||
completion,
|
||||
diagnostics,
|
||||
highlight,
|
||||
index,
|
||||
largeFileSize,
|
||||
workspaceSymbol,
|
||||
xref);
|
||||
clang, client, codeLens, completion, diagnostics, highlight,
|
||||
index, largeFileSize, workspaceSymbol, xref);
|
||||
|
||||
extern Config* g_config;
|
||||
extern Config *g_config;
|
||||
thread_local extern int g_thread_id;
|
||||
|
@ -8,9 +8,9 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<std::string> GetFileContents(
|
||||
const std::string& path,
|
||||
std::unordered_map<std::string, FileContents>* file_contents) {
|
||||
std::optional<std::string>
|
||||
GetFileContents(const std::string &path,
|
||||
std::unordered_map<std::string, FileContents> *file_contents) {
|
||||
auto it = file_contents->find(path);
|
||||
if (it == file_contents->end()) {
|
||||
std::optional<std::string> content = ReadContent(path);
|
||||
@ -21,9 +21,9 @@ std::optional<std::string> GetFileContents(
|
||||
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) {
|
||||
line_offsets_.push_back(0);
|
||||
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<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)
|
||||
return content.substr(*start_offset, *end_offset - *start_offset);
|
||||
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);
|
||||
auto it = state.find(file);
|
||||
if (it != state.end())
|
||||
@ -57,9 +57,9 @@ VFS::State VFS::Get(const std::string& file) {
|
||||
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);
|
||||
State& st = state[file];
|
||||
State &st = state[file];
|
||||
if (st.stage < stage) {
|
||||
st.owner = owner;
|
||||
st.stage = stage;
|
||||
@ -68,9 +68,9 @@ bool VFS::Mark(const std::string& file, int owner, int stage) {
|
||||
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);
|
||||
State& st = state[file];
|
||||
State &st = state[file];
|
||||
if (st.timestamp < ts) {
|
||||
st.timestamp = ts;
|
||||
return true;
|
||||
@ -78,23 +78,23 @@ bool VFS::Stamp(const std::string& file, int64_t ts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void VFS::ResetLocked(const std::string& file) {
|
||||
State& st = state[file];
|
||||
void VFS::ResetLocked(const std::string &file) {
|
||||
State &st = state[file];
|
||||
if (st.owner == 0 || st.owner == g_thread_id)
|
||||
st.stage = 0;
|
||||
}
|
||||
|
||||
void VFS::Reset(const std::string& file) {
|
||||
void VFS::Reset(const std::string &file) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
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) {}
|
||||
|
||||
IndexFile* FileConsumer::TryConsumeFile(
|
||||
const clang::FileEntry& File,
|
||||
std::unordered_map<std::string, FileContents>* file_contents_map) {
|
||||
IndexFile *FileConsumer::TryConsumeFile(
|
||||
const clang::FileEntry &File,
|
||||
std::unordered_map<std::string, FileContents> *file_contents_map) {
|
||||
auto UniqueID = File.getUniqueID();
|
||||
auto it = local_.find(UniqueID);
|
||||
if (it != local_.end())
|
||||
@ -115,13 +115,14 @@ IndexFile* FileConsumer::TryConsumeFile(
|
||||
return nullptr;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<IndexFile>> FileConsumer::TakeLocalState() {
|
||||
std::vector<std::unique_ptr<IndexFile>> result;
|
||||
for (auto& entry : local_) {
|
||||
for (auto &entry : local_) {
|
||||
if (entry.second)
|
||||
result.push_back(std::move(entry.second));
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ struct IndexFile;
|
||||
|
||||
struct FileContents {
|
||||
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<std::string> ContentsInRange(Range range) const;
|
||||
@ -34,23 +34,22 @@ struct VFS {
|
||||
mutable std::unordered_map<std::string, State> state;
|
||||
mutable std::mutex mutex;
|
||||
|
||||
State Get(const std::string& file);
|
||||
bool Mark(const std::string& file, int owner, int stage);
|
||||
bool Stamp(const std::string& file, int64_t ts);
|
||||
void ResetLocked(const std::string& file);
|
||||
void Reset(const std::string& file);
|
||||
State Get(const std::string &file);
|
||||
bool Mark(const std::string &file, int owner, int stage);
|
||||
bool Stamp(const std::string &file, int64_t ts);
|
||||
void ResetLocked(const std::string &file);
|
||||
void Reset(const std::string &file);
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<llvm::sys::fs::UniqueID> {
|
||||
template <> struct hash<llvm::sys::fs::UniqueID> {
|
||||
std::size_t operator()(llvm::sys::fs::UniqueID ID) const {
|
||||
size_t ret = ID.getDevice();
|
||||
hash_combine(ret, ID.getFile());
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
// 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
|
||||
@ -60,7 +59,7 @@ struct hash<llvm::sys::fs::UniqueID> {
|
||||
// The indexer does this because header files do not have their own translation
|
||||
// units but we still want to index them.
|
||||
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
|
||||
// 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
|
||||
// variable since it is large and we do not want to copy it.
|
||||
IndexFile* TryConsumeFile(const clang::FileEntry& file,
|
||||
std::unordered_map<std::string, FileContents>* file_contents);
|
||||
IndexFile *
|
||||
TryConsumeFile(const clang::FileEntry &file,
|
||||
std::unordered_map<std::string, FileContents> *file_contents);
|
||||
|
||||
// Returns and passes ownership of all local state.
|
||||
std::vector<std::unique_ptr<IndexFile>> TakeLocalState();
|
||||
|
||||
private:
|
||||
std::unordered_map<llvm::sys::fs::UniqueID, std::unique_ptr<IndexFile>> local_;
|
||||
VFS* vfs_;
|
||||
private:
|
||||
std::unordered_map<llvm::sys::fs::UniqueID, std::unique_ptr<IndexFile>>
|
||||
local_;
|
||||
VFS *vfs_;
|
||||
std::string parse_file_;
|
||||
int thread_id_;
|
||||
};
|
||||
|
@ -6,10 +6,8 @@ using namespace llvm;
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
void GetFilesInFolder(std::string folder,
|
||||
bool recursive,
|
||||
bool dir_prefix,
|
||||
const std::function<void(const std::string&)>& handler) {
|
||||
void GetFilesInFolder(std::string folder, bool recursive, bool dir_prefix,
|
||||
const std::function<void(const std::string &)> &handler) {
|
||||
EnsureEndsInSlash(folder);
|
||||
sys::fs::file_status Status;
|
||||
if (sys::fs::status(folder, Status, true))
|
||||
@ -20,7 +18,7 @@ void GetFilesInFolder(std::string folder,
|
||||
std::set<sys::fs::UniqueID> seen{Status.getUniqueID()};
|
||||
while (curr.size() || succ.size()) {
|
||||
if (curr.empty()) {
|
||||
for (auto& it : succ)
|
||||
for (auto &it : succ)
|
||||
if (!seen.count(it.second.getUniqueID()))
|
||||
curr.push_back(std::move(it.first));
|
||||
succ.clear();
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "fuzzy_match.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
enum CharClass { Other, Lower, Upper };
|
||||
@ -17,7 +17,7 @@ CharClass GetCharClass(int c) {
|
||||
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()) {
|
||||
*class_set = 0;
|
||||
return;
|
||||
@ -41,7 +41,7 @@ void CalculateRoles(std::string_view s, int roles[], int* class_set) {
|
||||
}
|
||||
roles[s.size() - 1] = fn();
|
||||
}
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
int FuzzyMatcher::MissScore(int j, bool last) {
|
||||
int s = -3;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <string_view>
|
||||
|
||||
class FuzzyMatcher {
|
||||
public:
|
||||
public:
|
||||
constexpr static int kMaxPat = 100;
|
||||
constexpr static int kMaxText = 200;
|
||||
// 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);
|
||||
int Match(std::string_view text);
|
||||
|
||||
private:
|
||||
private:
|
||||
int case_sensitivity;
|
||||
std::string pat;
|
||||
std::string_view text;
|
||||
|
@ -19,7 +19,7 @@ struct CompletionCandidate {
|
||||
lsCompletionItem completion_item;
|
||||
};
|
||||
|
||||
std::string ElideLongPath(const std::string& path) {
|
||||
std::string ElideLongPath(const std::string &path) {
|
||||
if (g_config->completion.includeMaxPathSize <= 0)
|
||||
return path;
|
||||
|
||||
@ -30,8 +30,8 @@ std::string ElideLongPath(const std::string& path) {
|
||||
return ".." + path.substr(start + 2);
|
||||
}
|
||||
|
||||
size_t TrimCommonPathPrefix(const std::string& result,
|
||||
const std::string& trimmer) {
|
||||
size_t TrimCommonPathPrefix(const std::string &result,
|
||||
const std::string &trimmer) {
|
||||
#ifdef _WIN32
|
||||
std::string s = result, t = trimmer;
|
||||
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.
|
||||
bool TrimPath(Project* project,
|
||||
const std::string& project_root,
|
||||
std::string* insert_path) {
|
||||
bool TrimPath(Project *project, const std::string &project_root,
|
||||
std::string *insert_path) {
|
||||
size_t start = TrimCommonPathPrefix(*insert_path, project_root);
|
||||
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));
|
||||
|
||||
for (auto& include_dir : project->angle_include_directories) {
|
||||
for (auto &include_dir : project->angle_include_directories) {
|
||||
auto len = TrimCommonPathPrefix(*insert_path, include_dir);
|
||||
if (len > start) {
|
||||
start = len;
|
||||
@ -67,12 +66,11 @@ bool TrimPath(Project* project,
|
||||
return angle;
|
||||
}
|
||||
|
||||
lsCompletionItem BuildCompletionItem(const std::string& path,
|
||||
bool use_angle_brackets,
|
||||
bool is_stl) {
|
||||
lsCompletionItem BuildCompletionItem(const std::string &path,
|
||||
bool use_angle_brackets, bool is_stl) {
|
||||
lsCompletionItem item;
|
||||
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->newText = path;
|
||||
item.insertTextFormat = lsInsertTextFormat::PlainText;
|
||||
@ -87,9 +85,9 @@ lsCompletionItem BuildCompletionItem(const std::string& path,
|
||||
return item;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
IncludeComplete::IncludeComplete(Project* project)
|
||||
IncludeComplete::IncludeComplete(Project *project)
|
||||
: is_scanning(false), project_(project) {}
|
||||
|
||||
void IncludeComplete::Rescan() {
|
||||
@ -102,8 +100,9 @@ void IncludeComplete::Rescan() {
|
||||
|
||||
if (!match_ && (g_config->completion.includeWhitelist.size() ||
|
||||
g_config->completion.includeBlacklist.size()))
|
||||
match_ = std::make_unique<GroupMatch>(g_config->completion.includeWhitelist,
|
||||
g_config->completion.includeBlacklist);
|
||||
match_ =
|
||||
std::make_unique<GroupMatch>(g_config->completion.includeWhitelist,
|
||||
g_config->completion.includeBlacklist);
|
||||
|
||||
is_scanning = true;
|
||||
std::thread([this]() {
|
||||
@ -111,17 +110,18 @@ void IncludeComplete::Rescan() {
|
||||
Timer timer("include", "scan include paths");
|
||||
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*/);
|
||||
for (const std::string& dir : project_->angle_include_directories)
|
||||
for (const std::string &dir : project_->angle_include_directories)
|
||||
InsertIncludesFromDirectory(dir, true /*use_angle_brackets*/);
|
||||
|
||||
is_scanning = false;
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
|
||||
lsCompletionItem&& item) {
|
||||
void IncludeComplete::InsertCompletionItem(const std::string &absolute_path,
|
||||
lsCompletionItem &&item) {
|
||||
if (inserted_paths.insert({item.detail, inserted_paths.size()}).second) {
|
||||
completion_items.push_back(item);
|
||||
// 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;
|
||||
}
|
||||
} else {
|
||||
lsCompletionItem& inserted_item =
|
||||
lsCompletionItem &inserted_item =
|
||||
completion_items[inserted_paths[item.detail]];
|
||||
// Update |use_angle_brackets_|, prefer quotes.
|
||||
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))
|
||||
return;
|
||||
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);
|
||||
for (CompletionCandidate& result : results)
|
||||
for (CompletionCandidate &result : results)
|
||||
InsertCompletionItem(result.absolute_path,
|
||||
std::move(result.completion_item));
|
||||
}
|
||||
|
||||
std::optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(
|
||||
const std::string& absolute_path) {
|
||||
std::optional<lsCompletionItem>
|
||||
IncludeComplete::FindCompletionItemForAbsolutePath(
|
||||
const std::string &absolute_path) {
|
||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||
|
||||
auto it = absolute_path_to_completion_item.find(absolute_path);
|
||||
|
@ -10,26 +10,26 @@ struct GroupMatch;
|
||||
struct Project;
|
||||
|
||||
struct IncludeComplete {
|
||||
IncludeComplete(Project* project);
|
||||
IncludeComplete(Project *project);
|
||||
|
||||
// Starts scanning directories. Clears existing cache.
|
||||
void Rescan();
|
||||
|
||||
// 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
|
||||
// blocking function and should be run off the querydb thread.
|
||||
void InsertIncludesFromDirectory(std::string directory,
|
||||
bool use_angle_brackets);
|
||||
|
||||
std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
|
||||
const std::string& absolute_path);
|
||||
std::optional<lsCompletionItem>
|
||||
FindCompletionItemForAbsolutePath(const std::string &absolute_path);
|
||||
|
||||
// Insert item to |completion_items|.
|
||||
// Update |absolute_path_to_completion_item| and |inserted_paths|.
|
||||
void InsertCompletionItem(const std::string& absolute_path,
|
||||
lsCompletionItem&& item);
|
||||
void InsertCompletionItem(const std::string &absolute_path,
|
||||
lsCompletionItem &&item);
|
||||
|
||||
// Guards |completion_items| when |is_scanning| is true.
|
||||
std::mutex completion_items_mutex;
|
||||
@ -44,6 +44,6 @@ struct IncludeComplete {
|
||||
std::unordered_map<std::string, int> inserted_paths;
|
||||
|
||||
// Cached references
|
||||
Project* project_;
|
||||
Project *project_;
|
||||
std::unique_ptr<GroupMatch> match_;
|
||||
};
|
||||
|
250
src/indexer.cc
250
src/indexer.cc
@ -21,9 +21,9 @@ using ccls::Intern;
|
||||
using namespace clang;
|
||||
using llvm::Timer;
|
||||
|
||||
#include <algorithm>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
|
||||
@ -40,14 +40,14 @@ struct IndexParam {
|
||||
std::string short_name;
|
||||
std::string qualified;
|
||||
};
|
||||
std::unordered_map<const Decl*, DeclInfo> Decl2Info;
|
||||
std::unordered_map<const Decl *, DeclInfo> Decl2Info;
|
||||
|
||||
ASTUnit& Unit;
|
||||
ASTContext* Ctx;
|
||||
ASTUnit &Unit;
|
||||
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) {}
|
||||
|
||||
IndexFile *ConsumeFile(const FileEntry &File) {
|
||||
@ -63,7 +63,7 @@ struct IndexParam {
|
||||
// Set modification time.
|
||||
std::optional<int64_t> write_time = LastWriteTime(file_name);
|
||||
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)
|
||||
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);
|
||||
if (invalid)
|
||||
return "";
|
||||
return Buf.substr(BInfo.second, EInfo.second + Lexer::MeasureTokenLength(
|
||||
ELoc, SM, LangOpts) -
|
||||
BInfo.second);
|
||||
return Buf.substr(BInfo.second,
|
||||
EInfo.second +
|
||||
Lexer::MeasureTokenLength(ELoc, SM, LangOpts) -
|
||||
BInfo.second);
|
||||
}
|
||||
|
||||
SymbolKind GetSymbolKind(const Decl* D) {
|
||||
SymbolKind GetSymbolKind(const Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
case Decl::TranslationUnit:
|
||||
return SymbolKind::File;
|
||||
@ -136,46 +137,46 @@ SymbolKind GetSymbolKind(const Decl* D) {
|
||||
|
||||
LanguageId GetDeclLanguage(const Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
default:
|
||||
return LanguageId::C;
|
||||
case Decl::ImplicitParam:
|
||||
case Decl::ObjCAtDefsField:
|
||||
case Decl::ObjCCategory:
|
||||
case Decl::ObjCCategoryImpl:
|
||||
case Decl::ObjCCompatibleAlias:
|
||||
case Decl::ObjCImplementation:
|
||||
case Decl::ObjCInterface:
|
||||
case Decl::ObjCIvar:
|
||||
case Decl::ObjCMethod:
|
||||
case Decl::ObjCProperty:
|
||||
case Decl::ObjCPropertyImpl:
|
||||
case Decl::ObjCProtocol:
|
||||
case Decl::ObjCTypeParam:
|
||||
return LanguageId::ObjC;
|
||||
case Decl::CXXConstructor:
|
||||
case Decl::CXXConversion:
|
||||
case Decl::CXXDestructor:
|
||||
case Decl::CXXMethod:
|
||||
case Decl::CXXRecord:
|
||||
case Decl::ClassTemplate:
|
||||
case Decl::ClassTemplatePartialSpecialization:
|
||||
case Decl::ClassTemplateSpecialization:
|
||||
case Decl::Friend:
|
||||
case Decl::FriendTemplate:
|
||||
case Decl::FunctionTemplate:
|
||||
case Decl::LinkageSpec:
|
||||
case Decl::Namespace:
|
||||
case Decl::NamespaceAlias:
|
||||
case Decl::NonTypeTemplateParm:
|
||||
case Decl::StaticAssert:
|
||||
case Decl::TemplateTemplateParm:
|
||||
case Decl::TemplateTypeParm:
|
||||
case Decl::UnresolvedUsingTypename:
|
||||
case Decl::UnresolvedUsingValue:
|
||||
case Decl::Using:
|
||||
case Decl::UsingDirective:
|
||||
case Decl::UsingShadow:
|
||||
return LanguageId::Cpp;
|
||||
default:
|
||||
return LanguageId::C;
|
||||
case Decl::ImplicitParam:
|
||||
case Decl::ObjCAtDefsField:
|
||||
case Decl::ObjCCategory:
|
||||
case Decl::ObjCCategoryImpl:
|
||||
case Decl::ObjCCompatibleAlias:
|
||||
case Decl::ObjCImplementation:
|
||||
case Decl::ObjCInterface:
|
||||
case Decl::ObjCIvar:
|
||||
case Decl::ObjCMethod:
|
||||
case Decl::ObjCProperty:
|
||||
case Decl::ObjCPropertyImpl:
|
||||
case Decl::ObjCProtocol:
|
||||
case Decl::ObjCTypeParam:
|
||||
return LanguageId::ObjC;
|
||||
case Decl::CXXConstructor:
|
||||
case Decl::CXXConversion:
|
||||
case Decl::CXXDestructor:
|
||||
case Decl::CXXMethod:
|
||||
case Decl::CXXRecord:
|
||||
case Decl::ClassTemplate:
|
||||
case Decl::ClassTemplatePartialSpecialization:
|
||||
case Decl::ClassTemplateSpecialization:
|
||||
case Decl::Friend:
|
||||
case Decl::FriendTemplate:
|
||||
case Decl::FunctionTemplate:
|
||||
case Decl::LinkageSpec:
|
||||
case Decl::Namespace:
|
||||
case Decl::NamespaceAlias:
|
||||
case Decl::NonTypeTemplateParm:
|
||||
case Decl::StaticAssert:
|
||||
case Decl::TemplateTemplateParm:
|
||||
case Decl::TemplateTypeParm:
|
||||
case Decl::UnresolvedUsingTypename:
|
||||
case Decl::UnresolvedUsingValue:
|
||||
case Decl::Using:
|
||||
case Decl::UsingDirective:
|
||||
case Decl::UsingShadow:
|
||||
return LanguageId::Cpp;
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +188,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
|
||||
BaseType = PTy->getPointeeType();
|
||||
else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
|
||||
BaseType = BPy->getPointeeType();
|
||||
else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
|
||||
else if (const ArrayType *ATy = dyn_cast<ArrayType>(BaseType))
|
||||
BaseType = ATy->getElementType();
|
||||
else if (const VectorType *VTy = BaseType->getAs<VectorType>())
|
||||
BaseType = VTy->getElementType();
|
||||
@ -200,8 +201,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
|
||||
BaseType = ATy->getDeducedType();
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return BaseType;
|
||||
@ -210,7 +210,7 @@ QualType GetBaseType(QualType T, bool deduce_auto) {
|
||||
const Decl *GetTypeDecl(QualType T, bool *specialization = nullptr) {
|
||||
Decl *D = nullptr;
|
||||
T = GetBaseType(T.getUnqualifiedType(), true);
|
||||
const Type* TP = T.getTypePtrOrNull();
|
||||
const Type *TP = T.getTypePtrOrNull();
|
||||
if (!TP)
|
||||
return nullptr;
|
||||
|
||||
@ -254,7 +254,7 @@ try_again:
|
||||
D = cast<InjectedClassNameType>(TP)->getDecl();
|
||||
break;
|
||||
|
||||
// FIXME: Template type parameters!
|
||||
// FIXME: Template type parameters!
|
||||
|
||||
case Type::Elaborated:
|
||||
TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull();
|
||||
@ -266,19 +266,19 @@ try_again:
|
||||
return D;
|
||||
}
|
||||
|
||||
const Decl* GetSpecialized(const Decl* D) {
|
||||
const Decl *GetSpecialized(const Decl *D) {
|
||||
if (!D)
|
||||
return D;
|
||||
Decl *Template = nullptr;
|
||||
if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
|
||||
if (const ClassTemplatePartialSpecializationDecl *PartialSpec
|
||||
= dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
|
||||
if (const ClassTemplatePartialSpecializationDecl *PartialSpec =
|
||||
dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
|
||||
Template = PartialSpec->getSpecializedTemplate();
|
||||
else if (const ClassTemplateSpecializationDecl *ClassSpec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
|
||||
else if (const ClassTemplateSpecializationDecl *ClassSpec =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *> Result
|
||||
= ClassSpec->getSpecializedTemplateOrPartial();
|
||||
ClassTemplatePartialSpecializationDecl *>
|
||||
Result = ClassSpec->getSpecializedTemplateOrPartial();
|
||||
if (Result.is<ClassTemplateDecl *>())
|
||||
Template = Result.get<ClassTemplateDecl *>();
|
||||
else
|
||||
@ -293,8 +293,8 @@ const Decl* GetSpecialized(const Decl* D) {
|
||||
} else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
||||
if (Var->isStaticDataMember())
|
||||
Template = Var->getInstantiatedFromStaticDataMember();
|
||||
} else if (const RedeclarableTemplateDecl *Tmpl
|
||||
= dyn_cast<RedeclarableTemplateDecl>(D))
|
||||
} else if (const RedeclarableTemplateDecl *Tmpl =
|
||||
dyn_cast<RedeclarableTemplateDecl>(D))
|
||||
Template = Tmpl->getInstantiatedFromMemberTemplate();
|
||||
else
|
||||
return nullptr;
|
||||
@ -302,7 +302,7 @@ const Decl* GetSpecialized(const Decl* D) {
|
||||
}
|
||||
|
||||
bool ValidateRecord(const RecordDecl *RD) {
|
||||
for (const auto *I : RD->fields()){
|
||||
for (const auto *I : RD->fields()) {
|
||||
QualType FQT = I->getType();
|
||||
if (FQT->isIncompleteType() || FQT->isDependentType())
|
||||
return false;
|
||||
@ -317,12 +317,13 @@ bool ValidateRecord(const RecordDecl *RD) {
|
||||
class IndexDataConsumer : public index::IndexDataConsumer {
|
||||
public:
|
||||
ASTContext *Ctx;
|
||||
IndexParam& param;
|
||||
IndexParam ¶m;
|
||||
|
||||
std::string GetComment(const Decl* D) {
|
||||
std::string GetComment(const Decl *D) {
|
||||
SourceManager &SM = Ctx->getSourceManager();
|
||||
const RawComment *RC = Ctx->getRawCommentForAnyRedecl(D);
|
||||
if (!RC) return "";
|
||||
if (!RC)
|
||||
return "";
|
||||
StringRef Raw = RC->getRawText(Ctx->getSourceManager());
|
||||
SourceRange R = RC->getSourceRange();
|
||||
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(R.getBegin());
|
||||
@ -422,7 +423,7 @@ public:
|
||||
return PP;
|
||||
}
|
||||
|
||||
static void SimplifyAnonymous(std::string& name) {
|
||||
static void SimplifyAnonymous(std::string &name) {
|
||||
for (std::string::size_type i = 0;;) {
|
||||
if ((i = name.find("(anonymous ", i)) == std::string::npos)
|
||||
break;
|
||||
@ -476,7 +477,7 @@ public:
|
||||
void SetVarName(const Decl *D, std::string_view short_name,
|
||||
std::string_view qualified, IndexVar::Def &def) {
|
||||
QualType T;
|
||||
const Expr* init = nullptr;
|
||||
const Expr *init = nullptr;
|
||||
bool binding = false;
|
||||
if (auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
T = VD->getType();
|
||||
@ -496,7 +497,7 @@ public:
|
||||
PrintingPolicy PP = GetDefaultPolicy();
|
||||
T.print(OS, PP);
|
||||
if (Str.size() &&
|
||||
(Str.back() != ' ' && Str.back() != '*' && Str.back() != '&'))
|
||||
(Str.back() != ' ' && Str.back() != '*' && Str.back() != '&'))
|
||||
Str += ' ';
|
||||
def.qual_name_offset = Str.size();
|
||||
def.short_name_offset = Str.size() + qualified.size() - short_name.size();
|
||||
@ -508,7 +509,7 @@ public:
|
||||
}
|
||||
if (init) {
|
||||
SourceManager &SM = Ctx->getSourceManager();
|
||||
const LangOptions& Lang = Ctx->getLangOpts();
|
||||
const LangOptions &Lang = Ctx->getLangOpts();
|
||||
SourceRange R = SM.getExpansionRange(init->getSourceRange())
|
||||
#if LLVM_VERSION_MAJOR >= 7
|
||||
.getAsRange()
|
||||
@ -533,7 +534,8 @@ public:
|
||||
void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
|
||||
SourceLocation Spell) const {
|
||||
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
|
||||
if (!FE) return;
|
||||
if (!FE)
|
||||
return;
|
||||
auto UID = FE->getUniqueID();
|
||||
auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID);
|
||||
if (inserted) {
|
||||
@ -565,10 +567,8 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
IndexDataConsumer(IndexParam& param) : param(param) {}
|
||||
void initialize(ASTContext &Ctx) override {
|
||||
this->Ctx = param.Ctx = &Ctx;
|
||||
}
|
||||
IndexDataConsumer(IndexParam ¶m) : param(param) {}
|
||||
void initialize(ASTContext &Ctx) override { this->Ctx = param.Ctx = &Ctx; }
|
||||
bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
|
||||
ArrayRef<index::SymbolRelation> Relations,
|
||||
#if LLVM_VERSION_MAJOR >= 7
|
||||
@ -615,7 +615,7 @@ public:
|
||||
if (!db)
|
||||
return true;
|
||||
|
||||
const Decl* OrigD = ASTNode.OrigD;
|
||||
const Decl *OrigD = ASTNode.OrigD;
|
||||
const DeclContext *SemDC = OrigD->getDeclContext();
|
||||
const DeclContext *LexDC = ASTNode.ContainerDC;
|
||||
Role role = static_cast<Role>(Roles);
|
||||
@ -629,7 +629,7 @@ public:
|
||||
IndexType *type = nullptr;
|
||||
IndexVar *var = nullptr;
|
||||
SymbolKind kind = GetSymbolKind(D);
|
||||
IndexParam::DeclInfo* info;
|
||||
IndexParam::DeclInfo *info;
|
||||
Usr usr = GetUsr(D, &info);
|
||||
|
||||
auto do_def_decl = [&](auto *entity) {
|
||||
@ -687,7 +687,7 @@ public:
|
||||
if (type->def.detailed_name[0] == '\0')
|
||||
SetName(OrigD, info->short_name, info->qualified, type->def);
|
||||
if (is_def || is_decl) {
|
||||
const Decl* DC = cast<Decl>(SemDC);
|
||||
const Decl *DC = cast<Decl>(SemDC);
|
||||
if (GetSymbolKind(DC) == SymbolKind::Type)
|
||||
db->ToType(GetUsr(DC)).def.types.push_back(usr);
|
||||
}
|
||||
@ -717,7 +717,7 @@ public:
|
||||
db->ToType(usr1).instances.push_back(usr);
|
||||
} else {
|
||||
for (const Decl *D1 = GetTypeDecl(T); D1; D1 = GetSpecialized(D1)) {
|
||||
IndexParam::DeclInfo* info1;
|
||||
IndexParam::DeclInfo *info1;
|
||||
Usr usr1 = GetUsr(D1, &info1);
|
||||
auto it = db->usr2type.find(usr1);
|
||||
if (it != db->usr2type.end()) {
|
||||
@ -725,10 +725,11 @@ public:
|
||||
it->second.instances.push_back(usr);
|
||||
break;
|
||||
}
|
||||
// e.g. TemplateTypeParmDecl is not handled by handleDeclOccurence.
|
||||
// e.g. TemplateTypeParmDecl is not handled by
|
||||
// handleDeclOccurence.
|
||||
SourceRange R1 = D1->getSourceRange();
|
||||
if (SM.getFileID(R1.getBegin()) == LocFID) {
|
||||
IndexType& type1 = db->ToType(usr1);
|
||||
IndexType &type1 = db->ToType(usr1);
|
||||
SourceLocation L1 = D1->getLocation();
|
||||
type1.def.spell = GetUse(db, FromTokenRange(SM, Lang, {L1, L1}),
|
||||
SemDC, Role::Definition);
|
||||
@ -932,7 +933,7 @@ public:
|
||||
if (auto *ND = dyn_cast<NamedDecl>(D)) {
|
||||
SmallVector<const NamedDecl *, 8> OverDecls;
|
||||
Ctx->getOverriddenMethods(ND, OverDecls);
|
||||
for (const auto* ND1 : OverDecls) {
|
||||
for (const auto *ND1 : OverDecls) {
|
||||
Usr usr1 = GetUsr(ND1);
|
||||
func->def.bases.push_back(usr1);
|
||||
db->ToFunc(usr1).derived.push_back(usr);
|
||||
@ -985,10 +986,10 @@ public:
|
||||
};
|
||||
|
||||
class IndexPPCallbacks : public PPCallbacks {
|
||||
SourceManager& SM;
|
||||
IndexParam& param;
|
||||
SourceManager &SM;
|
||||
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();
|
||||
SmallString<256> USR("@macro@");
|
||||
USR += Name;
|
||||
@ -1025,13 +1026,13 @@ public:
|
||||
}
|
||||
void MacroDefined(const Token &Tok, const MacroDirective *MD) override {
|
||||
llvm::sys::fs::UniqueID UniqueID;
|
||||
const LangOptions& Lang = param.Ctx->getLangOpts();
|
||||
const LangOptions &Lang = param.Ctx->getLangOpts();
|
||||
SourceLocation L = MD->getLocation();
|
||||
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
|
||||
if (!FE)
|
||||
return;
|
||||
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
||||
auto[Name, usr] = GetMacro(Tok);
|
||||
auto [Name, usr] = GetMacro(Tok);
|
||||
IndexVar &var = db->ToVar(usr);
|
||||
auto range = FromTokenRange(SM, Lang, {L, L}, &UniqueID);
|
||||
var.def.kind = lsSymbolKind::Macro;
|
||||
@ -1053,15 +1054,15 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
void MacroExpands(const Token &Tok, const MacroDefinition &MD,
|
||||
SourceRange R, const MacroArgs *Args) override {
|
||||
void MacroExpands(const Token &Tok, const MacroDefinition &MD, SourceRange R,
|
||||
const MacroArgs *Args) override {
|
||||
llvm::sys::fs::UniqueID UniqueID;
|
||||
SourceLocation L = SM.getSpellingLoc(R.getBegin());
|
||||
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
|
||||
if (!FE)
|
||||
return;
|
||||
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
||||
auto[Name, usr] = GetMacro(Tok);
|
||||
auto [Name, usr] = GetMacro(Tok);
|
||||
IndexVar &var = db->ToVar(usr);
|
||||
var.uses.push_back(
|
||||
{{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
|
||||
@ -1085,17 +1086,19 @@ public:
|
||||
};
|
||||
|
||||
class IndexFrontendAction : public ASTFrontendAction {
|
||||
IndexParam& param;
|
||||
IndexParam ¶m;
|
||||
|
||||
public:
|
||||
IndexFrontendAction(IndexParam& param) : param(param) {}
|
||||
IndexFrontendAction(IndexParam ¶m) : param(param) {}
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override {
|
||||
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>();
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
const int IndexFile::kMajorVersion = 17;
|
||||
const int IndexFile::kMinorVersion = 1;
|
||||
@ -1104,21 +1107,21 @@ IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
|
||||
const std::string &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);
|
||||
if (inserted)
|
||||
it->second.usr = usr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
IndexType& IndexFile::ToType(Usr usr) {
|
||||
IndexType &IndexFile::ToType(Usr usr) {
|
||||
auto [it, inserted] = usr2type.try_emplace(usr);
|
||||
if (inserted)
|
||||
it->second.usr = usr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
IndexVar& IndexFile::ToVar(Usr usr) {
|
||||
IndexVar &IndexFile::ToVar(Usr usr) {
|
||||
auto [it, inserted] = usr2var.try_emplace(usr);
|
||||
if (inserted)
|
||||
it->second.usr = usr;
|
||||
@ -1129,8 +1132,7 @@ std::string IndexFile::ToString() {
|
||||
return ccls::Serialize(SerializeFormat::Json, *this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Uniquify(std::vector<T>& a) {
|
||||
template <typename T> void Uniquify(std::vector<T> &a) {
|
||||
std::unordered_set<T> seen;
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < a.size(); i++)
|
||||
@ -1140,21 +1142,19 @@ void Uniquify(std::vector<T>& a) {
|
||||
}
|
||||
|
||||
namespace ccls::idx {
|
||||
std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
VFS* vfs,
|
||||
const std::string& opt_wdir,
|
||||
const std::string& file,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<FileContents>& file_contents) {
|
||||
std::vector<std::unique_ptr<IndexFile>>
|
||||
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
|
||||
const std::vector<std::string> &args,
|
||||
const std::vector<FileContents> &file_contents) {
|
||||
if (!g_config->index.enabled)
|
||||
return {};
|
||||
|
||||
std::vector<const char *> Args;
|
||||
for (auto& arg: args)
|
||||
for (auto &arg : args)
|
||||
Args.push_back(arg.c_str());
|
||||
auto PCHCO = std::make_shared<PCHContainerOperations>();
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine>
|
||||
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
|
||||
CompilerInstance::createDiagnostics(new DiagnosticOptions));
|
||||
std::shared_ptr<CompilerInvocation> CI =
|
||||
createInvocationFromCommandLine(Args, Diags);
|
||||
if (!CI)
|
||||
@ -1212,34 +1212,34 @@ std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
return {};
|
||||
}
|
||||
|
||||
const SourceManager& SM = Unit->getSourceManager();
|
||||
const FileEntry* FE = SM.getFileEntryForID(SM.getMainFileID());
|
||||
IndexFile* main_file = param.ConsumeFile(*FE);
|
||||
const SourceManager &SM = Unit->getSourceManager();
|
||||
const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
|
||||
IndexFile *main_file = param.ConsumeFile(*FE);
|
||||
std::unordered_map<std::string, int> inc_to_line;
|
||||
if (main_file)
|
||||
for (auto& inc : main_file->includes)
|
||||
for (auto &inc : main_file->includes)
|
||||
inc_to_line[inc.resolved_path] = inc.line;
|
||||
|
||||
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->args = args;
|
||||
for (auto &[_, it] : entry->uid2lid_and_path)
|
||||
entry->lid2path.emplace_back(it.first, std::move(it.second));
|
||||
entry->uid2lid_and_path.clear();
|
||||
for (auto& it : entry->usr2func) {
|
||||
for (auto &it : entry->usr2func) {
|
||||
// e.g. declaration + out-of-line definition
|
||||
Uniquify(it.second.derived);
|
||||
Uniquify(it.second.uses);
|
||||
}
|
||||
for (auto& it : entry->usr2type) {
|
||||
for (auto &it : entry->usr2type) {
|
||||
Uniquify(it.second.derived);
|
||||
Uniquify(it.second.uses);
|
||||
// e.g. declaration + out-of-line definition
|
||||
Uniquify(it.second.def.bases);
|
||||
Uniquify(it.second.def.funcs);
|
||||
}
|
||||
for (auto& it : entry->usr2var)
|
||||
for (auto &it : entry->usr2var)
|
||||
Uniquify(it.second.uses);
|
||||
|
||||
if (main_file) {
|
||||
@ -1270,7 +1270,7 @@ std::vector<std::unique_ptr<IndexFile>> Index(
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace ccls::idx
|
||||
|
||||
// |SymbolRef| is serialized this way.
|
||||
// |Use| also uses this though it has an extra field |file|,
|
||||
@ -1306,10 +1306,10 @@ void Reflect(Writer &vis, Reference &v) {
|
||||
}
|
||||
}
|
||||
|
||||
void Reflect(Reader& vis, Use& v) {
|
||||
void Reflect(Reader &vis, Use &v) {
|
||||
if (vis.Format() == SerializeFormat::Json) {
|
||||
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);
|
||||
s = strchr(s, '|');
|
||||
v.usr = strtoull(s + 1, &s, 10);
|
||||
@ -1318,11 +1318,11 @@ void Reflect(Reader& vis, Use& v) {
|
||||
if (*s == '|')
|
||||
v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
|
||||
} else {
|
||||
Reflect(vis, static_cast<Reference&>(v));
|
||||
Reflect(vis, static_cast<Reference &>(v));
|
||||
Reflect(vis, v.file_id);
|
||||
}
|
||||
}
|
||||
void Reflect(Writer& vis, Use& v) {
|
||||
void Reflect(Writer &vis, Use &v) {
|
||||
if (vis.Format() == SerializeFormat::Json) {
|
||||
char buf[99];
|
||||
if (v.file_id == -1)
|
||||
@ -1335,7 +1335,7 @@ void Reflect(Writer& vis, Use& v) {
|
||||
std::string s(buf);
|
||||
Reflect(vis, s);
|
||||
} else {
|
||||
Reflect(vis, static_cast<Reference&>(v));
|
||||
Reflect(vis, static_cast<Reference &>(v));
|
||||
Reflect(vis, v.file_id);
|
||||
}
|
||||
}
|
||||
|
101
src/indexer.h
101
src/indexer.h
@ -14,9 +14,9 @@
|
||||
#include <clang/Basic/Specifiers.h>
|
||||
#include <llvm/ADT/StringMap.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@ -27,10 +27,10 @@ struct SymbolIdx {
|
||||
Usr usr;
|
||||
SymbolKind kind;
|
||||
|
||||
bool operator==(const SymbolIdx& o) const {
|
||||
bool operator==(const SymbolIdx &o) const {
|
||||
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;
|
||||
}
|
||||
};
|
||||
@ -47,8 +47,8 @@ struct Reference {
|
||||
std::tuple<Range, Usr, SymbolKind, Role> ToTuple() const {
|
||||
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.
|
||||
@ -60,22 +60,21 @@ MAKE_HASHABLE(SymbolRef, t.range, t.usr, t.kind, t.role);
|
||||
struct Use : Reference {
|
||||
// |file| is used in Query* but not in Index*
|
||||
int file_id = -1;
|
||||
bool operator==(const Use& o) const {
|
||||
bool operator==(const Use &o) const {
|
||||
// lexical container info is ignored.
|
||||
return range == o.range && file_id == o.file_id;
|
||||
}
|
||||
};
|
||||
MAKE_HASHABLE(Use, t.range, t.file_id)
|
||||
|
||||
void Reflect(Reader& visitor, Reference& value);
|
||||
void Reflect(Writer& visitor, Reference& value);
|
||||
void Reflect(Reader& visitor, Use& value);
|
||||
void Reflect(Writer& visitor, Use& value);
|
||||
void Reflect(Reader &visitor, Reference &value);
|
||||
void Reflect(Writer &visitor, Reference &value);
|
||||
void Reflect(Reader &visitor, Use &value);
|
||||
void Reflect(Writer &visitor, Use &value);
|
||||
|
||||
template <typename D>
|
||||
struct NameMixin {
|
||||
template <typename D> struct NameMixin {
|
||||
std::string_view Name(bool qualified) const {
|
||||
auto self = static_cast<const D*>(this);
|
||||
auto self = static_cast<const D *>(this);
|
||||
return qualified
|
||||
? std::string_view(self->detailed_name + self->qual_name_offset,
|
||||
self->short_name_offset -
|
||||
@ -88,9 +87,9 @@ struct NameMixin {
|
||||
|
||||
struct FuncDef : NameMixin<FuncDef> {
|
||||
// General metadata.
|
||||
const char* detailed_name = "";
|
||||
const char* hover = "";
|
||||
const char* comments = "";
|
||||
const char *detailed_name = "";
|
||||
const char *hover = "";
|
||||
const char *comments = "";
|
||||
Maybe<Use> spell;
|
||||
Maybe<Use> extent;
|
||||
|
||||
@ -112,20 +111,9 @@ struct FuncDef : NameMixin<FuncDef> {
|
||||
|
||||
std::vector<Usr> GetBases() const { return bases; }
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(FuncDef,
|
||||
detailed_name,
|
||||
qual_name_offset,
|
||||
short_name_offset,
|
||||
short_name_size,
|
||||
kind,
|
||||
storage,
|
||||
hover,
|
||||
comments,
|
||||
spell,
|
||||
extent,
|
||||
bases,
|
||||
vars,
|
||||
callees);
|
||||
MAKE_REFLECT_STRUCT(FuncDef, detailed_name, qual_name_offset, short_name_offset,
|
||||
short_name_size, kind, storage, hover, comments, spell,
|
||||
extent, bases, vars, callees);
|
||||
|
||||
struct IndexFunc : NameMixin<IndexFunc> {
|
||||
using Def = FuncDef;
|
||||
@ -137,9 +125,9 @@ struct IndexFunc : NameMixin<IndexFunc> {
|
||||
};
|
||||
|
||||
struct TypeDef : NameMixin<TypeDef> {
|
||||
const char* detailed_name = "";
|
||||
const char* hover = "";
|
||||
const char* comments = "";
|
||||
const char *detailed_name = "";
|
||||
const char *hover = "";
|
||||
const char *comments = "";
|
||||
|
||||
Maybe<Use> spell;
|
||||
Maybe<Use> extent;
|
||||
@ -163,21 +151,9 @@ struct TypeDef : NameMixin<TypeDef> {
|
||||
|
||||
std::vector<Usr> GetBases() const { return bases; }
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(TypeDef,
|
||||
detailed_name,
|
||||
qual_name_offset,
|
||||
short_name_offset,
|
||||
short_name_size,
|
||||
kind,
|
||||
hover,
|
||||
comments,
|
||||
spell,
|
||||
extent,
|
||||
alias_of,
|
||||
bases,
|
||||
types,
|
||||
funcs,
|
||||
vars);
|
||||
MAKE_REFLECT_STRUCT(TypeDef, detailed_name, qual_name_offset, short_name_offset,
|
||||
short_name_size, kind, hover, comments, spell, extent,
|
||||
alias_of, bases, types, funcs, vars);
|
||||
|
||||
struct IndexType {
|
||||
using Def = TypeDef;
|
||||
@ -191,9 +167,9 @@ struct IndexType {
|
||||
|
||||
struct VarDef : NameMixin<VarDef> {
|
||||
// General metadata.
|
||||
const char* detailed_name = "";
|
||||
const char* hover = "";
|
||||
const char* comments = "";
|
||||
const char *detailed_name = "";
|
||||
const char *hover = "";
|
||||
const char *comments = "";
|
||||
Maybe<Use> spell;
|
||||
Maybe<Use> extent;
|
||||
|
||||
@ -217,17 +193,8 @@ struct VarDef : NameMixin<VarDef> {
|
||||
|
||||
std::vector<Usr> GetBases() const { return {}; }
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(VarDef,
|
||||
detailed_name,
|
||||
qual_name_offset,
|
||||
short_name_offset,
|
||||
short_name_size,
|
||||
hover,
|
||||
comments,
|
||||
spell,
|
||||
extent,
|
||||
type,
|
||||
kind,
|
||||
MAKE_REFLECT_STRUCT(VarDef, detailed_name, qual_name_offset, short_name_offset,
|
||||
short_name_size, hover, comments, spell, extent, type, kind,
|
||||
storage);
|
||||
|
||||
struct IndexVar {
|
||||
@ -289,9 +256,9 @@ struct IndexFile {
|
||||
IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
|
||||
const std::string &contents);
|
||||
|
||||
IndexFunc& ToFunc(Usr usr);
|
||||
IndexType& ToType(Usr usr);
|
||||
IndexVar& ToVar(Usr usr);
|
||||
IndexFunc &ToFunc(Usr usr);
|
||||
IndexType &ToType(Usr usr);
|
||||
IndexVar &ToVar(Usr usr);
|
||||
|
||||
std::string ToString();
|
||||
};
|
||||
@ -299,6 +266,6 @@ struct IndexFile {
|
||||
namespace ccls::idx {
|
||||
std::vector<std::unique_ptr<IndexFile>>
|
||||
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
|
||||
const std::vector<std::string> &args,
|
||||
const std::vector<FileContents> &file_contents);
|
||||
const std::vector<std::string> &args,
|
||||
const std::vector<FileContents> &file_contents);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ LanguageId SourceFileLanguage(std::string_view path) {
|
||||
return LanguageId::Unknown;
|
||||
}
|
||||
|
||||
const char* LanguageIdentifier(LanguageId lang) {
|
||||
const char *LanguageIdentifier(LanguageId lang) {
|
||||
switch (lang) {
|
||||
case LanguageId::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);
|
||||
|
||||
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/Support/Threading.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <mutex>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <iomanip>
|
||||
#include <mutex>
|
||||
|
||||
namespace ccls::log {
|
||||
static std::mutex mtx;
|
||||
FILE* file;
|
||||
FILE *file;
|
||||
Verbosity verbosity;
|
||||
|
||||
Message::Message(Verbosity verbosity, const char* file, int line)
|
||||
Message::Message(Verbosity verbosity, const char *file, int line)
|
||||
: verbosity_(verbosity) {
|
||||
using namespace llvm;
|
||||
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();
|
||||
}
|
||||
{
|
||||
const char* p = strrchr(file, '/');
|
||||
const char *p = strrchr(file, '/');
|
||||
if (p)
|
||||
file = p + 1;
|
||||
stream_ << std::right << std::setw(15) << file << ':' << std::left
|
||||
@ -52,11 +52,12 @@ Message::Message(Verbosity verbosity, const char* file, int line)
|
||||
}
|
||||
|
||||
Message::~Message() {
|
||||
if (!file) return;
|
||||
if (!file)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
stream_ << '\n';
|
||||
fputs(stream_.str().c_str(), file);
|
||||
if (verbosity_ == Verbosity_FATAL)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
} // namespace ccls::log
|
||||
|
@ -8,31 +8,29 @@
|
||||
|
||||
// Cache that evicts old entries which have not been used recently. Implemented
|
||||
// using array/linear search so this works well for small array sizes.
|
||||
template <typename TKey, typename TValue>
|
||||
struct LruCache {
|
||||
template <typename TKey, typename TValue> struct LruCache {
|
||||
explicit LruCache(int max_entries);
|
||||
|
||||
// Fetches an entry for |key|. If it does not exist, |allocator| will be
|
||||
// invoked to create one.
|
||||
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
|
||||
// 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.
|
||||
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.
|
||||
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
|
||||
// temrinates early.
|
||||
template <typename TFunc>
|
||||
void IterateValues(TFunc func);
|
||||
template <typename TFunc> void IterateValues(TFunc func);
|
||||
|
||||
// Empties the cache
|
||||
void Clear(void);
|
||||
|
||||
private:
|
||||
private:
|
||||
// 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
|
||||
// score. This means that the oldest/least recently accessed value has the
|
||||
@ -43,7 +41,7 @@ struct LruCache {
|
||||
uint32_t score = 0;
|
||||
TKey key;
|
||||
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();
|
||||
@ -60,7 +58,7 @@ LruCache<TKey, TValue>::LruCache(int max_entries) : max_entries_(max_entries) {
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
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) {
|
||||
std::shared_ptr<TValue> result = TryGet(key);
|
||||
if (!result)
|
||||
@ -69,9 +67,9 @@ std::shared_ptr<TValue> LruCache<TKey, TValue>::Get(const TKey& key,
|
||||
}
|
||||
|
||||
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.
|
||||
for (Entry& entry : entries_) {
|
||||
for (Entry &entry : entries_) {
|
||||
if (entry.key == key) {
|
||||
entry.score = next_score_;
|
||||
IncrementScore();
|
||||
@ -83,7 +81,7 @@ std::shared_ptr<TValue> LruCache<TKey, TValue>::TryGet(const TKey& key) {
|
||||
}
|
||||
|
||||
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) {
|
||||
if (entries_[i].key == key) {
|
||||
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>
|
||||
void LruCache<TKey, TValue>::Insert(const TKey& key,
|
||||
const std::shared_ptr<TValue>& value) {
|
||||
void LruCache<TKey, TValue>::Insert(const TKey &key,
|
||||
const std::shared_ptr<TValue> &value) {
|
||||
if ((int)entries_.size() >= max_entries_)
|
||||
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 TFunc>
|
||||
void LruCache<TKey, TValue>::IterateValues(TFunc func) {
|
||||
for (Entry& entry : entries_) {
|
||||
for (Entry &entry : entries_) {
|
||||
if (!func(entry.value))
|
||||
break;
|
||||
}
|
||||
@ -123,13 +121,13 @@ void LruCache<TKey, TValue>::IncrementScore() {
|
||||
// Overflow.
|
||||
if (++next_score_ == 0) {
|
||||
std::sort(entries_.begin(), entries_.end());
|
||||
for (Entry& entry : entries_)
|
||||
for (Entry &entry : entries_)
|
||||
entry.score = next_score_++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
void LruCache<TKey, TValue>::Clear(void) {
|
||||
entries_.clear();
|
||||
next_score_ = 0;
|
||||
entries_.clear();
|
||||
next_score_ = 0;
|
||||
}
|
||||
|
43
src/lsp.cc
43
src/lsp.cc
@ -7,7 +7,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
MessageRegistry* MessageRegistry::instance_ = nullptr;
|
||||
MessageRegistry *MessageRegistry::instance_ = nullptr;
|
||||
|
||||
lsTextDocumentIdentifier
|
||||
lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const {
|
||||
@ -17,8 +17,8 @@ lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const {
|
||||
}
|
||||
|
||||
// Reads a JsonRpc message. |read| returns the next input character.
|
||||
std::optional<std::string> ReadJsonRpcContentFrom(
|
||||
std::function<std::optional<char>()> read) {
|
||||
std::optional<std::string>
|
||||
ReadJsonRpcContentFrom(std::function<std::optional<char>()> read) {
|
||||
// Read the content length. It is terminated by the "\r\n" sequence.
|
||||
int exit_seq = 0;
|
||||
std::string stringified_content_length;
|
||||
@ -37,7 +37,7 @@ std::optional<std::string> ReadJsonRpcContentFrom(
|
||||
|
||||
stringified_content_length += c;
|
||||
}
|
||||
const char* kContentLengthStart = "Content-Length: ";
|
||||
const char *kContentLengthStart = "Content-Length: ";
|
||||
assert(StartsWith(stringified_content_length, kContentLengthStart));
|
||||
int content_length =
|
||||
atoi(stringified_content_length.c_str() + strlen(kContentLengthStart));
|
||||
@ -78,8 +78,8 @@ std::optional<char> ReadCharFromStdinBlocking() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> MessageRegistry::ReadMessageFromStdin(
|
||||
std::unique_ptr<InMessage>* message) {
|
||||
std::optional<std::string>
|
||||
MessageRegistry::ReadMessageFromStdin(std::unique_ptr<InMessage> *message) {
|
||||
std::optional<std::string> content =
|
||||
ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
|
||||
if (!content) {
|
||||
@ -95,9 +95,8 @@ std::optional<std::string> MessageRegistry::ReadMessageFromStdin(
|
||||
return Parse(json_reader, message);
|
||||
}
|
||||
|
||||
std::optional<std::string> MessageRegistry::Parse(
|
||||
Reader& visitor,
|
||||
std::unique_ptr<InMessage>* message) {
|
||||
std::optional<std::string>
|
||||
MessageRegistry::Parse(Reader &visitor, std::unique_ptr<InMessage> *message) {
|
||||
if (!visitor.HasMember("jsonrpc") ||
|
||||
std::string(visitor["jsonrpc"]->GetString()) != "2.0") {
|
||||
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 '") +
|
||||
method + "'";
|
||||
|
||||
Allocator& allocator = allocators[method];
|
||||
Allocator &allocator = allocators[method];
|
||||
try {
|
||||
allocator(visitor, message);
|
||||
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
|
||||
// available.
|
||||
return std::string("Fail to parse '") + method + "' " +
|
||||
static_cast<JsonReader&>(visitor).GetPath() + ", expected " +
|
||||
static_cast<JsonReader &>(visitor).GetPath() + ", expected " +
|
||||
e.what();
|
||||
}
|
||||
}
|
||||
|
||||
MessageRegistry* MessageRegistry::instance() {
|
||||
MessageRegistry *MessageRegistry::instance() {
|
||||
if (!instance_)
|
||||
instance_ = new MessageRegistry();
|
||||
|
||||
@ -133,7 +132,7 @@ MessageRegistry* MessageRegistry::instance() {
|
||||
|
||||
lsBaseOutMessage::~lsBaseOutMessage() = default;
|
||||
|
||||
void lsBaseOutMessage::Write(std::ostream& out) {
|
||||
void lsBaseOutMessage::Write(std::ostream &out) {
|
||||
rapidjson::StringBuffer output;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
|
||||
JsonWriter json_writer{&writer};
|
||||
@ -144,8 +143,8 @@ void lsBaseOutMessage::Write(std::ostream& out) {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
void lsResponseError::Write(Writer& visitor) {
|
||||
auto& value = *this;
|
||||
void lsResponseError::Write(Writer &visitor) {
|
||||
auto &value = *this;
|
||||
int code2 = static_cast<int>(this->code);
|
||||
|
||||
visitor.StartObject();
|
||||
@ -154,22 +153,22 @@ void lsResponseError::Write(Writer& visitor) {
|
||||
visitor.EndObject();
|
||||
}
|
||||
|
||||
lsDocumentUri lsDocumentUri::FromPath(const std::string& path) {
|
||||
lsDocumentUri lsDocumentUri::FromPath(const std::string &path) {
|
||||
lsDocumentUri result;
|
||||
result.SetPath(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lsDocumentUri::operator==(const lsDocumentUri& other) const {
|
||||
bool lsDocumentUri::operator==(const lsDocumentUri &other) const {
|
||||
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
|
||||
raw_uri = path;
|
||||
|
||||
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,
|
||||
"%3A");
|
||||
}
|
||||
@ -231,11 +230,11 @@ std::string lsPosition::ToString() const {
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// not, emit a string.
|
||||
if (value.language) {
|
||||
|
75
src/lsp.h
75
src/lsp.h
@ -8,52 +8,50 @@
|
||||
#include <iosfwd>
|
||||
#include <unordered_map>
|
||||
|
||||
#define REGISTER_IN_MESSAGE(type) \
|
||||
#define REGISTER_IN_MESSAGE(type) \
|
||||
static MessageRegistryRegister<type> type##message_handler_instance_;
|
||||
|
||||
struct MessageRegistry {
|
||||
static MessageRegistry* instance_;
|
||||
static MessageRegistry* instance();
|
||||
static MessageRegistry *instance_;
|
||||
static MessageRegistry *instance();
|
||||
|
||||
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::optional<std::string> ReadMessageFromStdin(
|
||||
std::unique_ptr<InMessage>* message);
|
||||
std::optional<std::string> Parse(Reader& visitor,
|
||||
std::unique_ptr<InMessage>* message);
|
||||
std::optional<std::string>
|
||||
ReadMessageFromStdin(std::unique_ptr<InMessage> *message);
|
||||
std::optional<std::string> Parse(Reader &visitor,
|
||||
std::unique_ptr<InMessage> *message);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MessageRegistryRegister {
|
||||
template <typename T> struct MessageRegistryRegister {
|
||||
MessageRegistryRegister() {
|
||||
T dummy;
|
||||
std::string method_name = dummy.GetMethodType();
|
||||
MessageRegistry::instance()->allocators[method_name] =
|
||||
[](Reader& visitor, std::unique_ptr<InMessage>* message) {
|
||||
[](Reader &visitor, std::unique_ptr<InMessage> *message) {
|
||||
*message = std::make_unique<T>();
|
||||
// Reflect may throw and *message will be partially deserialized.
|
||||
Reflect(visitor, static_cast<T&>(**message));
|
||||
Reflect(visitor, static_cast<T &>(**message));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct 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.
|
||||
void Write(std::ostream& out);
|
||||
void Write(std::ostream &out);
|
||||
};
|
||||
|
||||
template <typename TDerived>
|
||||
struct lsOutMessage : lsBaseOutMessage {
|
||||
template <typename TDerived> struct lsOutMessage : lsBaseOutMessage {
|
||||
// All derived types need to reflect on the |jsonrpc| member.
|
||||
std::string jsonrpc = "2.0";
|
||||
|
||||
void ReflectWriter(Writer& writer) override {
|
||||
Reflect(writer, static_cast<TDerived&>(*this));
|
||||
void ReflectWriter(Writer &writer) override {
|
||||
Reflect(writer, static_cast<TDerived &>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
@ -75,7 +73,7 @@ struct lsResponseError {
|
||||
// Short description.
|
||||
std::string message;
|
||||
|
||||
void Write(Writer& visitor);
|
||||
void Write(Writer &visitor);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -87,28 +85,28 @@ struct lsResponseError {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 raw_uri;
|
||||
};
|
||||
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, lsDocumentUri& value) {
|
||||
void Reflect(TVisitor &visitor, lsDocumentUri &value) {
|
||||
Reflect(visitor, value.raw_uri);
|
||||
}
|
||||
|
||||
struct lsPosition {
|
||||
int line = 0;
|
||||
int character = 0;
|
||||
bool operator==(const lsPosition& o) const {
|
||||
bool operator==(const lsPosition &o) const {
|
||||
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;
|
||||
}
|
||||
std::string ToString() const;
|
||||
@ -118,10 +116,10 @@ MAKE_REFLECT_STRUCT(lsPosition, line, character);
|
||||
struct lsRange {
|
||||
lsPosition start;
|
||||
lsPosition end;
|
||||
bool operator==(const lsRange& o) const {
|
||||
bool operator==(const lsRange &o) const {
|
||||
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;
|
||||
}
|
||||
};
|
||||
@ -130,10 +128,10 @@ MAKE_REFLECT_STRUCT(lsRange, start, end);
|
||||
struct lsLocation {
|
||||
lsDocumentUri uri;
|
||||
lsRange range;
|
||||
bool operator==(const lsLocation& o) const {
|
||||
bool operator==(const lsLocation &o) const {
|
||||
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
|
||||
: range < o.range;
|
||||
}
|
||||
@ -192,8 +190,7 @@ struct lsLocationEx : lsLocation {
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
|
||||
|
||||
template <typename T>
|
||||
struct lsCommand {
|
||||
template <typename T> struct lsCommand {
|
||||
// Title of the command (ie, 'save')
|
||||
std::string title;
|
||||
// Actual command identifier.
|
||||
@ -204,7 +201,7 @@ struct lsCommand {
|
||||
T arguments;
|
||||
};
|
||||
template <typename TVisitor, typename T>
|
||||
void Reflect(TVisitor& visitor, lsCommand<T>& value) {
|
||||
void Reflect(TVisitor &visitor, lsCommand<T> &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(title);
|
||||
REFLECT_MEMBER(command);
|
||||
@ -212,8 +209,7 @@ void Reflect(TVisitor& visitor, lsCommand<T>& value) {
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
template <typename TData, typename TCommandArguments>
|
||||
struct lsCodeLens {
|
||||
template <typename TData, typename TCommandArguments> struct lsCodeLens {
|
||||
// The range in which this code lens is valid. Should only span a single line.
|
||||
lsRange range;
|
||||
// The command this code lens represents.
|
||||
@ -223,7 +219,7 @@ struct lsCodeLens {
|
||||
TData data;
|
||||
};
|
||||
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(range);
|
||||
REFLECT_MEMBER(command);
|
||||
@ -263,7 +259,7 @@ struct lsTextEdit {
|
||||
// empty string.
|
||||
std::string newText;
|
||||
|
||||
bool operator==(const lsTextEdit& that);
|
||||
bool operator==(const lsTextEdit &that);
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsTextEdit, range, newText);
|
||||
|
||||
@ -321,7 +317,7 @@ struct lsMarkedString {
|
||||
std::optional<std::string> language;
|
||||
std::string value;
|
||||
};
|
||||
void Reflect(Writer& visitor, lsMarkedString& value);
|
||||
void Reflect(Writer &visitor, lsMarkedString &value);
|
||||
|
||||
struct lsTextDocumentContentChangeEvent {
|
||||
// The range of the document that changed.
|
||||
@ -337,8 +333,7 @@ struct lsTextDocumentDidChangeParams {
|
||||
lsVersionedTextDocumentIdentifier textDocument;
|
||||
std::vector<lsTextDocumentContentChangeEvent> contentChanges;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams,
|
||||
textDocument,
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams, textDocument,
|
||||
contentChanges);
|
||||
|
||||
// Show a message to the user.
|
||||
@ -360,7 +355,7 @@ struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
|
||||
};
|
||||
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
|
||||
void Reflect(TVisitor &visitor, Out_ShowLogMessage &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(jsonrpc);
|
||||
std::string method = value.method();
|
||||
|
@ -106,9 +106,9 @@ struct lsCompletionItem {
|
||||
// nor with themselves.
|
||||
// std::vector<TextEdit> additionalTextEdits;
|
||||
|
||||
// An std::optional command that is executed *after* inserting this completion.
|
||||
// *Note* that additional modifications to the current document should be
|
||||
// described with the additionalTextEdits-property. Command command;
|
||||
// An std::optional command that is executed *after* inserting this
|
||||
// completion. *Note* that additional modifications to the current document
|
||||
// should be described with the additionalTextEdits-property. Command command;
|
||||
|
||||
// An data entry field that is preserved on a completion item between
|
||||
// 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
|
||||
// into the document, as it could live in either |textEdit|, |insertText|, or
|
||||
// |label|.
|
||||
const std::string& InsertedContent() const {
|
||||
const std::string &InsertedContent() const {
|
||||
if (textEdit)
|
||||
return textEdit->newText;
|
||||
if (!insertText.empty())
|
||||
@ -125,13 +125,6 @@ struct lsCompletionItem {
|
||||
return label;
|
||||
}
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsCompletionItem,
|
||||
label,
|
||||
kind,
|
||||
detail,
|
||||
documentation,
|
||||
sortText,
|
||||
insertText,
|
||||
filterText,
|
||||
insertTextFormat,
|
||||
MAKE_REFLECT_STRUCT(lsCompletionItem, label, kind, detail, documentation,
|
||||
sortText, insertText, filterText, insertTextFormat,
|
||||
textEdit);
|
||||
|
@ -88,7 +88,7 @@ struct Out_TextDocumentPublishDiagnostics
|
||||
Params params;
|
||||
};
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
|
||||
void Reflect(TVisitor &visitor, Out_TextDocumentPublishDiagnostics &value) {
|
||||
std::string method = "textDocument/publishDiagnostics";
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(jsonrpc);
|
||||
@ -96,6 +96,5 @@ void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
|
||||
REFLECT_MEMBER(params);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params,
|
||||
uri,
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, uri,
|
||||
diagnostics);
|
||||
|
24
src/main.cc
24
src/main.cc
@ -28,21 +28,21 @@ std::string g_init_options;
|
||||
namespace {
|
||||
opt<bool> opt_help("h", desc("Alias for -help"));
|
||||
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_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"));
|
||||
|
||||
void CloseLog() {
|
||||
fclose(ccls::log::file);
|
||||
}
|
||||
void CloseLog() { fclose(ccls::log::file); }
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char **argv) {
|
||||
TraceMe();
|
||||
sys::PrintStackTraceOnErrorSignal(argv[0]);
|
||||
|
||||
@ -98,9 +98,9 @@ int main(int argc, char** argv) {
|
||||
try {
|
||||
Config 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",
|
||||
static_cast<JsonReader&>(json_reader).GetPath().c_str(),
|
||||
static_cast<JsonReader &>(json_reader).GetPath().c_str(),
|
||||
e.what());
|
||||
return 1;
|
||||
}
|
||||
@ -108,11 +108,13 @@ int main(int argc, char** argv) {
|
||||
|
||||
sys::ChangeStdinToBinary();
|
||||
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();
|
||||
// The thread that writes responses from the main thread to stdout.
|
||||
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();
|
||||
}
|
||||
|
||||
|
34
src/match.cc
34
src/match.cc
@ -5,7 +5,7 @@
|
||||
using namespace ccls;
|
||||
|
||||
// static
|
||||
std::optional<Matcher> Matcher::Create(const std::string& search) {
|
||||
std::optional<Matcher> Matcher::Create(const std::string &search) {
|
||||
/*
|
||||
std::string real_search;
|
||||
real_search.reserve(search.size() * 3 + 2);
|
||||
@ -19,51 +19,51 @@ std::optional<Matcher> Matcher::Create(const std::string& search) {
|
||||
try {
|
||||
Matcher m;
|
||||
m.regex_string = search;
|
||||
m.regex = std::regex(
|
||||
search, std::regex_constants::ECMAScript | std::regex_constants::icase |
|
||||
std::regex_constants::optimize
|
||||
// std::regex_constants::nosubs
|
||||
m.regex = std::regex(search, std::regex_constants::ECMAScript |
|
||||
std::regex_constants::icase |
|
||||
std::regex_constants::optimize
|
||||
// std::regex_constants::nosubs
|
||||
);
|
||||
return m;
|
||||
} catch (const std::exception& e) {
|
||||
} catch (const std::exception &e) {
|
||||
Out_ShowLogMessage out;
|
||||
out.display_type = Out_ShowLogMessage::DisplayType::Show;
|
||||
out.params.type = lsMessageType::Error;
|
||||
out.params.message = "ccls: Parsing EMCAScript regex \"" + search +
|
||||
"\" failed; " + e.what();
|
||||
out.params.message =
|
||||
"ccls: Parsing EMCAScript regex \"" + search + "\" failed; " + e.what();
|
||||
pipeline::WriteStdout(kMethodType_Unknown, out);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool Matcher::IsMatch(const std::string& value) const {
|
||||
bool Matcher::IsMatch(const std::string &value) const {
|
||||
// std::smatch match;
|
||||
// return std::regex_match(value, match, regex);
|
||||
return std::regex_search(value, regex, std::regex_constants::match_any);
|
||||
}
|
||||
|
||||
GroupMatch::GroupMatch(const std::vector<std::string>& whitelist,
|
||||
const std::vector<std::string>& blacklist) {
|
||||
for (const std::string& entry : whitelist) {
|
||||
GroupMatch::GroupMatch(const std::vector<std::string> &whitelist,
|
||||
const std::vector<std::string> &blacklist) {
|
||||
for (const std::string &entry : whitelist) {
|
||||
std::optional<Matcher> m = Matcher::Create(entry);
|
||||
if (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);
|
||||
if (m)
|
||||
this->blacklist.push_back(*m);
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupMatch::IsMatch(const std::string& value,
|
||||
std::string* match_failure_reason) const {
|
||||
for (const Matcher& m : whitelist) {
|
||||
bool GroupMatch::IsMatch(const std::string &value,
|
||||
std::string *match_failure_reason) const {
|
||||
for (const Matcher &m : whitelist) {
|
||||
if (m.IsMatch(value))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const Matcher& m : blacklist) {
|
||||
for (const Matcher &m : blacklist) {
|
||||
if (m.IsMatch(value)) {
|
||||
if (match_failure_reason)
|
||||
*match_failure_reason = "blacklist \"" + m.regex_string + "\"";
|
||||
|
12
src/match.h
12
src/match.h
@ -7,9 +7,9 @@
|
||||
#include <vector>
|
||||
|
||||
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::regex regex;
|
||||
@ -17,11 +17,11 @@ struct Matcher {
|
||||
|
||||
// Check multiple |Matcher| instances at the same time.
|
||||
struct GroupMatch {
|
||||
GroupMatch(const std::vector<std::string>& whitelist,
|
||||
const std::vector<std::string>& blacklist);
|
||||
GroupMatch(const std::vector<std::string> &whitelist,
|
||||
const std::vector<std::string> &blacklist);
|
||||
|
||||
bool IsMatch(const std::string& value,
|
||||
std::string* match_failure_reason = nullptr) const;
|
||||
bool IsMatch(const std::string &value,
|
||||
std::string *match_failure_reason = nullptr) const;
|
||||
|
||||
std::vector<Matcher> whitelist;
|
||||
std::vector<Matcher> blacklist;
|
||||
|
33
src/maybe.h
33
src/maybe.h
@ -4,29 +4,28 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
// Like std::optional, but the stored data is responsible for containing the empty
|
||||
// state. T should define a function `bool T::Valid()`.
|
||||
template <typename T>
|
||||
class Maybe {
|
||||
// Like std::optional, but the stored data is responsible for containing the
|
||||
// empty state. T should define a function `bool T::Valid()`.
|
||||
template <typename T> class Maybe {
|
||||
T storage;
|
||||
|
||||
public:
|
||||
public:
|
||||
constexpr Maybe() = default;
|
||||
Maybe(const Maybe&) = default;
|
||||
Maybe(const Maybe &) = default;
|
||||
Maybe(std::nullopt_t) {}
|
||||
Maybe(const T& x) : storage(x) {}
|
||||
Maybe(T&& x) : storage(std::forward<T>(x)) {}
|
||||
Maybe(const T &x) : storage(x) {}
|
||||
Maybe(T &&x) : storage(std::forward<T>(x)) {}
|
||||
|
||||
Maybe& operator=(const Maybe&) = default;
|
||||
Maybe& operator=(const T& x) {
|
||||
Maybe &operator=(const Maybe &) = default;
|
||||
Maybe &operator=(const T &x) {
|
||||
storage = x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T* operator->() const { return &storage; }
|
||||
T* operator->() { return &storage; }
|
||||
const T& operator*() const { return storage; }
|
||||
T& operator*() { return storage; }
|
||||
const T *operator->() const { return &storage; }
|
||||
T *operator->() { return &storage; }
|
||||
const T &operator*() const { return storage; }
|
||||
T &operator*() { return storage; }
|
||||
|
||||
bool Valid() const { return storage.Valid(); }
|
||||
explicit operator bool() const { return Valid(); }
|
||||
@ -36,9 +35,9 @@ class Maybe {
|
||||
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()
|
||||
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 storage == o.storage; }
|
||||
bool operator!=(const Maybe &o) const { return !(*this == o); }
|
||||
};
|
||||
|
@ -337,15 +337,16 @@ void EmitSemanticHighlighting(DB *db,
|
||||
out.params.uri = lsDocumentUri::FromPath(wfile->filename);
|
||||
// Transform lsRange into pair<int, int> (offset pairs)
|
||||
if (!g_config->highlight.lsRanges) {
|
||||
std::vector<std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>>
|
||||
scratch;
|
||||
std::vector<
|
||||
std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>>
|
||||
scratch;
|
||||
for (auto &entry : grouped_symbols) {
|
||||
for (auto &range : entry.second.lsRanges)
|
||||
scratch.emplace_back(range, &entry.second);
|
||||
entry.second.lsRanges.clear();
|
||||
}
|
||||
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;
|
||||
int l = 0, c = 0, i = 0, p = 0;
|
||||
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]))
|
||||
p++;
|
||||
}
|
||||
if (l < line) return true;
|
||||
if (l < line)
|
||||
return true;
|
||||
for (; c < col && i < buf.size() && buf[i] != '\n'; c++)
|
||||
if (p++, uint8_t(buf[i++]) >= 128)
|
||||
// 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++;
|
||||
return c < col;
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
#include "method.h"
|
||||
#include "query.h"
|
||||
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@ -28,7 +28,7 @@ struct WorkingFiles;
|
||||
// relatively stable ids. Only supports xxx files at a time.
|
||||
struct SemanticHighlightSymbolCache {
|
||||
struct Entry {
|
||||
SemanticHighlightSymbolCache* all_caches_ = nullptr;
|
||||
SemanticHighlightSymbolCache *all_caches_ = nullptr;
|
||||
|
||||
// The path this cache belongs to.
|
||||
std::string path;
|
||||
@ -38,13 +38,13 @@ struct SemanticHighlightSymbolCache {
|
||||
TNameToId detailed_func_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,
|
||||
const std::string& detailed_name);
|
||||
int GetStableId(SymbolKind kind, const std::string& detailed_name);
|
||||
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;
|
||||
@ -54,7 +54,7 @@ struct SemanticHighlightSymbolCache {
|
||||
|
||||
SemanticHighlightSymbolCache();
|
||||
void Init();
|
||||
std::shared_ptr<Entry> GetCacheForFile(const std::string& path);
|
||||
std::shared_ptr<Entry> GetCacheForFile(const std::string &path);
|
||||
};
|
||||
|
||||
struct Out_CclsPublishSemanticHighlighting
|
||||
@ -79,9 +79,7 @@ struct Out_CclsPublishSemanticHighlighting
|
||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Symbol, stableId,
|
||||
parentKind, kind, storage, ranges, lsRanges);
|
||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Params, uri, symbols);
|
||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting,
|
||||
jsonrpc,
|
||||
method,
|
||||
MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, jsonrpc, method,
|
||||
params);
|
||||
|
||||
// Usage:
|
||||
@ -94,54 +92,49 @@ MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting,
|
||||
// Then there will be a global FooHandler instance in
|
||||
// |MessageHandler::message_handlers|.
|
||||
|
||||
#define REGISTER_MESSAGE_HANDLER(type) \
|
||||
#define REGISTER_MESSAGE_HANDLER(type) \
|
||||
static type type##message_handler_instance_;
|
||||
|
||||
struct MessageHandler {
|
||||
DB* db = nullptr;
|
||||
MultiQueueWaiter* waiter = nullptr;
|
||||
Project* project = nullptr;
|
||||
DiagnosticsPublisher* diag_pub = nullptr;
|
||||
VFS* vfs = nullptr;
|
||||
ImportManager* import_manager = nullptr;
|
||||
SemanticHighlightSymbolCache* semantic_cache = nullptr;
|
||||
WorkingFiles* working_files = nullptr;
|
||||
ClangCompleteManager* clang_complete = nullptr;
|
||||
IncludeComplete* include_complete = nullptr;
|
||||
CodeCompleteCache* global_code_complete_cache = nullptr;
|
||||
CodeCompleteCache* non_global_code_complete_cache = nullptr;
|
||||
CodeCompleteCache* signature_cache = nullptr;
|
||||
DB *db = nullptr;
|
||||
MultiQueueWaiter *waiter = nullptr;
|
||||
Project *project = nullptr;
|
||||
DiagnosticsPublisher *diag_pub = nullptr;
|
||||
VFS *vfs = nullptr;
|
||||
ImportManager *import_manager = nullptr;
|
||||
SemanticHighlightSymbolCache *semantic_cache = nullptr;
|
||||
WorkingFiles *working_files = nullptr;
|
||||
ClangCompleteManager *clang_complete = nullptr;
|
||||
IncludeComplete *include_complete = nullptr;
|
||||
CodeCompleteCache *global_code_complete_cache = nullptr;
|
||||
CodeCompleteCache *non_global_code_complete_cache = nullptr;
|
||||
CodeCompleteCache *signature_cache = nullptr;
|
||||
|
||||
virtual MethodType GetMethodType() const = 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();
|
||||
};
|
||||
|
||||
template <typename TMessage>
|
||||
struct BaseMessageHandler : MessageHandler {
|
||||
virtual void Run(TMessage* message) = 0;
|
||||
template <typename TMessage> struct BaseMessageHandler : MessageHandler {
|
||||
virtual void Run(TMessage *message) = 0;
|
||||
|
||||
// MessageHandler:
|
||||
void Run(std::unique_ptr<InMessage> message) override {
|
||||
Run(static_cast<TMessage*>(message.get()));
|
||||
Run(static_cast<TMessage *>(message.get()));
|
||||
}
|
||||
};
|
||||
|
||||
bool FindFileOrFail(DB* db,
|
||||
Project* project,
|
||||
std::optional<lsRequestId> id,
|
||||
const std::string& absolute_path,
|
||||
QueryFile** out_query_file,
|
||||
int* out_file_id = nullptr);
|
||||
bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
|
||||
const std::string &absolute_path,
|
||||
QueryFile **out_query_file, int *out_file_id = nullptr);
|
||||
|
||||
void EmitSkippedRanges(WorkingFile *working_file,
|
||||
const std::vector<Range> &skipped_ranges);
|
||||
|
||||
void EmitSemanticHighlighting(DB* db,
|
||||
SemanticHighlightSymbolCache* semantic_cache,
|
||||
WorkingFile* working_file,
|
||||
QueryFile* file);
|
||||
void EmitSemanticHighlighting(DB *db,
|
||||
SemanticHighlightSymbolCache *semantic_cache,
|
||||
WorkingFile *working_file, QueryFile *file);
|
||||
|
@ -18,14 +18,14 @@ REGISTER_IN_MESSAGE(In_CclsBase);
|
||||
struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(In_CclsBase* request) override {
|
||||
QueryFile* file;
|
||||
void Run(In_CclsBase *request) override {
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList out;
|
||||
@ -33,12 +33,12 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
|
||||
for (SymbolRef sym :
|
||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||
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,
|
||||
GetTypeDeclarations(db, def->bases));
|
||||
break;
|
||||
} 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,
|
||||
GetFuncDeclarations(db, def->bases));
|
||||
break;
|
||||
@ -48,4 +48,4 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsBase);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -44,16 +44,9 @@ struct In_CclsCallHierarchy : public RequestInMessage {
|
||||
int levels = 1;
|
||||
};
|
||||
Params params;
|
||||
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy::Params,
|
||||
textDocument,
|
||||
position,
|
||||
id,
|
||||
callee,
|
||||
callType,
|
||||
qualified,
|
||||
levels);
|
||||
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy::Params, textDocument, position, id,
|
||||
callee, callType, qualified, levels);
|
||||
MAKE_REFLECT_STRUCT(In_CclsCallHierarchy, id, params);
|
||||
REGISTER_IN_MESSAGE(In_CclsCallHierarchy);
|
||||
|
||||
@ -72,26 +65,15 @@ struct Out_CclsCallHierarchy : public lsOutMessage<Out_CclsCallHierarchy> {
|
||||
lsRequestId id;
|
||||
std::optional<Entry> result;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_CclsCallHierarchy::Entry,
|
||||
id,
|
||||
name,
|
||||
location,
|
||||
callType,
|
||||
numChildren,
|
||||
children);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCallHierarchy,
|
||||
jsonrpc,
|
||||
id,
|
||||
MAKE_REFLECT_STRUCT(Out_CclsCallHierarchy::Entry, id, name, location, callType,
|
||||
numChildren, children);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCallHierarchy, jsonrpc, id,
|
||||
result);
|
||||
|
||||
bool Expand(MessageHandler* m,
|
||||
Out_CclsCallHierarchy::Entry* entry,
|
||||
bool callee,
|
||||
CallType call_type,
|
||||
bool qualified,
|
||||
int levels) {
|
||||
const QueryFunc& func = m->db->Func(entry->usr);
|
||||
const QueryFunc::Def* def = func.AnyDef();
|
||||
bool Expand(MessageHandler *m, Out_CclsCallHierarchy::Entry *entry, bool callee,
|
||||
CallType call_type, bool qualified, int levels) {
|
||||
const QueryFunc &func = m->db->Func(entry->usr);
|
||||
const QueryFunc::Def *def = func.AnyDef();
|
||||
entry->numChildren = 0;
|
||||
if (!def)
|
||||
return false;
|
||||
@ -108,13 +90,12 @@ bool Expand(MessageHandler* m,
|
||||
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 (const auto* def = func.AnyDef())
|
||||
if (const auto *def = func.AnyDef())
|
||||
for (SymbolRef ref : def->callees)
|
||||
if (ref.kind == SymbolKind::Func)
|
||||
handle(Use{{ref.range, ref.usr, ref.kind, ref.role},
|
||||
def->file_id},
|
||||
handle(Use{{ref.range, ref.usr, ref.kind, ref.role}, def->file_id},
|
||||
call_type);
|
||||
} else {
|
||||
for (Use use : func.uses)
|
||||
@ -125,7 +106,7 @@ bool Expand(MessageHandler* m,
|
||||
|
||||
std::unordered_set<Usr> seen;
|
||||
seen.insert(func.usr);
|
||||
std::vector<const QueryFunc*> stack;
|
||||
std::vector<const QueryFunc *> stack;
|
||||
entry->name = def->Name(qualified);
|
||||
handle_uses(func, CallType::Direct);
|
||||
|
||||
@ -133,10 +114,10 @@ bool Expand(MessageHandler* m,
|
||||
if (call_type & CallType::Base) {
|
||||
stack.push_back(&func);
|
||||
while (stack.size()) {
|
||||
const QueryFunc& func1 = *stack.back();
|
||||
const QueryFunc &func1 = *stack.back();
|
||||
stack.pop_back();
|
||||
if (auto* def1 = func1.AnyDef()) {
|
||||
EachDefinedFunc(m->db, def1->bases, [&](QueryFunc& func2) {
|
||||
if (auto *def1 = func1.AnyDef()) {
|
||||
EachDefinedFunc(m->db, def1->bases, [&](QueryFunc &func2) {
|
||||
if (!seen.count(func2.usr)) {
|
||||
seen.insert(func2.usr);
|
||||
stack.push_back(&func2);
|
||||
@ -151,9 +132,9 @@ bool Expand(MessageHandler* m,
|
||||
if (call_type & CallType::Derived) {
|
||||
stack.push_back(&func);
|
||||
while (stack.size()) {
|
||||
const QueryFunc& func1 = *stack.back();
|
||||
const QueryFunc &func1 = *stack.back();
|
||||
stack.pop_back();
|
||||
EachDefinedFunc(m->db, func1.derived, [&](QueryFunc& func2) {
|
||||
EachDefinedFunc(m->db, func1.derived, [&](QueryFunc &func2) {
|
||||
if (!seen.count(func2.usr)) {
|
||||
seen.insert(func2.usr);
|
||||
stack.push_back(&func2);
|
||||
@ -165,16 +146,13 @@ bool Expand(MessageHandler* m,
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Handler_CclsCallHierarchy
|
||||
: BaseMessageHandler<In_CclsCallHierarchy> {
|
||||
struct Handler_CclsCallHierarchy : BaseMessageHandler<In_CclsCallHierarchy> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
std::optional<Out_CclsCallHierarchy::Entry> BuildInitial(Usr root_usr,
|
||||
bool callee,
|
||||
CallType call_type,
|
||||
bool qualified,
|
||||
int levels) {
|
||||
const auto* def = db->Func(root_usr).AnyDef();
|
||||
std::optional<Out_CclsCallHierarchy::Entry>
|
||||
BuildInitial(Usr root_usr, bool callee, CallType call_type, bool qualified,
|
||||
int levels) {
|
||||
const auto *def = db->Func(root_usr).AnyDef();
|
||||
if (!def)
|
||||
return {};
|
||||
|
||||
@ -191,8 +169,8 @@ struct Handler_CclsCallHierarchy
|
||||
return entry;
|
||||
}
|
||||
|
||||
void Run(In_CclsCallHierarchy* request) override {
|
||||
auto& params = request->params;
|
||||
void Run(In_CclsCallHierarchy *request) override {
|
||||
auto ¶ms = request->params;
|
||||
Out_CclsCallHierarchy out;
|
||||
out.id = request->id;
|
||||
|
||||
@ -211,11 +189,11 @@ struct Handler_CclsCallHierarchy
|
||||
params.levels);
|
||||
out.result = std::move(entry);
|
||||
} else {
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file))
|
||||
return;
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
for (SymbolRef sym :
|
||||
FindSymbolsAtLocation(working_file, file, params.position)) {
|
||||
@ -232,4 +210,4 @@ struct Handler_CclsCallHierarchy
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -15,14 +15,14 @@ REGISTER_IN_MESSAGE(In_CclsCallers);
|
||||
|
||||
struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_CclsCallers* request) override {
|
||||
QueryFile* file;
|
||||
void Run(In_CclsCallers *request) override {
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList out;
|
||||
@ -30,7 +30,7 @@ struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
|
||||
for (SymbolRef sym :
|
||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||
if (sym.kind == SymbolKind::Func) {
|
||||
QueryFunc& func = db->GetFunc(sym);
|
||||
QueryFunc &func = db->GetFunc(sym);
|
||||
std::vector<Use> uses = func.uses;
|
||||
for (Use func_ref : GetUsesForAllBases(db, func))
|
||||
uses.push_back(func_ref);
|
||||
@ -44,4 +44,4 @@ struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsCallers);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -3,14 +3,8 @@
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
MAKE_REFLECT_STRUCT(QueryFile::Def,
|
||||
path,
|
||||
args,
|
||||
language,
|
||||
outline,
|
||||
all_symbols,
|
||||
skipped_ranges,
|
||||
dependencies);
|
||||
MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, outline, all_symbols,
|
||||
skipped_ranges, dependencies);
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "$ccls/fileInfo";
|
||||
@ -35,8 +29,8 @@ MAKE_REFLECT_STRUCT(Out_CclsFileInfo, jsonrpc, id, result);
|
||||
|
||||
struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_CclsFileInfo* request) override {
|
||||
QueryFile* file;
|
||||
void Run(In_CclsFileInfo *request) override {
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
@ -54,4 +48,4 @@ struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "match.h"
|
||||
#include "message_handler.h"
|
||||
#include "pipeline.hh"
|
||||
#include "platform.h"
|
||||
#include "project.h"
|
||||
#include "pipeline.hh"
|
||||
#include "working_files.h"
|
||||
using namespace ccls;
|
||||
|
||||
@ -21,38 +21,36 @@ struct In_CclsFreshenIndex : public NotificationInMessage {
|
||||
};
|
||||
Params params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex::Params,
|
||||
dependencies,
|
||||
whitelist,
|
||||
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex::Params, dependencies, whitelist,
|
||||
blacklist);
|
||||
MAKE_REFLECT_STRUCT(In_CclsFreshenIndex, params);
|
||||
REGISTER_IN_MESSAGE(In_CclsFreshenIndex);
|
||||
|
||||
struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
|
||||
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);
|
||||
|
||||
std::queue<const QueryFile*> q;
|
||||
std::queue<const QueryFile *> q;
|
||||
// |need_index| stores every filename ever enqueued.
|
||||
std::unordered_set<std::string> need_index;
|
||||
// Reverse dependency graph.
|
||||
std::unordered_map<std::string, std::vector<std::string>> graph;
|
||||
// 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 (matcher.IsMatch(file.def->path))
|
||||
q.push(&file);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
while (!q.empty()) {
|
||||
const QueryFile* file = q.front();
|
||||
const QueryFile *file = q.front();
|
||||
q.pop();
|
||||
need_index.insert(file->def->path);
|
||||
|
||||
@ -61,13 +59,13 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
|
||||
continue;
|
||||
{
|
||||
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)
|
||||
st.stage = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
if (it != path_to_file.end()) {
|
||||
q.push(it->second);
|
||||
@ -81,4 +79,4 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -51,32 +51,18 @@ struct Out_CclsInheritanceHierarchy
|
||||
lsRequestId id;
|
||||
std::optional<Entry> result;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_CclsInheritanceHierarchy::Entry,
|
||||
id,
|
||||
kind,
|
||||
name,
|
||||
location,
|
||||
numChildren,
|
||||
children);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritanceHierarchy,
|
||||
jsonrpc,
|
||||
id,
|
||||
result);
|
||||
MAKE_REFLECT_STRUCT(Out_CclsInheritanceHierarchy::Entry, id, kind, name,
|
||||
location, numChildren, children);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritanceHierarchy, jsonrpc,
|
||||
id, result);
|
||||
|
||||
bool Expand(MessageHandler* m,
|
||||
Out_CclsInheritanceHierarchy::Entry* entry,
|
||||
bool derived,
|
||||
bool qualified,
|
||||
int levels);
|
||||
bool Expand(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
|
||||
bool derived, bool qualified, int levels);
|
||||
|
||||
template <typename Q>
|
||||
bool ExpandHelper(MessageHandler* m,
|
||||
Out_CclsInheritanceHierarchy::Entry* entry,
|
||||
bool derived,
|
||||
bool qualified,
|
||||
int levels,
|
||||
Q& entity) {
|
||||
const auto* def = entity.AnyDef();
|
||||
bool ExpandHelper(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
|
||||
bool derived, bool qualified, int levels, Q &entity) {
|
||||
const auto *def = entity.AnyDef();
|
||||
if (def) {
|
||||
entry->name = def->Name(qualified);
|
||||
if (def->spell) {
|
||||
@ -122,11 +108,8 @@ bool ExpandHelper(MessageHandler* m,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Expand(MessageHandler* m,
|
||||
Out_CclsInheritanceHierarchy::Entry* entry,
|
||||
bool derived,
|
||||
bool qualified,
|
||||
int levels) {
|
||||
bool Expand(MessageHandler *m, Out_CclsInheritanceHierarchy::Entry *entry,
|
||||
bool derived, bool qualified, int levels) {
|
||||
if (entry->kind == SymbolKind::Func)
|
||||
return ExpandHelper(m, entry, derived, qualified, levels,
|
||||
m->db->Func(entry->usr));
|
||||
@ -149,8 +132,8 @@ struct Handler_CclsInheritanceHierarchy
|
||||
return entry;
|
||||
}
|
||||
|
||||
void Run(In_CclsInheritanceHierarchy* request) override {
|
||||
auto& params = request->params;
|
||||
void Run(In_CclsInheritanceHierarchy *request) override {
|
||||
auto ¶ms = request->params;
|
||||
Out_CclsInheritanceHierarchy out;
|
||||
out.id = request->id;
|
||||
|
||||
@ -169,12 +152,11 @@ struct Handler_CclsInheritanceHierarchy
|
||||
Expand(this, &entry, params.derived, params.qualified, params.levels))
|
||||
out.result = std::move(entry);
|
||||
} else {
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file))
|
||||
return;
|
||||
WorkingFile* wfile =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position))
|
||||
if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
|
||||
@ -208,4 +190,4 @@ struct Handler_CclsInheritanceHierarchy
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -30,17 +30,12 @@ struct In_CclsMemberHierarchy : public RequestInMessage {
|
||||
Params params;
|
||||
};
|
||||
|
||||
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy::Params,
|
||||
textDocument,
|
||||
position,
|
||||
id,
|
||||
qualified,
|
||||
levels);
|
||||
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy::Params, textDocument, position, id,
|
||||
qualified, levels);
|
||||
MAKE_REFLECT_STRUCT(In_CclsMemberHierarchy, id, params);
|
||||
REGISTER_IN_MESSAGE(In_CclsMemberHierarchy);
|
||||
|
||||
struct Out_CclsMemberHierarchy
|
||||
: public lsOutMessage<Out_CclsMemberHierarchy> {
|
||||
struct Out_CclsMemberHierarchy : public lsOutMessage<Out_CclsMemberHierarchy> {
|
||||
struct Entry {
|
||||
Usr usr;
|
||||
std::string id;
|
||||
@ -56,31 +51,18 @@ struct Out_CclsMemberHierarchy
|
||||
lsRequestId id;
|
||||
std::optional<Entry> result;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_CclsMemberHierarchy::Entry,
|
||||
id,
|
||||
name,
|
||||
fieldName,
|
||||
location,
|
||||
numChildren,
|
||||
children);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMemberHierarchy,
|
||||
jsonrpc,
|
||||
id,
|
||||
MAKE_REFLECT_STRUCT(Out_CclsMemberHierarchy::Entry, id, name, fieldName,
|
||||
location, numChildren, children);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMemberHierarchy, jsonrpc, id,
|
||||
result);
|
||||
|
||||
bool Expand(MessageHandler* m,
|
||||
Out_CclsMemberHierarchy::Entry* entry,
|
||||
bool qualified,
|
||||
int levels);
|
||||
bool Expand(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
|
||||
bool qualified, int levels);
|
||||
|
||||
// Add a field to |entry| which is a Func/Type.
|
||||
void DoField(MessageHandler* m,
|
||||
Out_CclsMemberHierarchy::Entry* entry,
|
||||
const QueryVar& var,
|
||||
int64_t offset,
|
||||
bool qualified,
|
||||
int levels) {
|
||||
const QueryVar::Def* def1 = var.AnyDef();
|
||||
void DoField(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
|
||||
const QueryVar &var, int64_t offset, bool qualified, int levels) {
|
||||
const QueryVar::Def *def1 = var.AnyDef();
|
||||
if (!def1)
|
||||
return;
|
||||
Out_CclsMemberHierarchy::Entry entry1;
|
||||
@ -120,37 +102,35 @@ void DoField(MessageHandler* m,
|
||||
}
|
||||
|
||||
// Expand a type node by adding members recursively to it.
|
||||
bool Expand(MessageHandler* m,
|
||||
Out_CclsMemberHierarchy::Entry* entry,
|
||||
bool qualified,
|
||||
int levels) {
|
||||
bool Expand(MessageHandler *m, Out_CclsMemberHierarchy::Entry *entry,
|
||||
bool qualified, int levels) {
|
||||
if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
|
||||
entry->name = ClangBuiltinTypeName(int(entry->usr));
|
||||
return true;
|
||||
}
|
||||
const QueryType& type = m->db->Type(entry->usr);
|
||||
const QueryType::Def* def = type.AnyDef();
|
||||
const QueryType &type = m->db->Type(entry->usr);
|
||||
const QueryType::Def *def = type.AnyDef();
|
||||
// builtin types have no declaration and empty |qualified|.
|
||||
if (!def)
|
||||
return false;
|
||||
entry->name = def->Name(qualified);
|
||||
std::unordered_set<Usr> seen;
|
||||
if (levels > 0) {
|
||||
std::vector<const QueryType*> stack;
|
||||
std::vector<const QueryType *> stack;
|
||||
seen.insert(type.usr);
|
||||
stack.push_back(&type);
|
||||
while (stack.size()) {
|
||||
const auto* def = stack.back()->AnyDef();
|
||||
const auto *def = stack.back()->AnyDef();
|
||||
stack.pop_back();
|
||||
if (def) {
|
||||
EachDefinedType(m->db, def->bases, [&](QueryType& type1) {
|
||||
EachDefinedType(m->db, def->bases, [&](QueryType &type1) {
|
||||
if (!seen.count(type1.usr)) {
|
||||
seen.insert(type1.usr);
|
||||
stack.push_back(&type1);
|
||||
}
|
||||
});
|
||||
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;
|
||||
entry1.id = std::to_string(def->alias_of);
|
||||
entry1.usr = def->alias_of;
|
||||
@ -176,7 +156,7 @@ bool Expand(MessageHandler* m,
|
||||
}
|
||||
} else {
|
||||
for (auto it : def->vars) {
|
||||
QueryVar& var = m->db->Var(it.first);
|
||||
QueryVar &var = m->db->Var(it.first);
|
||||
if (!var.def.empty())
|
||||
DoField(m, entry, var, it.second, qualified, levels - 1);
|
||||
}
|
||||
@ -193,15 +173,13 @@ struct Handler_CclsMemberHierarchy
|
||||
: BaseMessageHandler<In_CclsMemberHierarchy> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
std::optional<Out_CclsMemberHierarchy::Entry> BuildInitial(SymbolKind kind,
|
||||
Usr root_usr,
|
||||
bool qualified,
|
||||
int levels) {
|
||||
std::optional<Out_CclsMemberHierarchy::Entry>
|
||||
BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels) {
|
||||
switch (kind) {
|
||||
default:
|
||||
return {};
|
||||
case SymbolKind::Func: {
|
||||
const auto* def = db->Func(root_usr).AnyDef();
|
||||
const auto *def = db->Func(root_usr).AnyDef();
|
||||
if (!def)
|
||||
return {};
|
||||
|
||||
@ -210,16 +188,16 @@ struct Handler_CclsMemberHierarchy
|
||||
entry.name = def->Name(qualified);
|
||||
if (def->spell) {
|
||||
if (std::optional<lsLocation> loc =
|
||||
GetLsLocation(db, working_files, *def->spell))
|
||||
GetLsLocation(db, working_files, *def->spell))
|
||||
entry.location = *loc;
|
||||
}
|
||||
EachDefinedVar(db, def->vars, [&](QueryVar& var) {
|
||||
DoField(this, &entry, var, -1, qualified, levels - 1);
|
||||
});
|
||||
EachDefinedVar(db, def->vars, [&](QueryVar &var) {
|
||||
DoField(this, &entry, var, -1, qualified, levels - 1);
|
||||
});
|
||||
return entry;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
const auto* def = db->Type(root_usr).AnyDef();
|
||||
const auto *def = db->Type(root_usr).AnyDef();
|
||||
if (!def)
|
||||
return {};
|
||||
|
||||
@ -228,7 +206,7 @@ struct Handler_CclsMemberHierarchy
|
||||
entry.usr = root_usr;
|
||||
if (def->spell) {
|
||||
if (std::optional<lsLocation> loc =
|
||||
GetLsLocation(db, working_files, *def->spell))
|
||||
GetLsLocation(db, working_files, *def->spell))
|
||||
entry.location = *loc;
|
||||
}
|
||||
Expand(this, &entry, qualified, levels);
|
||||
@ -237,8 +215,8 @@ struct Handler_CclsMemberHierarchy
|
||||
}
|
||||
}
|
||||
|
||||
void Run(In_CclsMemberHierarchy* request) override {
|
||||
auto& params = request->params;
|
||||
void Run(In_CclsMemberHierarchy *request) override {
|
||||
auto ¶ms = request->params;
|
||||
Out_CclsMemberHierarchy out;
|
||||
out.id = request->id;
|
||||
|
||||
@ -256,29 +234,28 @@ struct Handler_CclsMemberHierarchy
|
||||
Expand(this, &entry, params.qualified, params.levels))
|
||||
out.result = std::move(entry);
|
||||
} else {
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file))
|
||||
return;
|
||||
WorkingFile* wfile =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
|
||||
for (SymbolRef sym :
|
||||
FindSymbolsAtLocation(wfile, file, params.position)) {
|
||||
switch (sym.kind) {
|
||||
case SymbolKind::Func:
|
||||
case SymbolKind::Type:
|
||||
out.result = BuildInitial(sym.kind, sym.usr, params.qualified,
|
||||
params.levels);
|
||||
break;
|
||||
case SymbolKind::Var: {
|
||||
const QueryVar::Def* def = db->GetVar(sym).AnyDef();
|
||||
if (def && def->type)
|
||||
out.result = BuildInitial(SymbolKind::Type, def->type,
|
||||
params.qualified, params.levels);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
case SymbolKind::Func:
|
||||
case SymbolKind::Type:
|
||||
out.result =
|
||||
BuildInitial(sym.kind, sym.usr, params.qualified, params.levels);
|
||||
break;
|
||||
case SymbolKind::Var: {
|
||||
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
|
||||
if (def && def->type)
|
||||
out.result = BuildInitial(SymbolKind::Type, def->type,
|
||||
params.qualified, params.levels);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -289,4 +266,4 @@ struct Handler_CclsMemberHierarchy
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "message_handler.h"
|
||||
#include "query_utils.h"
|
||||
#include "pipeline.hh"
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
@ -15,24 +15,21 @@ struct In_CclsVars : public RequestInMessage {
|
||||
unsigned kind = ~0u;
|
||||
} params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_CclsVars::Params,
|
||||
textDocument,
|
||||
position,
|
||||
kind);
|
||||
MAKE_REFLECT_STRUCT(In_CclsVars::Params, textDocument, position, kind);
|
||||
MAKE_REFLECT_STRUCT(In_CclsVars, id, params);
|
||||
REGISTER_IN_MESSAGE(In_CclsVars);
|
||||
|
||||
struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(In_CclsVars* request) override {
|
||||
auto& params = request->params;
|
||||
QueryFile* file;
|
||||
void Run(In_CclsVars *request) override {
|
||||
auto ¶ms = request->params;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file))
|
||||
return;
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList out;
|
||||
@ -41,24 +38,24 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
|
||||
FindSymbolsAtLocation(working_file, file, params.position)) {
|
||||
Usr usr = sym.usr;
|
||||
switch (sym.kind) {
|
||||
default:
|
||||
break;
|
||||
case SymbolKind::Var: {
|
||||
const QueryVar::Def* def = db->GetVar(sym).AnyDef();
|
||||
if (!def || !def->type)
|
||||
continue;
|
||||
usr = def->type;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case SymbolKind::Type:
|
||||
out.result = GetLsLocationExs(
|
||||
db, working_files,
|
||||
GetVarDeclarations(db, db->Type(usr).instances, params.kind));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case SymbolKind::Var: {
|
||||
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
|
||||
if (!def || !def->type)
|
||||
continue;
|
||||
usr = def->type;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case SymbolKind::Type:
|
||||
out.result = GetLsLocationExs(
|
||||
db, working_files,
|
||||
GetVarDeclarations(db, db->Type(usr).instances, params.kind));
|
||||
break;
|
||||
}
|
||||
}
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsVars);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -10,9 +10,7 @@ REGISTER_IN_MESSAGE(In_Exit);
|
||||
struct Handler_Exit : MessageHandler {
|
||||
MethodType GetMethodType() const override { return kMethodType_Exit; }
|
||||
|
||||
void Run(std::unique_ptr<InMessage> request) override {
|
||||
exit(0);
|
||||
}
|
||||
void Run(std::unique_ptr<InMessage> request) override { exit(0); }
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_Exit);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -55,8 +55,7 @@ struct lsDocumentOnTypeFormattingOptions {
|
||||
// More trigger characters.
|
||||
std::vector<std::string> moreTriggerCharacter;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions,
|
||||
firstTriggerCharacter,
|
||||
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, firstTriggerCharacter,
|
||||
moreTriggerCharacter);
|
||||
|
||||
// Document link options
|
||||
@ -119,12 +118,8 @@ struct lsTextDocumentSyncOptions {
|
||||
// Save notifications are sent to the server.
|
||||
std::optional<lsSaveOptions> save;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions,
|
||||
openClose,
|
||||
change,
|
||||
willSave,
|
||||
willSaveWaitUntil,
|
||||
save);
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, openClose, change, willSave,
|
||||
willSaveWaitUntil, save);
|
||||
|
||||
struct lsServerCapabilities {
|
||||
// Defines how text documents are synced. Is either a detailed structure
|
||||
@ -161,7 +156,8 @@ struct lsServerCapabilities {
|
||||
// The server provides document range formatting.
|
||||
bool documentRangeFormattingProvider = false;
|
||||
// The server provides document formatting on typing.
|
||||
std::optional<lsDocumentOnTypeFormattingOptions> documentOnTypeFormattingProvider;
|
||||
std::optional<lsDocumentOnTypeFormattingOptions>
|
||||
documentOnTypeFormattingProvider;
|
||||
// The server provides rename support.
|
||||
bool renameProvider = true;
|
||||
// The server provides document link support.
|
||||
@ -169,25 +165,15 @@ struct lsServerCapabilities {
|
||||
// The server provides execute command support.
|
||||
lsExecuteCommandOptions executeCommandProvider;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsServerCapabilities,
|
||||
textDocumentSync,
|
||||
hoverProvider,
|
||||
completionProvider,
|
||||
signatureHelpProvider,
|
||||
definitionProvider,
|
||||
typeDefinitionProvider,
|
||||
referencesProvider,
|
||||
documentHighlightProvider,
|
||||
documentSymbolProvider,
|
||||
workspaceSymbolProvider,
|
||||
codeActionProvider,
|
||||
codeLensProvider,
|
||||
documentFormattingProvider,
|
||||
documentRangeFormattingProvider,
|
||||
documentOnTypeFormattingProvider,
|
||||
renameProvider,
|
||||
documentLinkProvider,
|
||||
executeCommandProvider);
|
||||
MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider,
|
||||
completionProvider, signatureHelpProvider,
|
||||
definitionProvider, typeDefinitionProvider,
|
||||
referencesProvider, documentHighlightProvider,
|
||||
documentSymbolProvider, workspaceSymbolProvider,
|
||||
codeActionProvider, codeLensProvider,
|
||||
documentFormattingProvider, documentRangeFormattingProvider,
|
||||
documentOnTypeFormattingProvider, renameProvider,
|
||||
documentLinkProvider, executeCommandProvider);
|
||||
|
||||
// Workspace specific client capabilities.
|
||||
struct lsWorkspaceClientCapabilites {
|
||||
@ -226,12 +212,8 @@ MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsWorkspaceEdit,
|
||||
documentChanges);
|
||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsGenericDynamicReg,
|
||||
dynamicRegistration);
|
||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites,
|
||||
applyEdit,
|
||||
workspaceEdit,
|
||||
didChangeConfiguration,
|
||||
didChangeWatchedFiles,
|
||||
symbol,
|
||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites, applyEdit, workspaceEdit,
|
||||
didChangeConfiguration, didChangeWatchedFiles, symbol,
|
||||
executeCommand);
|
||||
|
||||
// Text document specific client capabilities.
|
||||
@ -287,13 +269,9 @@ struct lsTextDocumentClientCapabilities {
|
||||
};
|
||||
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsSynchronization,
|
||||
dynamicRegistration,
|
||||
willSave,
|
||||
willSaveWaitUntil,
|
||||
didSave);
|
||||
dynamicRegistration, willSave, willSaveWaitUntil, didSave);
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion,
|
||||
dynamicRegistration,
|
||||
completionItem);
|
||||
dynamicRegistration, completionItem);
|
||||
MAKE_REFLECT_STRUCT(
|
||||
lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem,
|
||||
snippetSupport);
|
||||
@ -301,12 +279,9 @@ MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsGenericDynamicReg,
|
||||
dynamicRegistration);
|
||||
MAKE_REFLECT_STRUCT(
|
||||
lsTextDocumentClientCapabilities::CodeLensRegistrationOptions,
|
||||
dynamicRegistration,
|
||||
resolveProvider);
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
|
||||
synchronization,
|
||||
completion,
|
||||
rename);
|
||||
dynamicRegistration, resolveProvider);
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities, synchronization,
|
||||
completion, rename);
|
||||
|
||||
struct lsClientCapabilities {
|
||||
// Workspace specific client capabilities.
|
||||
@ -343,16 +318,16 @@ struct lsInitializeParams {
|
||||
|
||||
enum class lsTrace {
|
||||
// NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose';
|
||||
Off, // off
|
||||
Messages, // messages
|
||||
Verbose // verbose
|
||||
Off, // off
|
||||
Messages, // messages
|
||||
Verbose // verbose
|
||||
};
|
||||
|
||||
// The initial trace setting. If omitted trace is disabled ('off').
|
||||
lsTrace trace = lsTrace::Off;
|
||||
};
|
||||
|
||||
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) {
|
||||
void Reflect(Reader &reader, lsInitializeParams::lsTrace &value) {
|
||||
if (!reader.IsString()) {
|
||||
value = lsInitializeParams::lsTrace::Off;
|
||||
return;
|
||||
@ -366,7 +341,7 @@ void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) {
|
||||
value = lsInitializeParams::lsTrace::Verbose;
|
||||
}
|
||||
|
||||
#if 0 // unused
|
||||
#if 0 // unused
|
||||
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
|
||||
switch (value) {
|
||||
case lsInitializeParams::lsTrace::Off:
|
||||
@ -382,13 +357,8 @@ void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
|
||||
}
|
||||
#endif
|
||||
|
||||
MAKE_REFLECT_STRUCT(lsInitializeParams,
|
||||
processId,
|
||||
rootPath,
|
||||
rootUri,
|
||||
initializationOptions,
|
||||
capabilities,
|
||||
trace);
|
||||
MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri,
|
||||
initializationOptions, capabilities, trace);
|
||||
|
||||
struct lsInitializeError {
|
||||
// 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> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(In_InitializeRequest* request) override {
|
||||
auto& params = request->params;
|
||||
void Run(In_InitializeRequest *request) override {
|
||||
auto ¶ms = request->params;
|
||||
if (!params.rootUri)
|
||||
return;
|
||||
std::string project_path = NormalizePath(params.rootUri->GetPath());
|
||||
@ -438,7 +408,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
JsonReader json_reader{&reader};
|
||||
try {
|
||||
Reflect(json_reader, *g_config);
|
||||
} catch (std::invalid_argument&) {
|
||||
} catch (std::invalid_argument &) {
|
||||
// This will not trigger because parse error is handled in
|
||||
// MessageRegistry::Parse in lsp.cc
|
||||
}
|
||||
@ -460,7 +430,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
}
|
||||
|
||||
// Client capabilities
|
||||
const auto& capabilities = params.capabilities;
|
||||
const auto &capabilities = params.capabilities;
|
||||
g_config->client.snippetSupport =
|
||||
capabilities.textDocument.completion.completionItem.snippetSupport;
|
||||
|
||||
@ -508,7 +478,8 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
std::string name = "indexer" + std::to_string(i);
|
||||
set_thread_name(name.c_str());
|
||||
pipeline::Indexer_Main(diag_pub, vfs, project, working_files);
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
// Start scanning include directories before dispatching project
|
||||
@ -520,4 +491,4 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
}
|
||||
};
|
||||
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> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_Shutdown* request) override {
|
||||
void Run(In_Shutdown *request) override {
|
||||
Out_Shutdown out;
|
||||
out.id = request->id;
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_Shutdown);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -33,10 +33,8 @@ struct In_TextDocumentCodeAction : public RequestInMessage {
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionContext,
|
||||
diagnostics);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams,
|
||||
textDocument,
|
||||
range,
|
||||
context);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams, textDocument,
|
||||
range, context);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params);
|
||||
REGISTER_IN_MESSAGE(In_TextDocumentCodeAction);
|
||||
|
||||
@ -51,7 +49,7 @@ struct Handler_TextDocumentCodeAction
|
||||
: BaseMessageHandler<In_TextDocumentCodeAction> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(In_TextDocumentCodeAction* request) override {
|
||||
void Run(In_TextDocumentCodeAction *request) override {
|
||||
const auto ¶ms = request->params;
|
||||
WorkingFile *wfile =
|
||||
working_files->GetFileByFilename(params.textDocument.uri.GetPath());
|
||||
@ -74,4 +72,4 @@ struct Handler_TextDocumentCodeAction
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction);
|
||||
}
|
||||
} // namespace
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "clang_complete.h"
|
||||
#include "lsp_code_action.h"
|
||||
#include "message_handler.h"
|
||||
#include "query_utils.h"
|
||||
#include "pipeline.hh"
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
@ -30,10 +30,10 @@ struct Out_TextDocumentCodeLens
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
|
||||
|
||||
struct CommonCodeLensParams {
|
||||
std::vector<TCodeLens>* result;
|
||||
DB* db;
|
||||
WorkingFiles* working_files;
|
||||
WorkingFile* working_file;
|
||||
std::vector<TCodeLens> *result;
|
||||
DB *db;
|
||||
WorkingFiles *working_files;
|
||||
WorkingFile *working_file;
|
||||
};
|
||||
|
||||
Use OffsetStartColumn(Use use, int16_t offset) {
|
||||
@ -41,12 +41,9 @@ Use OffsetStartColumn(Use use, int16_t offset) {
|
||||
return use;
|
||||
}
|
||||
|
||||
void AddCodeLens(const char* singular,
|
||||
const char* plural,
|
||||
CommonCodeLensParams* common,
|
||||
Use use,
|
||||
const std::vector<Use>& uses,
|
||||
bool force_display) {
|
||||
void AddCodeLens(const char *singular, const char *plural,
|
||||
CommonCodeLensParams *common, Use use,
|
||||
const std::vector<Use> &uses, bool force_display) {
|
||||
TCodeLens code_lens;
|
||||
std::optional<lsRange> range = GetLsRange(common->working_file, use.range);
|
||||
if (!range)
|
||||
@ -83,7 +80,7 @@ void AddCodeLens(const char* singular,
|
||||
struct Handler_TextDocumentCodeLens
|
||||
: BaseMessageHandler<In_TextDocumentCodeLens> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentCodeLens* request) override {
|
||||
void Run(In_TextDocumentCodeLens *request) override {
|
||||
Out_TextDocumentCodeLens out;
|
||||
out.id = request->id;
|
||||
|
||||
@ -92,7 +89,7 @@ struct Handler_TextDocumentCodeLens
|
||||
|
||||
clang_complete->NotifyView(path);
|
||||
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
@ -110,119 +107,118 @@ struct Handler_TextDocumentCodeLens
|
||||
Use use{{sym.range, sym.usr, sym.kind, sym.role}, file->id};
|
||||
|
||||
switch (sym.kind) {
|
||||
case SymbolKind::Type: {
|
||||
QueryType& type = db->GetType(sym);
|
||||
const QueryType::Def* def = type.AnyDef();
|
||||
if (!def || def->kind == lsSymbolKind::Namespace)
|
||||
continue;
|
||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
|
||||
type.uses, true /*force_display*/);
|
||||
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
|
||||
GetTypeDeclarations(db, type.derived),
|
||||
false /*force_display*/);
|
||||
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
|
||||
GetVarDeclarations(db, type.instances, true),
|
||||
false /*force_display*/);
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
QueryFunc& func = db->GetFunc(sym);
|
||||
const QueryFunc::Def* def = func.AnyDef();
|
||||
if (!def)
|
||||
continue;
|
||||
case SymbolKind::Type: {
|
||||
QueryType &type = db->GetType(sym);
|
||||
const QueryType::Def *def = type.AnyDef();
|
||||
if (!def || def->kind == lsSymbolKind::Namespace)
|
||||
continue;
|
||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
|
||||
type.uses, true /*force_display*/);
|
||||
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
|
||||
GetTypeDeclarations(db, type.derived),
|
||||
false /*force_display*/);
|
||||
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
|
||||
GetVarDeclarations(db, type.instances, true),
|
||||
false /*force_display*/);
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
QueryFunc &func = db->GetFunc(sym);
|
||||
const QueryFunc::Def *def = func.AnyDef();
|
||||
if (!def)
|
||||
continue;
|
||||
|
||||
int16_t offset = 0;
|
||||
int16_t offset = 0;
|
||||
|
||||
// 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 location to the spelling location.
|
||||
auto try_ensure_spelling = [&](Use use) {
|
||||
Maybe<Use> def = GetDefinitionSpell(db, use);
|
||||
if (!def || def->range.start.line != use.range.start.line) {
|
||||
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*/);
|
||||
// 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 location to the spelling location.
|
||||
auto try_ensure_spelling = [&](Use use) {
|
||||
Maybe<Use> def = GetDefinitionSpell(db, use);
|
||||
if (!def || def->range.start.line != use.range.start.line) {
|
||||
return use;
|
||||
}
|
||||
return *def;
|
||||
};
|
||||
|
||||
AddCodeLens("derived", "derived", &common,
|
||||
OffsetStartColumn(use, offset++),
|
||||
GetFuncDeclarations(db, func.derived),
|
||||
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*/);
|
||||
}
|
||||
|
||||
// "Base"
|
||||
if (def->bases.size() == 1) {
|
||||
Maybe<Use> base_loc = GetDefinitionSpell(
|
||||
db, SymbolIdx{def->bases[0], SymbolKind::Func});
|
||||
if (base_loc) {
|
||||
std::optional<lsLocation> ls_base =
|
||||
GetLsLocation(db, working_files, *base_loc);
|
||||
if (ls_base) {
|
||||
std::optional<lsRange> range =
|
||||
GetLsRange(common.working_file, sym.range);
|
||||
if (range) {
|
||||
TCodeLens code_lens;
|
||||
code_lens.range = *range;
|
||||
code_lens.range.start.character += offset++;
|
||||
code_lens.command = lsCommand<lsCodeLensCommandArguments>();
|
||||
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);
|
||||
}
|
||||
AddCodeLens(
|
||||
"derived", "derived", &common, OffsetStartColumn(use, offset++),
|
||||
GetFuncDeclarations(db, func.derived), false /*force_display*/);
|
||||
|
||||
// "Base"
|
||||
if (def->bases.size() == 1) {
|
||||
Maybe<Use> base_loc = GetDefinitionSpell(
|
||||
db, SymbolIdx{def->bases[0], SymbolKind::Func});
|
||||
if (base_loc) {
|
||||
std::optional<lsLocation> ls_base =
|
||||
GetLsLocation(db, working_files, *base_loc);
|
||||
if (ls_base) {
|
||||
std::optional<lsRange> range =
|
||||
GetLsRange(common.working_file, sym.range);
|
||||
if (range) {
|
||||
TCodeLens code_lens;
|
||||
code_lens.range = *range;
|
||||
code_lens.range.start.character += offset++;
|
||||
code_lens.command = lsCommand<lsCodeLensCommandArguments>();
|
||||
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*/);
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
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;
|
||||
// Do not show 0 refs on macro with no uses, as it is most likely
|
||||
// a header guard.
|
||||
if (def->kind == lsSymbolKind::Macro)
|
||||
force_display = false;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
QueryVar &var = db->GetVar(sym);
|
||||
const QueryVar::Def *def = var.AnyDef();
|
||||
if (!def || (def->is_local() && !g_config->codeLens.localVariables))
|
||||
continue;
|
||||
|
||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
|
||||
var.uses, force_display);
|
||||
break;
|
||||
}
|
||||
case SymbolKind::File:
|
||||
case SymbolKind::Invalid: {
|
||||
assert(false && "unexpected");
|
||||
break;
|
||||
}
|
||||
bool force_display = true;
|
||||
// Do not show 0 refs on macro with no uses, as it is most likely
|
||||
// a header guard.
|
||||
if (def->kind == lsSymbolKind::Macro)
|
||||
force_display = false;
|
||||
|
||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), var.uses,
|
||||
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);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -70,8 +70,8 @@ struct Out_TextDocumentComplete
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result);
|
||||
|
||||
void DecorateIncludePaths(const std::smatch& match,
|
||||
std::vector<lsCompletionItem>* items) {
|
||||
void DecorateIncludePaths(const std::smatch &match,
|
||||
std::vector<lsCompletionItem> *items) {
|
||||
std::string spaces_after_include = " ";
|
||||
if (match[3].compare("include") == 0 && match[5].length())
|
||||
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;
|
||||
std::string suffix = match[7].str();
|
||||
|
||||
for (lsCompletionItem& item : *items) {
|
||||
for (lsCompletionItem &item : *items) {
|
||||
char quote0, quote1;
|
||||
if (match[5].compare("<") == 0 ||
|
||||
(match[5].length() == 0 && item.use_angle_brackets_))
|
||||
@ -103,17 +103,16 @@ struct ParseIncludeLineResult {
|
||||
std::smatch match;
|
||||
};
|
||||
|
||||
ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
|
||||
static const std::regex pattern(
|
||||
"(\\s*)" // [1]: spaces before '#'
|
||||
"#" //
|
||||
"(\\s*)" // [2]: spaces after '#'
|
||||
"([^\\s\"<]*)" // [3]: "include"
|
||||
"(\\s*)" // [4]: spaces before quote
|
||||
"([\"<])?" // [5]: the first quote char
|
||||
"([^\\s\">]*)" // [6]: path of file
|
||||
"[\">]?" //
|
||||
"(.*)"); // [7]: suffix after quote char
|
||||
ParseIncludeLineResult ParseIncludeLine(const std::string &line) {
|
||||
static const std::regex pattern("(\\s*)" // [1]: spaces before '#'
|
||||
"#" //
|
||||
"(\\s*)" // [2]: spaces after '#'
|
||||
"([^\\s\"<]*)" // [3]: "include"
|
||||
"(\\s*)" // [4]: spaces before quote
|
||||
"([\"<])?" // [5]: the first quote char
|
||||
"([^\\s\">]*)" // [6]: path of file
|
||||
"[\">]?" //
|
||||
"(.*)"); // [7]: suffix after quote char
|
||||
std::smatch match;
|
||||
bool ok = std::regex_match(line, match, pattern);
|
||||
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",
|
||||
"else", "elif", "endif", "line", "error", "pragma"};
|
||||
|
||||
std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems(
|
||||
const std::smatch& match) {
|
||||
std::vector<lsCompletionItem>
|
||||
PreprocessorKeywordCompletionItems(const std::smatch &match) {
|
||||
std::vector<lsCompletionItem> items;
|
||||
for (auto& keyword : preprocessorKeywords) {
|
||||
for (auto &keyword : preprocessorKeywords) {
|
||||
lsCompletionItem item;
|
||||
item.label = keyword;
|
||||
item.priority_ = (keyword == "include" ? 2 : 1);
|
||||
@ -140,12 +139,10 @@ std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems(
|
||||
return items;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
char* tofixedbase64(T input, char* out) {
|
||||
const char* digits =
|
||||
"./0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
template <typename T> char *tofixedbase64(T input, char *out) {
|
||||
const char *digits = "./0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
int len = (sizeof(T) * 8 - 1) / 6 + 1;
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
out[i] = digits[input % 64];
|
||||
@ -159,16 +156,15 @@ char* tofixedbase64(T input, char* out) {
|
||||
// significantly snappier completion experience as vscode is easily overloaded
|
||||
// when given 1000+ completion items.
|
||||
void FilterAndSortCompletionResponse(
|
||||
Out_TextDocumentComplete* complete_response,
|
||||
const std::string& complete_text,
|
||||
bool has_open_paren) {
|
||||
Out_TextDocumentComplete *complete_response,
|
||||
const std::string &complete_text, bool has_open_paren) {
|
||||
if (!g_config->completion.filterAndSort)
|
||||
return;
|
||||
|
||||
static Timer timer("FilterAndSortCompletionResponse", "");
|
||||
TimeRegion region(timer);
|
||||
|
||||
auto& items = complete_response->result.items;
|
||||
auto &items = complete_response->result.items;
|
||||
|
||||
auto finalize = [&]() {
|
||||
const size_t kMaxResultSize = 100u;
|
||||
@ -178,7 +174,7 @@ void FilterAndSortCompletionResponse(
|
||||
}
|
||||
|
||||
if (has_open_paren)
|
||||
for (auto& item: items)
|
||||
for (auto &item : items)
|
||||
item.insertText = item.label;
|
||||
|
||||
// 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.
|
||||
for (auto& item : items) {
|
||||
for (auto &item : items) {
|
||||
if (!item.filterText)
|
||||
item.filterText = item.label;
|
||||
}
|
||||
@ -203,19 +199,19 @@ void FilterAndSortCompletionResponse(
|
||||
// Fuzzy match and remove awful candidates.
|
||||
bool sensitive = g_config->completion.caseSensitivity;
|
||||
FuzzyMatcher fuzzy(complete_text, sensitive);
|
||||
for (auto& item : items) {
|
||||
for (auto &item : items) {
|
||||
item.score_ =
|
||||
ReverseSubseqMatch(complete_text, *item.filterText, sensitive) >= 0
|
||||
? fuzzy.Match(*item.filterText)
|
||||
: FuzzyMatcher::kMinScore;
|
||||
}
|
||||
items.erase(std::remove_if(items.begin(), items.end(),
|
||||
[](const lsCompletionItem& item) {
|
||||
[](const lsCompletionItem &item) {
|
||||
return item.score_ <= FuzzyMatcher::kMinScore;
|
||||
}),
|
||||
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_)
|
||||
return lhs.score_ > rhs.score_;
|
||||
if (lhs.priority_ != rhs.priority_)
|
||||
@ -231,16 +227,17 @@ void FilterAndSortCompletionResponse(
|
||||
|
||||
// Returns true if position is an points to a '(' character in |lines|. Skips
|
||||
// whitespace.
|
||||
bool IsOpenParenOrAngle(const std::vector<std::string>& lines,
|
||||
const lsPosition& position) {
|
||||
bool IsOpenParenOrAngle(const std::vector<std::string> &lines,
|
||||
const lsPosition &position) {
|
||||
auto [c, l] = position;
|
||||
while (l < lines.size()) {
|
||||
const auto& line = lines[l];
|
||||
const auto &line = lines[l];
|
||||
if (c >= line.size())
|
||||
return false;
|
||||
if (line[c] == '(' || line[c] == '<')
|
||||
return true;
|
||||
if (!isspace(line[c])) break;
|
||||
if (!isspace(line[c]))
|
||||
break;
|
||||
if (++c >= line.size()) {
|
||||
c = 0;
|
||||
l++;
|
||||
@ -254,8 +251,8 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
||||
|
||||
void Run(std::unique_ptr<InMessage> message) override {
|
||||
auto request = std::shared_ptr<In_TextDocumentComplete>(
|
||||
static_cast<In_TextDocumentComplete*>(message.release()));
|
||||
auto& params = request->params;
|
||||
static_cast<In_TextDocumentComplete *>(message.release()));
|
||||
auto ¶ms = request->params;
|
||||
|
||||
auto write_empty_result = [request]() {
|
||||
Out_TextDocumentComplete out;
|
||||
@ -264,7 +261,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
||||
};
|
||||
|
||||
std::string path = params.textDocument.uri.GetPath();
|
||||
WorkingFile* file = working_files->GetFileByFilename(path);
|
||||
WorkingFile *file = working_files->GetFileByFilename(path);
|
||||
if (!file) {
|
||||
write_empty_result();
|
||||
return;
|
||||
@ -350,15 +347,16 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
||||
if (include_complete->is_scanning)
|
||||
lock.lock();
|
||||
std::string quote = result.match[5];
|
||||
for (auto& item : include_complete->completion_items)
|
||||
if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\""))
|
||||
out.result.items.push_back(item);
|
||||
for (auto &item : include_complete->completion_items)
|
||||
if (quote.empty() ||
|
||||
quote == (item.use_angle_brackets_ ? "<" : "\""))
|
||||
out.result.items.push_back(item);
|
||||
}
|
||||
FilterAndSortCompletionResponse(&out, result.pattern, has_open_paren);
|
||||
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.character = 0;
|
||||
item.textEdit->range.end.line = params.position.line;
|
||||
@ -369,14 +367,15 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
||||
} else {
|
||||
ClangCompleteManager::OnComplete callback = std::bind(
|
||||
[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) {
|
||||
Out_TextDocumentComplete out;
|
||||
out.id = request->id;
|
||||
out.result.items = results;
|
||||
|
||||
// Emit completion results.
|
||||
FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren);
|
||||
FilterAndSortCompletionResponse(&out, existing_completion,
|
||||
has_open_paren);
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
|
||||
// Cache completion results.
|
||||
@ -435,4 +434,4 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCompletion);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -3,9 +3,9 @@
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "textDocument/definition";
|
||||
@ -24,35 +24,35 @@ struct Out_TextDocumentDefinition
|
||||
};
|
||||
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) {
|
||||
case SymbolKind::Var: {
|
||||
std::vector<Use> ret = GetNonDefDeclarations(db, sym);
|
||||
// If there is no declaration, jump the its type.
|
||||
if (ret.empty()) {
|
||||
for (auto& def : db->GetVar(sym).def)
|
||||
if (def.type) {
|
||||
if (Maybe<Use> use = GetDefinitionSpell(
|
||||
db, SymbolIdx{def.type, SymbolKind::Type})) {
|
||||
ret.push_back(*use);
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
std::vector<Use> ret = GetNonDefDeclarations(db, sym);
|
||||
// If there is no declaration, jump the its type.
|
||||
if (ret.empty()) {
|
||||
for (auto &def : db->GetVar(sym).def)
|
||||
if (def.type) {
|
||||
if (Maybe<Use> use = GetDefinitionSpell(
|
||||
db, SymbolIdx{def.type, SymbolKind::Type})) {
|
||||
ret.push_back(*use);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return GetNonDefDeclarations(db, sym);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return GetNonDefDeclarations(db, sym);
|
||||
}
|
||||
}
|
||||
|
||||
struct Handler_TextDocumentDefinition
|
||||
: BaseMessageHandler<In_TextDocumentDefinition> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentDefinition* request) override {
|
||||
auto& params = request->params;
|
||||
void Run(In_TextDocumentDefinition *request) override {
|
||||
auto ¶ms = request->params;
|
||||
int file_id;
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file, &file_id))
|
||||
return;
|
||||
@ -62,9 +62,8 @@ struct Handler_TextDocumentDefinition
|
||||
|
||||
Maybe<Use> on_def;
|
||||
bool has_symbol = false;
|
||||
WorkingFile* wfile =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
lsPosition& ls_pos = params.position;
|
||||
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
|
||||
lsPosition &ls_pos = params.position;
|
||||
|
||||
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) {
|
||||
// Found symbol. Return definition.
|
||||
@ -75,7 +74,7 @@ struct Handler_TextDocumentDefinition
|
||||
// - start at spelling but end at extent for better mouse tooltip
|
||||
// - goto declaration while in definition of recursive type
|
||||
std::vector<Use> uses;
|
||||
EachEntityDef(db, sym, [&](const auto& def) {
|
||||
EachEntityDef(db, sym, [&](const auto &def) {
|
||||
if (def.spell && def.extent) {
|
||||
Use spell = *def.spell;
|
||||
// If on a definition, clear |uses| to find declarations below.
|
||||
@ -109,7 +108,7 @@ struct Handler_TextDocumentDefinition
|
||||
|
||||
// No symbols - check for includes.
|
||||
if (out.result.empty()) {
|
||||
for (const IndexInclude& include : file->def->includes) {
|
||||
for (const IndexInclude &include : file->def->includes) {
|
||||
if (include.line == ls_pos.line) {
|
||||
lsLocationEx result;
|
||||
result.uri = lsDocumentUri::FromPath(include.resolved_path);
|
||||
@ -121,7 +120,7 @@ struct Handler_TextDocumentDefinition
|
||||
// Find the best match of the identifier at point.
|
||||
if (!has_symbol) {
|
||||
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 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});
|
||||
for (auto& type : db->types)
|
||||
for (auto &type : db->types)
|
||||
fn({type.usr, SymbolKind::Type});
|
||||
for (auto& var : db->vars)
|
||||
for (auto &var : db->vars)
|
||||
if (var.def.size() && !var.def[0].is_local())
|
||||
fn({var.usr, SymbolKind::Var});
|
||||
|
||||
@ -183,4 +182,4 @@ struct Handler_TextDocumentDefinition
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "clang_complete.h"
|
||||
#include "message_handler.h"
|
||||
#include "pipeline.hh"
|
||||
#include "project.h"
|
||||
#include "working_files.h"
|
||||
#include "pipeline.hh"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
@ -20,7 +20,7 @@ struct Handler_TextDocumentDidChange
|
||||
: BaseMessageHandler<In_TextDocumentDidChange> {
|
||||
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();
|
||||
working_files->OnChange(request->params);
|
||||
if (g_config->index.onDidChange) {
|
||||
@ -33,4 +33,4 @@ struct Handler_TextDocumentDidChange
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -22,7 +22,7 @@ struct Handler_TextDocumentDidClose
|
||||
: BaseMessageHandler<In_TextDocumentDidClose> {
|
||||
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();
|
||||
|
||||
// Clear any diagnostics for the file.
|
||||
@ -36,4 +36,4 @@ struct Handler_TextDocumentDidClose
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "clang_complete.h"
|
||||
#include "include_complete.h"
|
||||
#include "message_handler.h"
|
||||
#include "project.h"
|
||||
#include "pipeline.hh"
|
||||
#include "project.h"
|
||||
#include "working_files.h"
|
||||
using namespace ccls;
|
||||
|
||||
@ -12,7 +12,7 @@ MethodType kMethodType = "textDocument/didOpen";
|
||||
// Open, view, change, close file
|
||||
struct In_TextDocumentDidOpen : public NotificationInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
|
||||
struct Params {
|
||||
lsTextDocumentItem textDocument;
|
||||
|
||||
@ -31,18 +31,18 @@ struct Handler_TextDocumentDidOpen
|
||||
: BaseMessageHandler<In_TextDocumentDidOpen> {
|
||||
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
|
||||
// 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();
|
||||
|
||||
WorkingFile* working_file = working_files->OnOpen(params.textDocument);
|
||||
WorkingFile *working_file = working_files->OnOpen(params.textDocument);
|
||||
if (std::optional<std::string> cached_file_contents =
|
||||
pipeline::LoadCachedFileContents(path))
|
||||
working_file->SetIndexContent(*cached_file_contents);
|
||||
|
||||
QueryFile* file = nullptr;
|
||||
QueryFile *file = nullptr;
|
||||
FindFileOrFail(db, project, std::nullopt, path, &file);
|
||||
if (file && file->def) {
|
||||
EmitSkippedRanges(working_file, file->def->skipped_ranges);
|
||||
@ -68,4 +68,4 @@ struct Handler_TextDocumentDidOpen
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "clang_complete.h"
|
||||
#include "message_handler.h"
|
||||
#include "project.h"
|
||||
#include "pipeline.hh"
|
||||
#include "project.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
@ -28,8 +28,8 @@ struct Handler_TextDocumentDidSave
|
||||
: BaseMessageHandler<In_TextDocumentDidSave> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(In_TextDocumentDidSave* request) override {
|
||||
const auto& params = request->params;
|
||||
void Run(In_TextDocumentDidSave *request) override {
|
||||
const auto ¶ms = request->params;
|
||||
std::string path = params.textDocument.uri.GetPath();
|
||||
|
||||
// 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);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -24,16 +24,16 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentHighlight, jsonrpc, id, result);
|
||||
struct Handler_TextDocumentDocumentHighlight
|
||||
: BaseMessageHandler<In_TextDocumentDocumentHighlight> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentDocumentHighlight* request) override {
|
||||
void Run(In_TextDocumentDocumentHighlight *request) override {
|
||||
int file_id;
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file,
|
||||
&file_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentDocumentHighlight out;
|
||||
@ -66,4 +66,4 @@ struct Handler_TextDocumentDocumentHighlight
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -38,10 +38,10 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
|
||||
struct Handler_TextDocumentDocumentSymbol
|
||||
: BaseMessageHandler<In_TextDocumentDocumentSymbol> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentDocumentSymbol* request) override {
|
||||
auto& params = request->params;
|
||||
void Run(In_TextDocumentDocumentSymbol *request) override {
|
||||
auto ¶ms = request->params;
|
||||
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
int file_id;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file, &file_id))
|
||||
@ -67,8 +67,8 @@ struct Handler_TextDocumentDocumentSymbol
|
||||
if (std::optional<lsSymbolInformation> info =
|
||||
GetSymbolInfo(db, working_files, sym, false)) {
|
||||
if (sym.kind == SymbolKind::Var) {
|
||||
QueryVar& var = db->GetVar(sym);
|
||||
auto* def = var.AnyDef();
|
||||
QueryVar &var = db->GetVar(sym);
|
||||
auto *def = var.AnyDef();
|
||||
if (!def || !def->spell || def->is_local())
|
||||
continue;
|
||||
}
|
||||
@ -84,4 +84,4 @@ struct Handler_TextDocumentDocumentSymbol
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -7,10 +7,10 @@ namespace {
|
||||
MethodType kMethodType = "textDocument/hover";
|
||||
|
||||
// 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;
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
if (const auto* def = entity.AnyDef())
|
||||
WithEntity(db, sym, [&](const auto &entity) {
|
||||
if (const auto *def = entity.AnyDef())
|
||||
if (def->comments[0]) {
|
||||
lsMarkedString m;
|
||||
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.
|
||||
std::optional<lsMarkedString> GetHoverOrName(DB* db,
|
||||
LanguageId lang,
|
||||
std::optional<lsMarkedString> GetHoverOrName(DB *db, LanguageId lang,
|
||||
SymbolRef sym) {
|
||||
std::optional<lsMarkedString> ret;
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
if (const auto* def = entity.AnyDef()) {
|
||||
WithEntity(db, sym, [&](const auto &entity) {
|
||||
if (const auto *def = entity.AnyDef()) {
|
||||
lsMarkedString m;
|
||||
m.language = LanguageIdentifier(lang);
|
||||
if (def->hover[0]) {
|
||||
@ -58,21 +57,19 @@ struct Out_TextDocumentHover : public lsOutMessage<Out_TextDocumentHover> {
|
||||
std::optional<Result> result;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range);
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover,
|
||||
jsonrpc,
|
||||
id,
|
||||
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover, jsonrpc, id,
|
||||
result);
|
||||
|
||||
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentHover* request) override {
|
||||
auto& params = request->params;
|
||||
QueryFile* file;
|
||||
void Run(In_TextDocumentHover *request) override {
|
||||
auto ¶ms = request->params;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file))
|
||||
return;
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentHover out;
|
||||
@ -104,4 +101,4 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "message_handler.h"
|
||||
#include "query_utils.h"
|
||||
#include "pipeline.hh"
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
@ -16,14 +16,14 @@ REGISTER_IN_MESSAGE(In_TextDocumentImplementation);
|
||||
struct Handler_TextDocumentImplementation
|
||||
: BaseMessageHandler<In_TextDocumentImplementation> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentImplementation* request) override {
|
||||
QueryFile* file;
|
||||
void Run(In_TextDocumentImplementation *request) override {
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList out;
|
||||
@ -31,12 +31,12 @@ struct Handler_TextDocumentImplementation
|
||||
for (SymbolRef sym :
|
||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||
if (sym.kind == SymbolKind::Type) {
|
||||
QueryType& type = db->GetType(sym);
|
||||
QueryType &type = db->GetType(sym);
|
||||
out.result = GetLsLocationExs(db, working_files,
|
||||
GetTypeDeclarations(db, type.derived));
|
||||
break;
|
||||
} else if (sym.kind == SymbolKind::Func) {
|
||||
QueryFunc& func = db->GetFunc(sym);
|
||||
QueryFunc &func = db->GetFunc(sym);
|
||||
out.result = GetLsLocationExs(db, working_files,
|
||||
GetFuncDeclarations(db, func.derived));
|
||||
break;
|
||||
@ -46,4 +46,4 @@ struct Handler_TextDocumentImplementation
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -27,14 +27,9 @@ struct In_TextDocumentReferences : public RequestInMessage {
|
||||
|
||||
Params params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::lsReferenceContext,
|
||||
base,
|
||||
excludeRole,
|
||||
includeDeclaration,
|
||||
role);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params,
|
||||
textDocument,
|
||||
position,
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::lsReferenceContext, base,
|
||||
excludeRole, includeDeclaration, role);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params, textDocument, position,
|
||||
context);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences, id, params);
|
||||
REGISTER_IN_MESSAGE(In_TextDocumentReferences);
|
||||
@ -50,15 +45,14 @@ struct Handler_TextDocumentReferences
|
||||
: BaseMessageHandler<In_TextDocumentReferences> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(In_TextDocumentReferences* request) override {
|
||||
auto& params = request->params;
|
||||
QueryFile* file;
|
||||
void Run(In_TextDocumentReferences *request) override {
|
||||
auto ¶ms = request->params;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
params.textDocument.uri.GetPath(), &file))
|
||||
return;
|
||||
|
||||
WorkingFile* wfile =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentReferences out;
|
||||
out.id = request->id;
|
||||
@ -86,9 +80,9 @@ struct Handler_TextDocumentReferences
|
||||
out.result.push_back(*ls_loc);
|
||||
}
|
||||
};
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
WithEntity(db, sym, [&](const auto &entity) {
|
||||
lsSymbolKind parent_kind = lsSymbolKind::Unknown;
|
||||
for (auto& def : entity.def)
|
||||
for (auto &def : entity.def)
|
||||
if (def.spell) {
|
||||
parent_kind = GetSymbolKind(db, sym);
|
||||
if (params.context.base)
|
||||
@ -102,7 +96,7 @@ struct Handler_TextDocumentReferences
|
||||
for (Use use : entity.uses)
|
||||
fn(use, parent_kind);
|
||||
if (params.context.includeDeclaration) {
|
||||
for (auto& def : entity.def)
|
||||
for (auto &def : entity.def)
|
||||
if (def.spell)
|
||||
fn(*def.spell, parent_kind);
|
||||
for (Use use : entity.declarations)
|
||||
@ -120,21 +114,20 @@ struct Handler_TextDocumentReferences
|
||||
std::string path;
|
||||
if (params.position.line == 0)
|
||||
path = file->def->path;
|
||||
for (const IndexInclude& include : file->def->includes)
|
||||
for (const IndexInclude &include : file->def->includes)
|
||||
if (include.line == params.position.line) {
|
||||
path = include.resolved_path;
|
||||
break;
|
||||
}
|
||||
if (path.size())
|
||||
for (QueryFile& file1 : db->files)
|
||||
for (QueryFile &file1 : db->files)
|
||||
if (file1.def)
|
||||
for (const IndexInclude& include : file1.def->includes)
|
||||
for (const IndexInclude &include : file1.def->includes)
|
||||
if (include.resolved_path == path) {
|
||||
// Another file |file1| has the same include line.
|
||||
lsLocationEx result;
|
||||
result.uri = lsDocumentUri::FromPath(file1.def->path);
|
||||
result.range.start.line = result.range.end.line =
|
||||
include.line;
|
||||
result.range.start.line = result.range.end.line = include.line;
|
||||
out.result.push_back(std::move(result));
|
||||
break;
|
||||
}
|
||||
@ -146,4 +139,4 @@ struct Handler_TextDocumentReferences
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,19 +1,18 @@
|
||||
#include "message_handler.h"
|
||||
#include "query_utils.h"
|
||||
#include "pipeline.hh"
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "textDocument/rename";
|
||||
|
||||
lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
SymbolRef sym,
|
||||
const std::string& new_text) {
|
||||
lsWorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *working_files,
|
||||
SymbolRef sym, const std::string &new_text) {
|
||||
std::unordered_map<int, lsTextDocumentEdit> path_to_edit;
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -21,14 +20,14 @@ lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
|
||||
if (path_to_edit.find(file_id) == path_to_edit.end()) {
|
||||
path_to_edit[file_id] = lsTextDocumentEdit();
|
||||
|
||||
QueryFile& file = db->files[file_id];
|
||||
QueryFile &file = db->files[file_id];
|
||||
if (!file.def)
|
||||
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);
|
||||
|
||||
WorkingFile* working_file = working_files->GetFileByFilename(path);
|
||||
WorkingFile *working_file = working_files->GetFileByFilename(path);
|
||||
if (working_file)
|
||||
path_to_edit[file_id].textDocument.version = working_file->version;
|
||||
}
|
||||
@ -38,13 +37,13 @@ lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
|
||||
edit.newText = new_text;
|
||||
|
||||
// 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())
|
||||
edits.push_back(edit);
|
||||
});
|
||||
|
||||
lsWorkspaceEdit edit;
|
||||
for (const auto& changes : path_to_edit)
|
||||
for (const auto &changes : path_to_edit)
|
||||
edit.documentChanges.push_back(changes.second);
|
||||
return edit;
|
||||
}
|
||||
@ -65,9 +64,7 @@ struct In_TextDocumentRename : public RequestInMessage {
|
||||
};
|
||||
Params params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params,
|
||||
textDocument,
|
||||
position,
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params, textDocument, position,
|
||||
newName);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params);
|
||||
REGISTER_IN_MESSAGE(In_TextDocumentRename);
|
||||
@ -80,16 +77,16 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result);
|
||||
|
||||
struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentRename* request) override {
|
||||
void Run(In_TextDocumentRename *request) override {
|
||||
int file_id;
|
||||
QueryFile* file;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file,
|
||||
&file_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentRename out;
|
||||
@ -107,4 +104,4 @@ struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -70,9 +70,7 @@ struct lsSignatureHelp {
|
||||
// active signature does have any.
|
||||
std::optional<int> activeParameter;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsSignatureHelp,
|
||||
signatures,
|
||||
activeSignature,
|
||||
MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature,
|
||||
activeParameter);
|
||||
|
||||
struct Out_TextDocumentSignatureHelp
|
||||
@ -86,9 +84,9 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(std::unique_ptr<InMessage> message) override {
|
||||
auto request = static_cast<In_TextDocumentSignatureHelp*>(message.get());
|
||||
lsTextDocumentPositionParams& params = request->params;
|
||||
WorkingFile* file =
|
||||
auto request = static_cast<In_TextDocumentSignatureHelp *>(message.get());
|
||||
lsTextDocumentPositionParams ¶ms = request->params;
|
||||
WorkingFile *file =
|
||||
working_files->GetFileByFilename(params.textDocument.uri.GetPath());
|
||||
std::string search;
|
||||
int active_param = 0;
|
||||
@ -102,21 +100,21 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
|
||||
return;
|
||||
|
||||
ClangCompleteManager::OnComplete callback = std::bind(
|
||||
[this](InMessage* message, std::string search, int active_param,
|
||||
const std::vector<lsCompletionItem>& results,
|
||||
[this](InMessage *message, std::string search, int active_param,
|
||||
const std::vector<lsCompletionItem> &results,
|
||||
bool is_cached_result) {
|
||||
auto msg = static_cast<In_TextDocumentSignatureHelp*>(message);
|
||||
auto msg = static_cast<In_TextDocumentSignatureHelp *>(message);
|
||||
|
||||
Out_TextDocumentSignatureHelp out;
|
||||
out.id = msg->id;
|
||||
|
||||
for (auto& result : results) {
|
||||
for (auto &result : results) {
|
||||
if (result.label != search)
|
||||
continue;
|
||||
|
||||
lsSignatureInformation signature;
|
||||
signature.label = result.detail;
|
||||
for (auto& parameter : result.parameters_) {
|
||||
for (auto ¶meter : result.parameters_) {
|
||||
lsParameterInformation ls_param;
|
||||
ls_param.label = parameter;
|
||||
signature.parameters.push_back(ls_param);
|
||||
@ -168,4 +166,4 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentSignatureHelp);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -23,14 +23,14 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentTypeDefinition, jsonrpc, id, result);
|
||||
struct Handler_TextDocumentTypeDefinition
|
||||
: BaseMessageHandler<In_TextDocumentTypeDefinition> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentTypeDefinition* request) override {
|
||||
QueryFile* file;
|
||||
void Run(In_TextDocumentTypeDefinition *request) override {
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file,
|
||||
nullptr)) {
|
||||
return;
|
||||
}
|
||||
WorkingFile* working_file =
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentTypeDefinition out;
|
||||
@ -39,25 +39,25 @@ struct Handler_TextDocumentTypeDefinition
|
||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||
Usr usr = sym.usr;
|
||||
switch (sym.kind) {
|
||||
case SymbolKind::Var: {
|
||||
const QueryVar::Def* def = db->GetVar(sym).AnyDef();
|
||||
if (!def || !def->type)
|
||||
continue;
|
||||
usr = def->type;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
QueryType& type = db->Type(usr);
|
||||
for (const auto& def : type.def)
|
||||
if (def.spell) {
|
||||
if (auto ls_loc = GetLsLocationEx(db, working_files, *def.spell,
|
||||
g_config->xref.container))
|
||||
out.result.push_back(*ls_loc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case SymbolKind::Var: {
|
||||
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
|
||||
if (!def || !def->type)
|
||||
continue;
|
||||
usr = def->type;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
QueryType &type = db->Type(usr);
|
||||
for (const auto &def : type.def)
|
||||
if (def.spell) {
|
||||
if (auto ls_loc = GetLsLocationEx(db, working_files, *def.spell,
|
||||
g_config->xref.container))
|
||||
out.result.push_back(*ls_loc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,4 +66,4 @@ struct Handler_TextDocumentTypeDefinition
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "clang_complete.h"
|
||||
#include "message_handler.h"
|
||||
#include "project.h"
|
||||
#include "pipeline.hh"
|
||||
#include "project.h"
|
||||
#include "working_files.h"
|
||||
using namespace ccls;
|
||||
|
||||
@ -23,7 +23,7 @@ REGISTER_IN_MESSAGE(In_WorkspaceDidChangeConfiguration);
|
||||
struct Handler_WorkspaceDidChangeConfiguration
|
||||
: BaseMessageHandler<In_WorkspaceDidChangeConfiguration> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_WorkspaceDidChangeConfiguration* request) override {
|
||||
void Run(In_WorkspaceDidChangeConfiguration *request) override {
|
||||
project->Load(g_config->projectRoot);
|
||||
project->Index(working_files, lsRequestId());
|
||||
|
||||
@ -31,4 +31,4 @@ struct Handler_WorkspaceDidChangeConfiguration
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeConfiguration);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "clang_complete.h"
|
||||
#include "message_handler.h"
|
||||
#include "project.h"
|
||||
#include "pipeline.hh"
|
||||
#include "project.h"
|
||||
#include "working_files.h"
|
||||
using namespace ccls;
|
||||
|
||||
@ -36,8 +36,8 @@ REGISTER_IN_MESSAGE(In_WorkspaceDidChangeWatchedFiles);
|
||||
struct Handler_WorkspaceDidChangeWatchedFiles
|
||||
: BaseMessageHandler<In_WorkspaceDidChangeWatchedFiles> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_WorkspaceDidChangeWatchedFiles* request) override {
|
||||
for (lsFileEvent& event : request->params.changes) {
|
||||
void Run(In_WorkspaceDidChangeWatchedFiles *request) override {
|
||||
for (lsFileEvent &event : request->params.changes) {
|
||||
std::string path = event.uri.GetPath();
|
||||
Project::Entry entry;
|
||||
{
|
||||
@ -50,19 +50,19 @@ struct Handler_WorkspaceDidChangeWatchedFiles
|
||||
bool is_interactive =
|
||||
working_files->GetFileByFilename(entry.filename) != nullptr;
|
||||
switch (event.type) {
|
||||
case lsFileChangeType::Created:
|
||||
case lsFileChangeType::Changed: {
|
||||
pipeline::Index(path, entry.args, is_interactive);
|
||||
if (is_interactive)
|
||||
clang_complete->NotifySave(path);
|
||||
break;
|
||||
}
|
||||
case lsFileChangeType::Deleted:
|
||||
pipeline::Index(path, entry.args, is_interactive);
|
||||
break;
|
||||
case lsFileChangeType::Created:
|
||||
case lsFileChangeType::Changed: {
|
||||
pipeline::Index(path, entry.args, is_interactive);
|
||||
if (is_interactive)
|
||||
clang_complete->NotifySave(path);
|
||||
break;
|
||||
}
|
||||
case lsFileChangeType::Deleted:
|
||||
pipeline::Index(path, entry.args, is_interactive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeWatchedFiles);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "lsp_code_action.h"
|
||||
#include "message_handler.h"
|
||||
#include "query_utils.h"
|
||||
#include "pipeline.hh"
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
@ -24,8 +24,8 @@ MAKE_REFLECT_STRUCT(Out_WorkspaceExecuteCommand, jsonrpc, id, result);
|
||||
struct Handler_WorkspaceExecuteCommand
|
||||
: BaseMessageHandler<In_WorkspaceExecuteCommand> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_WorkspaceExecuteCommand* request) override {
|
||||
const auto& params = request->params;
|
||||
void Run(In_WorkspaceExecuteCommand *request) override {
|
||||
const auto ¶ms = request->params;
|
||||
Out_WorkspaceExecuteCommand out;
|
||||
out.id = request->id;
|
||||
if (params.command == "ccls._applyFixIt") {
|
||||
@ -40,4 +40,4 @@ struct Handler_WorkspaceExecuteCommand
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -4,21 +4,18 @@
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
#include <functional>
|
||||
#include <limits.h>
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "workspace/symbol";
|
||||
|
||||
// Lookup |symbol| in |db| and insert the value into |result|.
|
||||
bool AddSymbol(
|
||||
DB* db,
|
||||
WorkingFiles* working_files,
|
||||
SymbolIdx sym,
|
||||
bool use_detailed,
|
||||
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>>* result) {
|
||||
DB *db, WorkingFiles *working_files, SymbolIdx sym, bool use_detailed,
|
||||
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) {
|
||||
std::optional<lsSymbolInformation> info =
|
||||
GetSymbolInfo(db, working_files, sym, true);
|
||||
if (!info)
|
||||
@ -63,7 +60,7 @@ MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result);
|
||||
|
||||
struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_WorkspaceSymbol* request) override {
|
||||
void Run(In_WorkspaceSymbol *request) override {
|
||||
Out_WorkspaceSymbol out;
|
||||
out.id = request->id;
|
||||
|
||||
@ -83,40 +80,41 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
||||
auto Add = [&](SymbolIdx sym) {
|
||||
std::string_view detailed_name = db->GetSymbolName(sym, true);
|
||||
int pos =
|
||||
ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
|
||||
ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
|
||||
return pos >= 0 &&
|
||||
AddSymbol(db, working_files, sym,
|
||||
detailed_name.find(':', pos) != std::string::npos,
|
||||
&cands) &&
|
||||
cands.size() >= g_config->workspaceSymbol.maxNum;
|
||||
};
|
||||
for (auto& func : db->funcs)
|
||||
for (auto &func : db->funcs)
|
||||
if (Add({func.usr, SymbolKind::Func}))
|
||||
goto done_add;
|
||||
for (auto& type : db->types)
|
||||
for (auto &type : db->types)
|
||||
if (Add({type.usr, SymbolKind::Type}))
|
||||
goto done_add;
|
||||
for (auto& var : db->vars)
|
||||
for (auto &var : db->vars)
|
||||
if (var.def.size() && !var.def[0].is_local() &&
|
||||
Add({var.usr, SymbolKind::Var}))
|
||||
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.
|
||||
int longest = 0;
|
||||
for (auto& cand : cands)
|
||||
for (auto &cand : cands)
|
||||
longest = std::max(
|
||||
longest, int(db->GetSymbolName(std::get<2>(cand), true).size()));
|
||||
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
|
||||
for (auto& cand : cands)
|
||||
for (auto &cand : cands)
|
||||
std::get<1>(cand) = fuzzy.Match(
|
||||
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);
|
||||
});
|
||||
out.result.reserve(cands.size());
|
||||
for (auto& cand: cands) {
|
||||
for (auto &cand : cands) {
|
||||
// Discard awful candidates.
|
||||
if (std::get<1>(cand) <= FuzzyMatcher::kMinScore)
|
||||
break;
|
||||
@ -124,7 +122,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
||||
}
|
||||
} else {
|
||||
out.result.reserve(cands.size());
|
||||
for (auto& cand : cands)
|
||||
for (auto &cand : cands)
|
||||
out.result.push_back(std::get<0>(cand));
|
||||
}
|
||||
|
||||
@ -132,4 +130,4 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -4,12 +4,11 @@ MethodType kMethodType_Unknown = "$unknown";
|
||||
MethodType kMethodType_Exit = "exit";
|
||||
MethodType kMethodType_TextDocumentPublishDiagnostics =
|
||||
"textDocument/publishDiagnostics";
|
||||
MethodType kMethodType_CclsPublishSkippedRanges =
|
||||
"$ccls/publishSkippedRanges";
|
||||
MethodType kMethodType_CclsPublishSkippedRanges = "$ccls/publishSkippedRanges";
|
||||
MethodType kMethodType_CclsPublishSemanticHighlighting =
|
||||
"$ccls/publishSemanticHighlighting";
|
||||
|
||||
void Reflect(Reader& visitor, lsRequestId& value) {
|
||||
void Reflect(Reader &visitor, lsRequestId &value) {
|
||||
if (visitor.IsInt64()) {
|
||||
value.type = lsRequestId::kInt;
|
||||
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) {
|
||||
case lsRequestId::kNone:
|
||||
visitor.Null();
|
||||
|
14
src/method.h
14
src/method.h
@ -5,7 +5,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
using MethodType = const char*;
|
||||
using MethodType = const char *;
|
||||
extern MethodType kMethodType_Unknown;
|
||||
extern MethodType kMethodType_Exit;
|
||||
extern MethodType kMethodType_TextDocumentPublishDiagnostics;
|
||||
@ -22,8 +22,8 @@ struct lsRequestId {
|
||||
|
||||
bool Valid() const { return type != kNone; }
|
||||
};
|
||||
void Reflect(Reader& visitor, lsRequestId& value);
|
||||
void Reflect(Writer& visitor, lsRequestId& value);
|
||||
void Reflect(Reader &visitor, lsRequestId &value);
|
||||
void Reflect(Writer &visitor, lsRequestId &value);
|
||||
|
||||
struct InMessage {
|
||||
virtual ~InMessage() = default;
|
||||
@ -35,14 +35,10 @@ struct InMessage {
|
||||
struct RequestInMessage : public InMessage {
|
||||
// number or string, actually no null
|
||||
lsRequestId id;
|
||||
lsRequestId GetRequestId() const override {
|
||||
return id;
|
||||
}
|
||||
lsRequestId GetRequestId() const override { return id; }
|
||||
};
|
||||
|
||||
// NotificationInMessage does not have |id|.
|
||||
struct NotificationInMessage : public InMessage {
|
||||
lsRequestId GetRequestId() const override {
|
||||
return lsRequestId();
|
||||
}
|
||||
lsRequestId GetRequestId() const override { return lsRequestId(); }
|
||||
};
|
||||
|
116
src/pipeline.cc
116
src/pipeline.cc
@ -6,10 +6,10 @@
|
||||
#include "log.hh"
|
||||
#include "lsp.h"
|
||||
#include "message_handler.h"
|
||||
#include "pipeline.hh"
|
||||
#include "platform.h"
|
||||
#include "project.h"
|
||||
#include "query_utils.h"
|
||||
#include "pipeline.hh"
|
||||
|
||||
#include <llvm/ADT/Twine.h>
|
||||
#include <llvm/Support/Threading.h>
|
||||
@ -28,12 +28,12 @@ void DiagnosticsPublisher::Init() {
|
||||
g_config->diagnostics.blacklist);
|
||||
}
|
||||
|
||||
void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
|
||||
void DiagnosticsPublisher::Publish(WorkingFiles *working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics) {
|
||||
bool good = true;
|
||||
// Cache diagnostics so we can show fixits.
|
||||
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
||||
working_files->DoActionOnFile(path, [&](WorkingFile *working_file) {
|
||||
if (working_file) {
|
||||
good = working_file->diagnostics_.empty();
|
||||
working_file->diagnostics_ = diagnostics;
|
||||
@ -52,7 +52,8 @@ void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
|
||||
Out_TextDocumentPublishDiagnostics out;
|
||||
out.params.uri = lsDocumentUri::FromPath(path);
|
||||
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;
|
||||
};
|
||||
|
||||
MultiQueueWaiter* main_waiter;
|
||||
MultiQueueWaiter* indexer_waiter;
|
||||
MultiQueueWaiter* stdout_waiter;
|
||||
ThreadedQueue<std::unique_ptr<InMessage>>* on_request;
|
||||
ThreadedQueue<Index_Request>* index_request;
|
||||
ThreadedQueue<IndexUpdate>* on_indexed;
|
||||
ThreadedQueue<Stdout_Request>* for_stdout;
|
||||
MultiQueueWaiter *main_waiter;
|
||||
MultiQueueWaiter *indexer_waiter;
|
||||
MultiQueueWaiter *stdout_waiter;
|
||||
ThreadedQueue<std::unique_ptr<InMessage>> *on_request;
|
||||
ThreadedQueue<Index_Request> *index_request;
|
||||
ThreadedQueue<IndexUpdate> *on_indexed;
|
||||
ThreadedQueue<Stdout_Request> *for_stdout;
|
||||
|
||||
bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
|
||||
const std::vector<std::string> &args,
|
||||
@ -92,23 +93,24 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
|
||||
}
|
||||
|
||||
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 false;
|
||||
};
|
||||
|
||||
std::string AppendSerializationFormat(const std::string& base) {
|
||||
std::string AppendSerializationFormat(const std::string &base) {
|
||||
switch (g_config->cacheFormat) {
|
||||
case SerializeFormat::Binary:
|
||||
return base + ".blob";
|
||||
case SerializeFormat::Json:
|
||||
return base + ".json";
|
||||
case SerializeFormat::Binary:
|
||||
return base + ".blob";
|
||||
case SerializeFormat::Json:
|
||||
return base + ".json";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetCachePath(const std::string& source_file) {
|
||||
std::string GetCachePath(const std::string &source_file) {
|
||||
std::string cache_file;
|
||||
size_t len = g_config->projectRoot.size();
|
||||
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;
|
||||
}
|
||||
|
||||
std::unique_ptr<IndexFile> RawCacheLoad(
|
||||
const std::string& path) {
|
||||
std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
|
||||
std::string cache_path = GetCachePath(path);
|
||||
std::optional<std::string> file_content = ReadContent(cache_path);
|
||||
std::optional<std::string> serialized_indexed_content =
|
||||
@ -136,14 +137,12 @@ std::unique_ptr<IndexFile> RawCacheLoad(
|
||||
IndexFile::kMajorVersion);
|
||||
}
|
||||
|
||||
bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
WorkingFiles* working_files,
|
||||
Project* project,
|
||||
VFS* vfs) {
|
||||
bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
|
||||
Project *project, VFS *vfs) {
|
||||
std::optional<Index_Request> opt_request = index_request->TryPopFront();
|
||||
if (!opt_request)
|
||||
return false;
|
||||
auto& request = *opt_request;
|
||||
auto &request = *opt_request;
|
||||
|
||||
// Dummy one to trigger refresh semantic highlight.
|
||||
if (request.path.empty()) {
|
||||
@ -183,7 +182,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
reparse = 2;
|
||||
int reparseForDep = g_config->index.reparseForDependency;
|
||||
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 (dep.second < *write_time1) {
|
||||
reparse = 2;
|
||||
@ -210,7 +209,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
}
|
||||
|
||||
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)
|
||||
state.stage = 0;
|
||||
return true;
|
||||
@ -218,7 +217,8 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
|
||||
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 (g_config->index.enabled && request.id.Valid()) {
|
||||
@ -232,7 +232,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
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
|
||||
// to identify indexing problems. For interactive sessions, diagnostics are
|
||||
// handled by code completion.
|
||||
@ -260,7 +260,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
vfs->Reset(path);
|
||||
if (entry.id >= 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -274,7 +274,7 @@ bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void Init() {
|
||||
main_waiter = new MultiQueueWaiter;
|
||||
@ -288,28 +288,25 @@ void Init() {
|
||||
for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
|
||||
}
|
||||
|
||||
void Indexer_Main(DiagnosticsPublisher* diag_pub,
|
||||
VFS* vfs,
|
||||
Project* project,
|
||||
WorkingFiles* working_files) {
|
||||
void Indexer_Main(DiagnosticsPublisher *diag_pub, VFS *vfs, Project *project,
|
||||
WorkingFiles *working_files) {
|
||||
while (true)
|
||||
if (!Indexer_Parse(diag_pub, working_files, project, vfs))
|
||||
indexer_waiter->Wait(index_request);
|
||||
}
|
||||
|
||||
void Main_OnIndexed(DB* db,
|
||||
SemanticHighlightSymbolCache* semantic_cache,
|
||||
WorkingFiles* working_files,
|
||||
IndexUpdate* update) {
|
||||
void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
|
||||
WorkingFiles *working_files, IndexUpdate *update) {
|
||||
if (update->refresh) {
|
||||
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);
|
||||
for (auto& f : working_files->files) {
|
||||
for (auto &f : working_files->files) {
|
||||
std::string filename = LowerPathIfInsensitive(f->filename);
|
||||
if (db->name2file_id.find(filename) == db->name2file_id.end())
|
||||
continue;
|
||||
QueryFile* file = &db->files[db->name2file_id[filename]];
|
||||
QueryFile *file = &db->files[db->name2file_id[filename]];
|
||||
EmitSemanticHighlighting(db, semantic_cache, f.get(), file);
|
||||
}
|
||||
return;
|
||||
@ -322,9 +319,9 @@ void Main_OnIndexed(DB* db,
|
||||
|
||||
// Update indexed content, skipped ranges, and semantic highlighting.
|
||||
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;
|
||||
if (WorkingFile* working_file =
|
||||
if (WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(def_u.first.path)) {
|
||||
working_file->SetIndexContent(def_u.second);
|
||||
EmitSkippedRanges(working_file, def_u.first.skipped_ranges);
|
||||
@ -369,7 +366,8 @@ void LaunchStdin() {
|
||||
if (method_type == kMethodType_Exit)
|
||||
break;
|
||||
}
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
void LaunchStdout() {
|
||||
@ -383,7 +381,7 @@ void LaunchStdout() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& message : messages) {
|
||||
for (auto &message : messages) {
|
||||
#ifdef _WIN32
|
||||
fwrite(message.content.c_str(), message.content.size(), 1, stdout);
|
||||
fflush(stdout);
|
||||
@ -392,7 +390,8 @@ void LaunchStdout() {
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
void MainLoop() {
|
||||
@ -412,9 +411,8 @@ void MainLoop() {
|
||||
Out_Error out;
|
||||
out.id = id;
|
||||
out.error.code = lsErrorCodes::InternalError;
|
||||
out.error.message =
|
||||
"Dropping completion request; a newer request "
|
||||
"has come in that will be serviced instead.";
|
||||
out.error.message = "Dropping completion request; a newer request "
|
||||
"has come in that will be serviced instead.";
|
||||
pipeline::WriteStdout(kMethodType_Unknown, out);
|
||||
}
|
||||
});
|
||||
@ -426,7 +424,7 @@ void MainLoop() {
|
||||
DB db;
|
||||
|
||||
// Setup shared references.
|
||||
for (MessageHandler* handler : *MessageHandler::message_handlers) {
|
||||
for (MessageHandler *handler : *MessageHandler::message_handlers) {
|
||||
handler->db = &db;
|
||||
handler->waiter = indexer_waiter;
|
||||
handler->project = &project;
|
||||
@ -445,9 +443,9 @@ void MainLoop() {
|
||||
while (true) {
|
||||
std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll();
|
||||
bool did_work = messages.size();
|
||||
for (auto& message : messages) {
|
||||
for (auto &message : messages) {
|
||||
// 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()) {
|
||||
handler->Run(std::move(message));
|
||||
break;
|
||||
@ -473,18 +471,16 @@ void MainLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
void Index(const std::string& path,
|
||||
const std::vector<std::string>& args,
|
||||
bool interactive,
|
||||
lsRequestId id) {
|
||||
void Index(const std::string &path, const std::vector<std::string> &args,
|
||||
bool interactive, lsRequestId id) {
|
||||
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));
|
||||
}
|
||||
|
||||
void WriteStdout(MethodType method, lsBaseOutMessage& response) {
|
||||
void WriteStdout(MethodType method, lsBaseOutMessage &response) {
|
||||
std::ostringstream sstream;
|
||||
response.Write(sstream);
|
||||
|
||||
@ -494,4 +490,4 @@ void WriteStdout(MethodType method, lsBaseOutMessage& response) {
|
||||
for_stdout->PushBack(std::move(out));
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace ccls::pipeline
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <string_view>
|
||||
#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.
|
||||
void FreeUnusedMemory();
|
||||
@ -12,5 +12,5 @@ void FreeUnusedMemory();
|
||||
// Stop self and wait for SIGCONT.
|
||||
void TraceMe();
|
||||
|
||||
std::string GetExternalCommandOutput(const std::vector<std::string>& command,
|
||||
std::string GetExternalCommandOutput(const std::vector<std::string> &command,
|
||||
std::string_view input);
|
||||
|
@ -14,10 +14,10 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.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 <unistd.h>
|
||||
#ifdef __GLIBC__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
@ -89,9 +89,9 @@ std::optional<std::string> RealPathNotExpandSymlink(std::string path) {
|
||||
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);
|
||||
return resolved ? *resolved : path;
|
||||
}
|
||||
@ -106,12 +106,12 @@ void TraceMe() {
|
||||
// If the environment variable is defined, wait for a debugger.
|
||||
// In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
|
||||
// after detaching.
|
||||
const char* traceme = getenv("CCLS_TRACEME");
|
||||
const char *traceme = getenv("CCLS_TRACEME");
|
||||
if (traceme)
|
||||
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) {
|
||||
int pin[2], pout[2];
|
||||
if (pipe(pin) < 0) {
|
||||
@ -132,9 +132,9 @@ std::string GetExternalCommandOutput(const std::vector<std::string>& command,
|
||||
close(pin[1]);
|
||||
close(pout[0]);
|
||||
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++)
|
||||
argv[i] = const_cast<char*>(command[i].c_str());
|
||||
argv[i] = const_cast<char *>(command[i].c_str());
|
||||
argv[command.size()] = nullptr;
|
||||
execvp(argv[0], argv);
|
||||
_Exit(127);
|
||||
|
@ -15,10 +15,10 @@
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
std::string NormalizePath(const std::string& path) {
|
||||
std::string NormalizePath(const std::string &path) {
|
||||
DWORD retval = 0;
|
||||
TCHAR buffer[MAX_PATH] = TEXT("");
|
||||
TCHAR** lpp_part = {NULL};
|
||||
TCHAR **lpp_part = {NULL};
|
||||
|
||||
retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part);
|
||||
// fail, return original
|
||||
@ -36,7 +36,7 @@ void FreeUnusedMemory() {}
|
||||
// TODO Wait for debugger to attach
|
||||
void TraceMe() {}
|
||||
|
||||
std::string GetExternalCommandOutput(const std::vector<std::string>& command,
|
||||
std::string GetExternalCommandOutput(const std::vector<std::string> &command,
|
||||
std::string_view input) {
|
||||
return "";
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
Position Position::FromString(const std::string& encoded) {
|
||||
char* p = const_cast<char*>(encoded.c_str());
|
||||
Position Position::FromString(const std::string &encoded) {
|
||||
char *p = const_cast<char *>(encoded.c_str());
|
||||
int16_t line = int16_t(strtol(p, &p, 10)) - 1;
|
||||
assert(*p == ':');
|
||||
p++;
|
||||
@ -21,9 +21,9 @@ std::string Position::ToString() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
Range Range::FromString(const std::string& encoded) {
|
||||
Range Range::FromString(const std::string &encoded) {
|
||||
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;
|
||||
assert(*p == ':');
|
||||
p++;
|
||||
@ -57,7 +57,7 @@ std::string Range::ToString() {
|
||||
}
|
||||
|
||||
// Position
|
||||
void Reflect(Reader& visitor, Position& value) {
|
||||
void Reflect(Reader &visitor, Position &value) {
|
||||
if (visitor.Format() == SerializeFormat::Json) {
|
||||
value = Position::FromString(visitor.GetString());
|
||||
} else {
|
||||
@ -65,7 +65,7 @@ void Reflect(Reader& visitor, Position& value) {
|
||||
Reflect(visitor, value.column);
|
||||
}
|
||||
}
|
||||
void Reflect(Writer& visitor, Position& value) {
|
||||
void Reflect(Writer &visitor, Position &value) {
|
||||
if (visitor.Format() == SerializeFormat::Json) {
|
||||
std::string output = value.ToString();
|
||||
visitor.String(output.c_str(), output.size());
|
||||
@ -76,7 +76,7 @@ void Reflect(Writer& visitor, Position& value) {
|
||||
}
|
||||
|
||||
// Range
|
||||
void Reflect(Reader& visitor, Range& value) {
|
||||
void Reflect(Reader &visitor, Range &value) {
|
||||
if (visitor.Format() == SerializeFormat::Json) {
|
||||
value = Range::FromString(visitor.GetString());
|
||||
} else {
|
||||
@ -86,7 +86,7 @@ void Reflect(Reader& visitor, Range& value) {
|
||||
Reflect(visitor, value.end.column);
|
||||
}
|
||||
}
|
||||
void Reflect(Writer& visitor, Range& value) {
|
||||
void Reflect(Writer &visitor, Range &value) {
|
||||
if (visitor.Format() == SerializeFormat::Json) {
|
||||
std::string output = value.ToString();
|
||||
visitor.String(output.c_str(), output.size());
|
||||
|
@ -10,17 +10,17 @@ struct Position {
|
||||
int16_t line = -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; }
|
||||
std::string ToString();
|
||||
|
||||
// Compare two Positions and check if they are equal. Ignores the value of
|
||||
// |interesting|.
|
||||
bool operator==(const Position& o) const {
|
||||
bool operator==(const Position &o) const {
|
||||
return line == o.line && column == o.column;
|
||||
}
|
||||
bool operator<(const Position& o) const {
|
||||
bool operator<(const Position &o) const {
|
||||
if (line != o.line)
|
||||
return line < o.line;
|
||||
return column < o.column;
|
||||
@ -32,7 +32,7 @@ struct Range {
|
||||
Position start;
|
||||
Position end;
|
||||
|
||||
static Range FromString(const std::string& encoded);
|
||||
static Range FromString(const std::string &encoded);
|
||||
|
||||
bool Valid() const { return start.Valid(); }
|
||||
bool Contains(int line, int column) const;
|
||||
@ -40,17 +40,16 @@ struct Range {
|
||||
|
||||
std::string ToString();
|
||||
|
||||
bool operator==(const Range& o) const {
|
||||
bool operator==(const Range &o) const {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Range> {
|
||||
template <> struct hash<Range> {
|
||||
std::size_t operator()(Range x) const {
|
||||
union U {
|
||||
Range range = {};
|
||||
@ -61,12 +60,12 @@ struct hash<Range> {
|
||||
return hash<uint64_t>()(u.u64);
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
// Reflection
|
||||
class Reader;
|
||||
class Writer;
|
||||
void Reflect(Reader& visitor, Position& value);
|
||||
void Reflect(Writer& visitor, Position& value);
|
||||
void Reflect(Reader& visitor, Range& value);
|
||||
void Reflect(Writer& visitor, Range& value);
|
||||
void Reflect(Reader &visitor, Position &value);
|
||||
void Reflect(Writer &visitor, Position &value);
|
||||
void Reflect(Reader &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 "log.hh"
|
||||
#include "match.h"
|
||||
#include "platform.h"
|
||||
#include "pipeline.hh"
|
||||
#include "platform.h"
|
||||
#include "serializers/json.h"
|
||||
#include "utils.h"
|
||||
#include "working_files.h"
|
||||
@ -67,9 +67,9 @@ enum OptionClass {
|
||||
Separate,
|
||||
};
|
||||
|
||||
Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
ProjectConfig* config,
|
||||
const CompileCommandsEntry& entry) {
|
||||
Project::Entry
|
||||
GetCompilationEntryFromCompileCommandEntry(ProjectConfig *config,
|
||||
const CompileCommandsEntry &entry) {
|
||||
Project::Entry result;
|
||||
result.filename = entry.file;
|
||||
const std::string base_name = sys::path::filename(entry.file);
|
||||
@ -77,7 +77,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
// Expand %c %cpp %clang
|
||||
std::vector<std::string> args;
|
||||
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 (lang == LanguageId::C)
|
||||
args.push_back(arg.substr(3));
|
||||
@ -106,21 +106,21 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
auto TargetAndMode =
|
||||
driver::ToolChain::getTargetAndModeFromProgramName(args[0]);
|
||||
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));
|
||||
Driver.setTargetAndMode(TargetAndMode);
|
||||
}
|
||||
Driver.setCheckInputsExist(false);
|
||||
|
||||
std::vector<const char*> cargs;
|
||||
for (auto& arg : args)
|
||||
std::vector<const char *> cargs;
|
||||
for (auto &arg : args)
|
||||
cargs.push_back(arg.c_str());
|
||||
cargs.push_back("-fsyntax-only");
|
||||
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)
|
||||
return result;
|
||||
const driver::ArgStringList& CCArgs = Jobs.begin()->getArguments();
|
||||
const driver::ArgStringList &CCArgs = Jobs.begin()->getArguments();
|
||||
|
||||
auto CI = std::make_unique<CompilerInvocation>();
|
||||
CompilerInvocation::CreateFromArgs(*CI, CCArgs.data(),
|
||||
@ -132,16 +132,16 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
for (auto &E : HeaderOpts.UserEntries) {
|
||||
std::string path = entry.ResolveIfRelative(E.Path);
|
||||
switch (E.Group) {
|
||||
default:
|
||||
config->angle_dirs.insert(path);
|
||||
break;
|
||||
case frontend::Quoted:
|
||||
config->quote_dirs.insert(path);
|
||||
break;
|
||||
case frontend::Angled:
|
||||
config->angle_dirs.insert(path);
|
||||
config->quote_dirs.insert(path);
|
||||
break;
|
||||
default:
|
||||
config->angle_dirs.insert(path);
|
||||
break;
|
||||
case frontend::Quoted:
|
||||
config->quote_dirs.insert(path);
|
||||
break;
|
||||
case frontend::Angled:
|
||||
config->angle_dirs.insert(path);
|
||||
config->quote_dirs.insert(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +155,8 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
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);
|
||||
if (CI->getFileSystemOpts().WorkingDir.empty())
|
||||
args.push_back("-working-directory=" + entry.directory);
|
||||
@ -169,17 +170,18 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> ReadCompilerArgumentsFromFile(
|
||||
const std::string& path) {
|
||||
std::vector<std::string>
|
||||
ReadCompilerArgumentsFromFile(const std::string &path) {
|
||||
auto MBOrErr = MemoryBuffer::getFile(path);
|
||||
if (!MBOrErr) return {};
|
||||
if (!MBOrErr)
|
||||
return {};
|
||||
std::vector<std::string> args;
|
||||
for (line_iterator I(*MBOrErr.get(), true, '#'), E; I != E; ++I)
|
||||
args.push_back(*I);
|
||||
return args;
|
||||
}
|
||||
|
||||
std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
|
||||
std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig *config) {
|
||||
std::vector<Project::Entry> result;
|
||||
config->mode = ProjectMode::DotCcls;
|
||||
SmallString<256> Path;
|
||||
@ -194,7 +196,7 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
|
||||
|
||||
GetFilesInFolder(config->project_dir, true /*recursive*/,
|
||||
true /*add_folder_to_path*/,
|
||||
[&folder_args, &files](const std::string& path) {
|
||||
[&folder_args, &files](const std::string &path) {
|
||||
if (SourceFileLanguage(path) != LanguageId::Unknown) {
|
||||
files.push_back(path);
|
||||
} 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 auto& project_dir_args = folder_args[project_dir];
|
||||
const std::string &project_dir = config->project_dir;
|
||||
const auto &project_dir_args = folder_args[project_dir];
|
||||
LOG_IF_S(INFO, !project_dir_args.empty())
|
||||
<< "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()) {
|
||||
auto it = folder_args.find(cur);
|
||||
if (it != folder_args.end())
|
||||
@ -223,13 +226,13 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
|
||||
return folder_args[project_dir];
|
||||
};
|
||||
|
||||
for (const std::string& file : files) {
|
||||
for (const std::string &file : files) {
|
||||
CompileCommandsEntry e;
|
||||
e.directory = config->project_dir;
|
||||
e.file = file;
|
||||
e.args = GetCompilerArgumentForFile(file);
|
||||
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);
|
||||
result.push_back(GetCompilationEntryFromCompileCommandEntry(config, e));
|
||||
}
|
||||
@ -237,9 +240,9 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
||||
ProjectConfig* project,
|
||||
const std::string& opt_compilation_db_dir) {
|
||||
std::vector<Project::Entry>
|
||||
LoadCompilationEntriesFromDirectory(ProjectConfig *project,
|
||||
const std::string &opt_compilation_db_dir) {
|
||||
// If there is a .ccls file always load using directory listing.
|
||||
SmallString<256> Path;
|
||||
sys::path::append(Path, project->project_dir, ".ccls");
|
||||
@ -273,7 +276,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
||||
std::vector<std::string>{g_config->compilationDatabaseCommand,
|
||||
project->project_dir},
|
||||
input.GetString());
|
||||
FILE* fout = fopen(Path.c_str(), "wb");
|
||||
FILE *fout = fopen(Path.c_str(), "wb");
|
||||
fwrite(contents.c_str(), contents.size(), 1, fout);
|
||||
fclose(fout);
|
||||
#endif
|
||||
@ -284,7 +287,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
||||
tooling::CompilationDatabase::loadFromDirectory(comp_db_dir, err_msg);
|
||||
if (!g_config->compilationDatabaseCommand.empty()) {
|
||||
#ifdef _WIN32
|
||||
// TODO
|
||||
// TODO
|
||||
#else
|
||||
unlink(Path.c_str());
|
||||
rmdir(comp_db_dir.c_str());
|
||||
@ -326,11 +329,11 @@ int ComputeGuessScore(std::string_view a, std::string_view b) {
|
||||
return score;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
bool Project::loaded = false;
|
||||
|
||||
void Project::Load(const std::string& root_directory) {
|
||||
void Project::Load(const std::string &root_directory) {
|
||||
Project::loaded = false;
|
||||
// Load data.
|
||||
ProjectConfig project;
|
||||
@ -344,11 +347,11 @@ void Project::Load(const std::string& root_directory) {
|
||||
project.quote_dirs.end());
|
||||
angle_include_directories.assign(project.angle_dirs.begin(),
|
||||
project.angle_dirs.end());
|
||||
for (std::string& path : quote_include_directories) {
|
||||
for (std::string &path : quote_include_directories) {
|
||||
EnsureEndsInSlash(path);
|
||||
LOG_S(INFO) << "quote_include_dir: " << path;
|
||||
}
|
||||
for (std::string& path : angle_include_directories) {
|
||||
for (std::string &path : angle_include_directories) {
|
||||
EnsureEndsInSlash(path);
|
||||
LOG_S(INFO) << "angle_include_dir: " << path;
|
||||
}
|
||||
@ -362,9 +365,8 @@ void Project::Load(const std::string& root_directory) {
|
||||
}
|
||||
}
|
||||
|
||||
void Project::SetFlagsForFile(
|
||||
const std::vector<std::string>& flags,
|
||||
const std::string& path) {
|
||||
void Project::SetFlagsForFile(const std::vector<std::string> &flags,
|
||||
const std::string &path) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto it = absolute_path_to_entry_index_.find(path);
|
||||
if (it != absolute_path_to_entry_index_.end()) {
|
||||
@ -380,8 +382,8 @@ void Project::SetFlagsForFile(
|
||||
}
|
||||
}
|
||||
|
||||
Project::Entry Project::FindCompilationEntryForFile(
|
||||
const std::string& filename) {
|
||||
Project::Entry
|
||||
Project::FindCompilationEntryForFile(const std::string &filename) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
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.
|
||||
// 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();
|
||||
for (Entry& entry : entries) {
|
||||
for (Entry &entry : entries) {
|
||||
int score = ComputeGuessScore(filename, entry.filename);
|
||||
if (score > best_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
|
||||
// that path to the new filename.
|
||||
std::string best_entry_base_name = sys::path::filename(best_entry->filename);
|
||||
for (std::string& arg : result.args) {
|
||||
std::string best_entry_base_name =
|
||||
sys::path::filename(best_entry->filename);
|
||||
for (std::string &arg : result.args) {
|
||||
try {
|
||||
if (arg == best_entry->filename ||
|
||||
sys::path::filename(arg) == best_entry_base_name)
|
||||
@ -427,10 +430,10 @@ Project::Entry Project::FindCompilationEntryForFile(
|
||||
}
|
||||
|
||||
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);
|
||||
for (int i = 0; i < entries.size(); ++i) {
|
||||
const Project::Entry& entry = entries[i];
|
||||
const Project::Entry &entry = entries[i];
|
||||
std::string failure_reason;
|
||||
if (matcher.IsMatch(entry.filename, &failure_reason))
|
||||
action(i, entries[i]);
|
||||
@ -441,9 +444,8 @@ void Project::ForAllFilteredFiles(
|
||||
}
|
||||
}
|
||||
|
||||
void Project::Index(WorkingFiles* wfiles,
|
||||
lsRequestId id) {
|
||||
ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
|
||||
void Project::Index(WorkingFiles *wfiles, lsRequestId id) {
|
||||
ForAllFilteredFiles([&](int i, const Project::Entry &entry) {
|
||||
bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
|
||||
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
|
||||
// project root, not subdirectories). For compile_commands.json, its entries
|
||||
// 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
|
||||
// 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
|
||||
// that is not in the compilation_database.json make sure those changes
|
||||
// are permanent.
|
||||
void SetFlagsForFile(
|
||||
const std::vector<std::string>& flags,
|
||||
const std::string& path);
|
||||
void SetFlagsForFile(const std::vector<std::string> &flags,
|
||||
const std::string &path);
|
||||
|
||||
// Run |action| on every file in the project.
|
||||
void ForAllFilteredFiles(
|
||||
std::function<void(int i, const Entry& entry)> action);
|
||||
void
|
||||
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;
|
||||
};
|
||||
|
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;
|
||||
}
|
||||
|
||||
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)
|
||||
use.usr = file_id;
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
for (Use use : from)
|
||||
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());
|
||||
}
|
||||
|
||||
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()) {
|
||||
std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
|
||||
from.erase(
|
||||
std::remove_if(from.begin(), from.end(),
|
||||
[&](const T& t) { return to_remove_set.count(t) > 0; }),
|
||||
from.end());
|
||||
std::remove_if(from.begin(), from.end(),
|
||||
[&](const T &t) { return to_remove_set.count(t) > 0; }),
|
||||
from.end());
|
||||
}
|
||||
}
|
||||
|
||||
QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
||||
QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile &indexed) {
|
||||
QueryFile::Def def;
|
||||
def.path = std::move(indexed.path);
|
||||
def.args = std::move(indexed.args);
|
||||
def.includes = std::move(indexed.includes);
|
||||
def.skipped_ranges = std::move(indexed.skipped_ranges);
|
||||
def.dependencies.reserve(indexed.dependencies.size());
|
||||
for (auto& dep : indexed.dependencies)
|
||||
for (auto &dep : indexed.dependencies)
|
||||
def.dependencies.push_back(dep.first());
|
||||
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}});
|
||||
};
|
||||
|
||||
for (auto& it : indexed.usr2type) {
|
||||
const IndexType& type = it.second;
|
||||
for (auto &it : indexed.usr2type) {
|
||||
const IndexType &type = it.second;
|
||||
if (type.def.spell)
|
||||
add_all_symbols(*type.def.spell, type.usr, SymbolKind::Type);
|
||||
if (type.def.extent)
|
||||
@ -100,8 +100,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
||||
if (use.file_id == -1)
|
||||
add_all_symbols(use, type.usr, SymbolKind::Type);
|
||||
}
|
||||
for (auto& it: indexed.usr2func) {
|
||||
const IndexFunc& func = it.second;
|
||||
for (auto &it : indexed.usr2func) {
|
||||
const IndexFunc &func = it.second;
|
||||
if (func.def.spell)
|
||||
add_all_symbols(*func.def.spell, func.usr, SymbolKind::Func);
|
||||
if (func.def.extent)
|
||||
@ -124,8 +124,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
||||
add_all_symbols(use, func.usr, SymbolKind::Func);
|
||||
}
|
||||
}
|
||||
for (auto& it : indexed.usr2var) {
|
||||
const IndexVar& var = it.second;
|
||||
for (auto &it : indexed.usr2var) {
|
||||
const IndexVar &var = it.second;
|
||||
if (var.def.spell)
|
||||
add_all_symbols(*var.def.spell, var.usr, SymbolKind::Var);
|
||||
if (var.def.extent)
|
||||
@ -140,11 +140,11 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
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;
|
||||
});
|
||||
|
||||
@ -153,8 +153,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
||||
|
||||
// Returns true if an element with the same file is found.
|
||||
template <typename Q>
|
||||
bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) {
|
||||
for (auto& def1 : def_list)
|
||||
bool TryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
|
||||
for (auto &def1 : def_list)
|
||||
if (def1.file_id == def.file_id) {
|
||||
def1 = std::move(def);
|
||||
return true;
|
||||
@ -162,10 +162,9 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
IndexFile* current) {
|
||||
IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
|
||||
IndexUpdate r;
|
||||
static IndexFile empty(llvm::sys::fs::UniqueID(0, 0), current->path,
|
||||
"<empty>");
|
||||
@ -177,16 +176,16 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
r.files_def_update = BuildFileDefUpdate(std::move(*current));
|
||||
|
||||
r.funcs_hint = int(current->usr2func.size() - previous->usr2func.size());
|
||||
for (auto& it : previous->usr2func) {
|
||||
auto& func = it.second;
|
||||
for (auto &it : previous->usr2func) {
|
||||
auto &func = it.second;
|
||||
if (func.def.detailed_name[0])
|
||||
r.funcs_removed.push_back(func.usr);
|
||||
r.funcs_declarations[func.usr].first = std::move(func.declarations);
|
||||
r.funcs_uses[func.usr].first = std::move(func.uses);
|
||||
r.funcs_derived[func.usr].first = std::move(func.derived);
|
||||
}
|
||||
for (auto& it : current->usr2func) {
|
||||
auto& func = it.second;
|
||||
for (auto &it : current->usr2func) {
|
||||
auto &func = it.second;
|
||||
if (func.def.detailed_name[0])
|
||||
r.funcs_def_update.emplace_back(it.first, func.def);
|
||||
r.funcs_declarations[func.usr].second = std::move(func.declarations);
|
||||
@ -195,8 +194,8 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
}
|
||||
|
||||
r.types_hint = int(current->usr2type.size() - previous->usr2type.size());
|
||||
for (auto& it : previous->usr2type) {
|
||||
auto& type = it.second;
|
||||
for (auto &it : previous->usr2type) {
|
||||
auto &type = it.second;
|
||||
if (type.def.detailed_name[0])
|
||||
r.types_removed.push_back(type.usr);
|
||||
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_instances[type.usr].first = std::move(type.instances);
|
||||
};
|
||||
for (auto& it : current->usr2type) {
|
||||
auto& type = it.second;
|
||||
for (auto &it : current->usr2type) {
|
||||
auto &type = it.second;
|
||||
if (type.def.detailed_name[0])
|
||||
r.types_def_update.emplace_back(it.first, type.def);
|
||||
r.types_declarations[type.usr].second = std::move(type.declarations);
|
||||
@ -215,15 +214,15 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
};
|
||||
|
||||
r.vars_hint = int(current->usr2var.size() - previous->usr2var.size());
|
||||
for (auto& it : previous->usr2var) {
|
||||
auto& var = it.second;
|
||||
for (auto &it : previous->usr2var) {
|
||||
auto &var = it.second;
|
||||
if (var.def.detailed_name[0])
|
||||
r.vars_removed.push_back(var.usr);
|
||||
r.vars_declarations[var.usr].first = std::move(var.declarations);
|
||||
r.vars_uses[var.usr].first = std::move(var.uses);
|
||||
}
|
||||
for (auto& it : current->usr2var) {
|
||||
auto& var = it.second;
|
||||
for (auto &it : current->usr2var) {
|
||||
auto &var = it.second;
|
||||
if (var.def.detailed_name[0])
|
||||
r.vars_def_update.emplace_back(it.first, var.def);
|
||||
r.vars_declarations[var.usr].second = std::move(var.declarations);
|
||||
@ -233,51 +232,53 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
return r;
|
||||
}
|
||||
|
||||
void DB::RemoveUsrs(SymbolKind kind,
|
||||
int file_id,
|
||||
const std::vector<Usr>& to_remove) {
|
||||
void DB::RemoveUsrs(SymbolKind kind, int file_id,
|
||||
const std::vector<Usr> &to_remove) {
|
||||
switch (kind) {
|
||||
case SymbolKind::Func: {
|
||||
for (Usr usr : to_remove) {
|
||||
// FIXME
|
||||
if (!HasFunc(usr)) continue;
|
||||
QueryFunc& func = Func(usr);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case SymbolKind::Func: {
|
||||
for (Usr usr : to_remove) {
|
||||
// FIXME
|
||||
if (!HasFunc(usr))
|
||||
continue;
|
||||
QueryFunc &func = Func(usr);
|
||||
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);
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
for (Usr usr : to_remove) {
|
||||
// FIXME
|
||||
if (!HasType(usr)) continue;
|
||||
QueryType& type = Type(usr);
|
||||
auto it = llvm::find_if(type.def, [=](const QueryType::Def& def) {
|
||||
return def.file_id == file_id;
|
||||
});
|
||||
if (it != type.def.end())
|
||||
type.def.erase(it);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
for (Usr usr : to_remove) {
|
||||
// FIXME
|
||||
if (!HasType(usr))
|
||||
continue;
|
||||
QueryType &type = Type(usr);
|
||||
auto it = llvm::find_if(type.def, [=](const QueryType::Def &def) {
|
||||
return def.file_id == file_id;
|
||||
});
|
||||
if (it != type.def.end())
|
||||
type.def.erase(it);
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
for (Usr usr : to_remove) {
|
||||
// FIXME
|
||||
if (!HasVar(usr)) continue;
|
||||
QueryVar& var = Var(usr);
|
||||
auto it = llvm::find_if(var.def, [=](const QueryVar::Def& def) {
|
||||
return def.file_id == file_id;
|
||||
});
|
||||
if (it != var.def.end())
|
||||
var.def.erase(it);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
for (Usr usr : to_remove) {
|
||||
// FIXME
|
||||
if (!HasVar(usr))
|
||||
continue;
|
||||
QueryVar &var = Var(usr);
|
||||
auto it = llvm::find_if(var.def, [=](const QueryVar::Def &def) {
|
||||
return def.file_id == file_id;
|
||||
});
|
||||
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;
|
||||
for (auto & [ lid, path ] : u->prev_lid2path)
|
||||
for (auto &[lid, path] : u->prev_lid2path)
|
||||
prev_lid2file_id[lid] = GetFileId(path);
|
||||
for (auto & [ lid, path ] : u->lid2path)
|
||||
for (auto &[lid, path] : u->lid2path)
|
||||
lid2file_id[lid] = GetFileId(path);
|
||||
|
||||
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));
|
||||
REMOVE_ADD(func, declarations);
|
||||
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);
|
||||
|
||||
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, derived);
|
||||
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);
|
||||
|
||||
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);
|
||||
Update(lid2file_id, u->file_id, std::move(u->vars_def_update));
|
||||
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);
|
||||
|
||||
#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));
|
||||
if (it.second) {
|
||||
int id = files.size();
|
||||
@ -386,7 +387,7 @@ int DB::GetFileId(const std::string& path) {
|
||||
return it.first->second;
|
||||
}
|
||||
|
||||
int DB::Update(QueryFile::DefUpdate&& u) {
|
||||
int DB::Update(QueryFile::DefUpdate &&u) {
|
||||
int file_id = GetFileId(u.first.path);
|
||||
files[file_id].def = u.first;
|
||||
return file_id;
|
||||
@ -395,7 +396,7 @@ int DB::Update(QueryFile::DefUpdate&& u) {
|
||||
void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||
std::vector<std::pair<Usr, QueryFunc::Def>> &&us) {
|
||||
for (auto &u : us) {
|
||||
auto& def = u.second;
|
||||
auto &def = u.second;
|
||||
assert(def.detailed_name[0]);
|
||||
u.second.file_id = file_id;
|
||||
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());
|
||||
if (R.second)
|
||||
funcs.emplace_back();
|
||||
QueryFunc& existing = funcs[R.first->second];
|
||||
QueryFunc &existing = funcs[R.first->second];
|
||||
existing.usr = u.first;
|
||||
if (!TryReplaceDef(existing.def, 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,
|
||||
std::vector<std::pair<Usr, QueryType::Def>> &&us) {
|
||||
for (auto &u : us) {
|
||||
auto& def = u.second;
|
||||
auto &def = u.second;
|
||||
assert(def.detailed_name[0]);
|
||||
u.second.file_id = file_id;
|
||||
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());
|
||||
if (R.second)
|
||||
types.emplace_back();
|
||||
QueryType& existing = types[R.first->second];
|
||||
QueryType &existing = types[R.first->second];
|
||||
existing.usr = u.first;
|
||||
if (!TryReplaceDef(existing.def, 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,
|
||||
std::vector<std::pair<Usr, QueryVar::Def>> &&us) {
|
||||
for (auto &u : us) {
|
||||
auto& def = u.second;
|
||||
auto &def = u.second;
|
||||
assert(def.detailed_name[0]);
|
||||
u.second.file_id = file_id;
|
||||
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());
|
||||
if (R.second)
|
||||
vars.emplace_back();
|
||||
QueryVar& existing = vars[R.first->second];
|
||||
QueryVar &existing = vars[R.first->second];
|
||||
existing.usr = u.first;
|
||||
if (!TryReplaceDef(existing.def, 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) {
|
||||
Usr usr = sym.usr;
|
||||
switch (sym.kind) {
|
||||
default:
|
||||
break;
|
||||
case SymbolKind::File:
|
||||
if (files[usr].def)
|
||||
return files[usr].def->path;
|
||||
break;
|
||||
case SymbolKind::Func:
|
||||
if (const auto* def = Func(usr).AnyDef())
|
||||
return def->Name(qualified);
|
||||
break;
|
||||
case SymbolKind::Type:
|
||||
if (const auto* def = Type(usr).AnyDef())
|
||||
return def->Name(qualified);
|
||||
break;
|
||||
case SymbolKind::Var:
|
||||
if (const auto* def = Var(usr).AnyDef())
|
||||
return def->Name(qualified);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case SymbolKind::File:
|
||||
if (files[usr].def)
|
||||
return files[usr].def->path;
|
||||
break;
|
||||
case SymbolKind::Func:
|
||||
if (const auto *def = Func(usr).AnyDef())
|
||||
return def->Name(qualified);
|
||||
break;
|
||||
case SymbolKind::Type:
|
||||
if (const auto *def = Type(usr).AnyDef())
|
||||
return def->Name(qualified);
|
||||
break;
|
||||
case SymbolKind::Var:
|
||||
if (const auto *def = Var(usr).AnyDef())
|
||||
return def->Name(qualified);
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
42
src/query.h
42
src/query.h
@ -31,19 +31,20 @@ struct QueryFile {
|
||||
std::unordered_map<SymbolRef, int> symbol2refcnt;
|
||||
};
|
||||
|
||||
template <typename Q, typename QDef>
|
||||
struct QueryEntity {
|
||||
template <typename Q, typename QDef> struct QueryEntity {
|
||||
using Def = QDef;
|
||||
Def* AnyDef() {
|
||||
Def* ret = nullptr;
|
||||
for (auto& i : static_cast<Q*>(this)->def) {
|
||||
Def *AnyDef() {
|
||||
Def *ret = nullptr;
|
||||
for (auto &i : static_cast<Q *>(this)->def) {
|
||||
ret = &i;
|
||||
if (i.spell)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
const Def* AnyDef() const { return const_cast<QueryEntity*>(this)->AnyDef(); }
|
||||
const Def *AnyDef() const {
|
||||
return const_cast<QueryEntity *>(this)->AnyDef();
|
||||
}
|
||||
};
|
||||
|
||||
using UseUpdate =
|
||||
@ -78,8 +79,7 @@ struct QueryVar : QueryEntity<QueryVar, VarDef> {
|
||||
struct IndexUpdate {
|
||||
// Creates a new IndexUpdate based on the delta from previous to current. If
|
||||
// no delta computation should be done just pass null for previous.
|
||||
static IndexUpdate CreateDelta(IndexFile* previous,
|
||||
IndexFile* current);
|
||||
static IndexUpdate CreateDelta(IndexFile *previous, IndexFile *current);
|
||||
|
||||
int file_id;
|
||||
|
||||
@ -121,8 +121,7 @@ struct IndexUpdate {
|
||||
struct WrappedUsr {
|
||||
Usr usr;
|
||||
};
|
||||
template <>
|
||||
struct llvm::DenseMapInfo<WrappedUsr> {
|
||||
template <> struct llvm::DenseMapInfo<WrappedUsr> {
|
||||
static inline WrappedUsr getEmptyKey() { return {0}; }
|
||||
static inline WrappedUsr getTombstoneKey() { return {~0ULL}; }
|
||||
static unsigned getHashValue(WrappedUsr w) { return w.usr; }
|
||||
@ -141,11 +140,12 @@ struct DB {
|
||||
std::vector<QueryType> types;
|
||||
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|.
|
||||
void ApplyIndexUpdate(IndexUpdate* update);
|
||||
int GetFileId(const std::string& path);
|
||||
int Update(QueryFile::DefUpdate&& u);
|
||||
void ApplyIndexUpdate(IndexUpdate *update);
|
||||
int GetFileId(const std::string &path);
|
||||
int Update(QueryFile::DefUpdate &&u);
|
||||
void Update(const Lid2file_id &, int file_id,
|
||||
std::vector<std::pair<Usr, QueryType::Def>> &&us);
|
||||
void Update(const Lid2file_id &, int file_id,
|
||||
@ -158,12 +158,12 @@ struct DB {
|
||||
bool HasType(Usr usr) const { return type_usr.count({usr}); }
|
||||
bool HasVar(Usr usr) const { return var_usr.count({usr}); }
|
||||
|
||||
QueryFunc& Func(Usr usr) { return funcs[func_usr[{usr}]]; }
|
||||
QueryType& Type(Usr usr) { return types[type_usr[{usr}]]; }
|
||||
QueryVar& Var(Usr usr) { return vars[var_usr[{usr}]]; }
|
||||
QueryFunc &Func(Usr usr) { return funcs[func_usr[{usr}]]; }
|
||||
QueryType &Type(Usr usr) { return types[type_usr[{usr}]]; }
|
||||
QueryVar &Var(Usr usr) { return vars[var_usr[{usr}]]; }
|
||||
|
||||
QueryFile& GetFile(SymbolIdx ref) { return files[ref.usr]; }
|
||||
QueryFunc& GetFunc(SymbolIdx ref) { return Func(ref.usr); }
|
||||
QueryType& GetType(SymbolIdx ref) { return Type(ref.usr); }
|
||||
QueryVar& GetVar(SymbolIdx ref) { return Var(ref.usr); }
|
||||
QueryFile &GetFile(SymbolIdx ref) { return files[ref.usr]; }
|
||||
QueryFunc &GetFunc(SymbolIdx ref) { return Func(ref.usr); }
|
||||
QueryType &GetType(SymbolIdx ref) { return Type(ref.usr); }
|
||||
QueryVar &GetVar(SymbolIdx ref) { return Var(ref.usr); }
|
||||
};
|
||||
|
@ -8,22 +8,22 @@
|
||||
namespace {
|
||||
|
||||
// Computes roughly how long |range| is.
|
||||
int ComputeRangeSize(const Range& range) {
|
||||
int ComputeRangeSize(const Range &range) {
|
||||
if (range.start.line != range.end.line)
|
||||
return INT_MAX;
|
||||
return range.end.column - range.start.column;
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int>& entity_usr,
|
||||
std::vector<Q>& entities,
|
||||
const std::vector<Usr>& usrs) {
|
||||
std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int> &entity_usr,
|
||||
std::vector<Q> &entities,
|
||||
const std::vector<Usr> &usrs) {
|
||||
std::vector<Use> ret;
|
||||
ret.reserve(usrs.size());
|
||||
for (Usr usr : usrs) {
|
||||
Q& entity = entities[entity_usr[{usr}]];
|
||||
Q &entity = entities[entity_usr[{usr}]];
|
||||
bool has_def = false;
|
||||
for (auto& def : entity.def)
|
||||
for (auto &def : entity.def)
|
||||
if (def.spell) {
|
||||
ret.push_back(*def.spell);
|
||||
has_def = true;
|
||||
@ -35,39 +35,38 @@ std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int>& entity_usr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
Maybe<Use> GetDefinitionSpell(DB* db, SymbolIdx sym) {
|
||||
Maybe<Use> GetDefinitionSpell(DB *db, SymbolIdx sym) {
|
||||
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;
|
||||
}
|
||||
|
||||
Maybe<Use> GetDefinitionExtent(DB* db, SymbolIdx sym) {
|
||||
Maybe<Use> GetDefinitionExtent(DB *db, SymbolIdx sym) {
|
||||
// Used to jump to file.
|
||||
if (sym.kind == SymbolKind::File)
|
||||
return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None},
|
||||
int(sym.usr)};
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
std::vector<Use> GetVarDeclarations(DB* db,
|
||||
const std::vector<Usr>& usrs,
|
||||
std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
|
||||
unsigned kind) {
|
||||
std::vector<Use> ret;
|
||||
ret.reserve(usrs.size());
|
||||
for (Usr usr : usrs) {
|
||||
QueryVar& var = db->Var(usr);
|
||||
QueryVar &var = db->Var(usr);
|
||||
bool has_def = false;
|
||||
for (auto& def : var.def)
|
||||
for (auto &def : var.def)
|
||||
if (def.spell) {
|
||||
has_def = true;
|
||||
// See messages/ccls_vars.cc
|
||||
@ -90,29 +89,29 @@ std::vector<Use> GetVarDeclarations(DB* db,
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<Use> GetNonDefDeclarations(DB* db, SymbolIdx sym) {
|
||||
std::vector<Use> GetNonDefDeclarations(DB *db, SymbolIdx sym) {
|
||||
switch (sym.kind) {
|
||||
case SymbolKind::Func:
|
||||
return db->GetFunc(sym).declarations;
|
||||
case SymbolKind::Type:
|
||||
return db->GetType(sym).declarations;
|
||||
case SymbolKind::Var:
|
||||
return db->GetVar(sym).declarations;
|
||||
default:
|
||||
return {};
|
||||
case SymbolKind::Func:
|
||||
return db->GetFunc(sym).declarations;
|
||||
case SymbolKind::Type:
|
||||
return db->GetType(sym).declarations;
|
||||
case SymbolKind::Var:
|
||||
return db->GetVar(sym).declarations;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root) {
|
||||
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
|
||||
std::vector<Use> ret;
|
||||
std::vector<QueryFunc*> stack{&root};
|
||||
std::vector<QueryFunc *> stack{&root};
|
||||
std::unordered_set<Usr> seen;
|
||||
seen.insert(root.usr);
|
||||
while (!stack.empty()) {
|
||||
QueryFunc& func = *stack.back();
|
||||
QueryFunc &func = *stack.back();
|
||||
stack.pop_back();
|
||||
if (auto* def = func.AnyDef()) {
|
||||
EachDefinedFunc(db, def->bases, [&](QueryFunc& func1) {
|
||||
if (auto *def = func.AnyDef()) {
|
||||
EachDefinedFunc(db, def->bases, [&](QueryFunc &func1) {
|
||||
if (!seen.count(func1.usr)) {
|
||||
seen.insert(func1.usr);
|
||||
stack.push_back(&func1);
|
||||
@ -125,15 +124,15 @@ std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root) {
|
||||
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
|
||||
std::vector<Use> ret;
|
||||
std::vector<QueryFunc*> stack{&root};
|
||||
std::vector<QueryFunc *> stack{&root};
|
||||
std::unordered_set<Usr> seen;
|
||||
seen.insert(root.usr);
|
||||
while (!stack.empty()) {
|
||||
QueryFunc& func = *stack.back();
|
||||
QueryFunc &func = *stack.back();
|
||||
stack.pop_back();
|
||||
EachDefinedFunc(db, func.derived, [&](QueryFunc& func1) {
|
||||
EachDefinedFunc(db, func.derived, [&](QueryFunc &func1) {
|
||||
if (!seen.count(func1.usr)) {
|
||||
seen.insert(func1.usr);
|
||||
stack.push_back(&func1);
|
||||
@ -145,8 +144,8 @@ std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||
const Position& position) {
|
||||
std::optional<lsPosition> GetLsPosition(WorkingFile *working_file,
|
||||
const Position &position) {
|
||||
if (!working_file)
|
||||
return lsPosition{position.line, position.column};
|
||||
|
||||
@ -157,8 +156,8 @@ std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<lsRange> GetLsRange(WorkingFile* working_file,
|
||||
const Range& location) {
|
||||
std::optional<lsRange> GetLsRange(WorkingFile *working_file,
|
||||
const Range &location) {
|
||||
if (!working_file) {
|
||||
return lsRange{lsPosition{location.start.line, location.start.column},
|
||||
lsPosition{location.end.line, location.end.column}};
|
||||
@ -187,8 +186,8 @@ std::optional<lsRange> GetLsRange(WorkingFile* working_file,
|
||||
lsPosition{*end, end_column}};
|
||||
}
|
||||
|
||||
lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path) {
|
||||
QueryFile& file = db->files[file_id];
|
||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path) {
|
||||
QueryFile &file = db->files[file_id];
|
||||
if (file.def) {
|
||||
*path = file.def->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) {
|
||||
QueryFile& file = db->files[file_id];
|
||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id) {
|
||||
QueryFile &file = db->files[file_id];
|
||||
if (file.def) {
|
||||
return lsDocumentUri::FromPath(file.def->path);
|
||||
} else {
|
||||
@ -207,8 +206,7 @@ lsDocumentUri GetLsDocumentUri(DB* db, int file_id) {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<lsLocation> GetLsLocation(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
|
||||
Use use) {
|
||||
std::string path;
|
||||
lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
|
||||
@ -219,10 +217,8 @@ std::optional<lsLocation> GetLsLocation(DB* db,
|
||||
return lsLocation{uri, *range};
|
||||
}
|
||||
|
||||
std::optional<lsLocationEx> GetLsLocationEx(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
Use use,
|
||||
bool container) {
|
||||
std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
|
||||
Use use, bool container) {
|
||||
std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use);
|
||||
if (!ls_loc)
|
||||
return std::nullopt;
|
||||
@ -230,7 +226,7 @@ std::optional<lsLocationEx> GetLsLocationEx(DB* db,
|
||||
ret.lsLocation::operator=(*ls_loc);
|
||||
if (container) {
|
||||
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);
|
||||
return false;
|
||||
});
|
||||
@ -238,9 +234,8 @@ std::optional<lsLocationEx> GetLsLocationEx(DB* db,
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
const std::vector<Use>& uses) {
|
||||
std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
|
||||
const std::vector<Use> &uses) {
|
||||
std::vector<lsLocationEx> ret;
|
||||
for (Use use : uses)
|
||||
if (auto loc =
|
||||
@ -253,14 +248,14 @@ std::vector<lsLocationEx> GetLsLocationExs(DB* db,
|
||||
return ret;
|
||||
}
|
||||
|
||||
lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym) {
|
||||
lsSymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
|
||||
lsSymbolKind ret;
|
||||
if (sym.kind == SymbolKind::File)
|
||||
ret = lsSymbolKind::File;
|
||||
else {
|
||||
ret = lsSymbolKind::Unknown;
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
for (auto& def : entity.def) {
|
||||
WithEntity(db, sym, [&](const auto &entity) {
|
||||
for (auto &def : entity.def) {
|
||||
ret = def.kind;
|
||||
break;
|
||||
}
|
||||
@ -270,44 +265,44 @@ lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym) {
|
||||
}
|
||||
|
||||
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
||||
std::optional<lsSymbolInformation> GetSymbolInfo(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
std::optional<lsSymbolInformation> GetSymbolInfo(DB *db,
|
||||
WorkingFiles *working_files,
|
||||
SymbolIdx sym,
|
||||
bool detailed_name) {
|
||||
switch (sym.kind) {
|
||||
case SymbolKind::Invalid:
|
||||
case SymbolKind::Invalid:
|
||||
break;
|
||||
case SymbolKind::File: {
|
||||
QueryFile &file = db->GetFile(sym);
|
||||
if (!file.def)
|
||||
break;
|
||||
case SymbolKind::File: {
|
||||
QueryFile& file = db->GetFile(sym);
|
||||
if (!file.def)
|
||||
break;
|
||||
|
||||
lsSymbolInformation info;
|
||||
info.name = file.def->path;
|
||||
info.kind = lsSymbolKind::File;
|
||||
return info;
|
||||
}
|
||||
default: {
|
||||
lsSymbolInformation info;
|
||||
EachEntityDef(db, sym, [&](const auto& def) {
|
||||
if (detailed_name)
|
||||
info.name = def.detailed_name;
|
||||
else
|
||||
info.name = def.Name(true);
|
||||
info.kind = def.kind;
|
||||
info.containerName = def.detailed_name;
|
||||
return false;
|
||||
});
|
||||
return info;
|
||||
}
|
||||
lsSymbolInformation info;
|
||||
info.name = file.def->path;
|
||||
info.kind = lsSymbolKind::File;
|
||||
return info;
|
||||
}
|
||||
default: {
|
||||
lsSymbolInformation info;
|
||||
EachEntityDef(db, sym, [&](const auto &def) {
|
||||
if (detailed_name)
|
||||
info.name = def.detailed_name;
|
||||
else
|
||||
info.name = def.Name(true);
|
||||
info.kind = def.kind;
|
||||
info.containerName = def.detailed_name;
|
||||
return false;
|
||||
});
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||
QueryFile* file,
|
||||
lsPosition& ls_pos) {
|
||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
|
||||
QueryFile *file,
|
||||
lsPosition &ls_pos) {
|
||||
std::vector<SymbolRef> symbols;
|
||||
if (working_file) {
|
||||
if (auto line = working_file->GetIndexPosFromBufferPos(
|
||||
@ -322,7 +317,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||
for (SymbolRef sym : file->def->all_symbols)
|
||||
if (sym.range.Contains(ls_pos.line, ls_pos.character))
|
||||
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))
|
||||
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
|
||||
// better on constructors.
|
||||
std::sort(symbols.begin(), symbols.end(),
|
||||
[](const SymbolRef& a, const SymbolRef& b) {
|
||||
int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
|
||||
if (t)
|
||||
return t < 0;
|
||||
// MacroExpansion
|
||||
if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic)))
|
||||
return t > 0;
|
||||
if ((t = (a.role & Role::Definition) - (b.role & Role::Definition)))
|
||||
return t > 0;
|
||||
// operator> orders Var/Func before Type.
|
||||
t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
|
||||
if (t)
|
||||
return t > 0;
|
||||
return a.usr < b.usr;
|
||||
});
|
||||
std::sort(
|
||||
symbols.begin(), symbols.end(),
|
||||
[](const SymbolRef &a, const SymbolRef &b) {
|
||||
int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
|
||||
if (t)
|
||||
return t < 0;
|
||||
// MacroExpansion
|
||||
if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic)))
|
||||
return t > 0;
|
||||
if ((t = (a.role & Role::Definition) - (b.role & Role::Definition)))
|
||||
return t > 0;
|
||||
// operator> orders Var/Func before Type.
|
||||
t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
|
||||
if (t)
|
||||
return t > 0;
|
||||
return a.usr < b.usr;
|
||||
});
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
@ -5,81 +5,75 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
Maybe<Use> GetDefinitionSpell(DB* db, SymbolIdx sym);
|
||||
Maybe<Use> GetDefinitionExtent(DB* db, SymbolIdx sym);
|
||||
Maybe<Use> GetDefinitionSpell(DB *db, SymbolIdx sym);
|
||||
Maybe<Use> GetDefinitionExtent(DB *db, SymbolIdx sym);
|
||||
|
||||
// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
|
||||
// for each id.
|
||||
std::vector<Use> GetFuncDeclarations(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> GetFuncDeclarations(DB *, const std::vector<Usr> &);
|
||||
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
|
||||
std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
|
||||
|
||||
// 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> GetUsesForAllDerived(DB* db, QueryFunc& root);
|
||||
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||
const Position& position);
|
||||
std::optional<lsRange> GetLsRange(WorkingFile* working_file,
|
||||
const Range& location);
|
||||
lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path);
|
||||
lsDocumentUri GetLsDocumentUri(DB* db, int file_id);
|
||||
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root);
|
||||
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root);
|
||||
std::optional<lsPosition> GetLsPosition(WorkingFile *working_file,
|
||||
const Position &position);
|
||||
std::optional<lsRange> GetLsRange(WorkingFile *working_file,
|
||||
const Range &location);
|
||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
|
||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id);
|
||||
|
||||
std::optional<lsLocation> GetLsLocation(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
|
||||
Use use);
|
||||
std::optional<lsLocationEx> GetLsLocationEx(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
Use use,
|
||||
bool container);
|
||||
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
const std::vector<Use>& refs);
|
||||
std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
|
||||
Use use, bool container);
|
||||
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.
|
||||
std::optional<lsSymbolInformation> GetSymbolInfo(DB* db,
|
||||
WorkingFiles* working_files,
|
||||
std::optional<lsSymbolInformation> GetSymbolInfo(DB *db,
|
||||
WorkingFiles *working_files,
|
||||
SymbolIdx sym,
|
||||
bool detailed_name);
|
||||
|
||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||
QueryFile* file,
|
||||
lsPosition& ls_pos);
|
||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
|
||||
QueryFile *file,
|
||||
lsPosition &ls_pos);
|
||||
|
||||
template <typename Fn>
|
||||
void WithEntity(DB* db, SymbolIdx sym, Fn&& fn) {
|
||||
template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
|
||||
switch (sym.kind) {
|
||||
case SymbolKind::Invalid:
|
||||
case SymbolKind::File:
|
||||
break;
|
||||
case SymbolKind::Func:
|
||||
fn(db->GetFunc(sym));
|
||||
break;
|
||||
case SymbolKind::Type:
|
||||
fn(db->GetType(sym));
|
||||
break;
|
||||
case SymbolKind::Var:
|
||||
fn(db->GetVar(sym));
|
||||
break;
|
||||
case SymbolKind::Invalid:
|
||||
case SymbolKind::File:
|
||||
break;
|
||||
case SymbolKind::Func:
|
||||
fn(db->GetFunc(sym));
|
||||
break;
|
||||
case SymbolKind::Type:
|
||||
fn(db->GetType(sym));
|
||||
break;
|
||||
case SymbolKind::Var:
|
||||
fn(db->GetVar(sym));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void EachEntityDef(DB* db, SymbolIdx sym, Fn&& fn) {
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
for (auto& def : entity.def)
|
||||
template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
|
||||
WithEntity(db, sym, [&](const auto &entity) {
|
||||
for (auto &def : entity.def)
|
||||
if (!fn(def))
|
||||
break;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void EachOccurrence(DB* db, SymbolIdx sym, bool include_decl, Fn&& fn) {
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
|
||||
WithEntity(db, sym, [&](const auto &entity) {
|
||||
for (Use use : entity.uses)
|
||||
fn(use);
|
||||
if (include_decl) {
|
||||
for (auto& def : entity.def)
|
||||
for (auto &def : entity.def)
|
||||
if (def.spell)
|
||||
fn(*def.spell);
|
||||
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>
|
||||
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) {
|
||||
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);
|
||||
auto &obj = db->Func(usr);
|
||||
if (!obj.def.empty())
|
||||
fn(obj);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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())
|
||||
fn(obj);
|
||||
}
|
||||
|
@ -18,143 +18,115 @@ bool gTestOutputMode = false;
|
||||
|
||||
//// Elementary types
|
||||
|
||||
void Reflect(Reader& visitor, uint8_t& value) {
|
||||
value = visitor.GetUInt8();
|
||||
}
|
||||
void Reflect(Writer& visitor, uint8_t& value) {
|
||||
visitor.UInt8(value);
|
||||
}
|
||||
void Reflect(Reader &visitor, uint8_t &value) { value = visitor.GetUInt8(); }
|
||||
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())
|
||||
throw std::invalid_argument("short");
|
||||
value = (short)visitor.GetInt();
|
||||
}
|
||||
void Reflect(Writer& visitor, short& value) {
|
||||
visitor.Int(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, short &value) { visitor.Int(value); }
|
||||
|
||||
void Reflect(Reader& visitor, unsigned short& value) {
|
||||
void Reflect(Reader &visitor, unsigned short &value) {
|
||||
if (!visitor.IsInt())
|
||||
throw std::invalid_argument("unsigned short");
|
||||
value = (unsigned short)visitor.GetInt();
|
||||
}
|
||||
void Reflect(Writer& visitor, unsigned short& value) {
|
||||
visitor.Int(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, unsigned short &value) { visitor.Int(value); }
|
||||
|
||||
void Reflect(Reader& visitor, int& value) {
|
||||
void Reflect(Reader &visitor, int &value) {
|
||||
if (!visitor.IsInt())
|
||||
throw std::invalid_argument("int");
|
||||
value = visitor.GetInt();
|
||||
}
|
||||
void Reflect(Writer& visitor, int& value) {
|
||||
visitor.Int(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, int &value) { visitor.Int(value); }
|
||||
|
||||
void Reflect(Reader& visitor, unsigned& value) {
|
||||
void Reflect(Reader &visitor, unsigned &value) {
|
||||
if (!visitor.IsUInt64())
|
||||
throw std::invalid_argument("unsigned");
|
||||
value = visitor.GetUInt32();
|
||||
}
|
||||
void Reflect(Writer& visitor, unsigned& value) {
|
||||
visitor.UInt32(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, unsigned &value) { visitor.UInt32(value); }
|
||||
|
||||
void Reflect(Reader& visitor, long& value) {
|
||||
void Reflect(Reader &visitor, long &value) {
|
||||
if (!visitor.IsInt64())
|
||||
throw std::invalid_argument("long");
|
||||
value = long(visitor.GetInt64());
|
||||
}
|
||||
void Reflect(Writer& visitor, long& value) {
|
||||
visitor.Int64(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, long &value) { visitor.Int64(value); }
|
||||
|
||||
void Reflect(Reader& visitor, unsigned long& value) {
|
||||
void Reflect(Reader &visitor, unsigned long &value) {
|
||||
if (!visitor.IsUInt64())
|
||||
throw std::invalid_argument("unsigned long");
|
||||
value = (unsigned long)visitor.GetUInt64();
|
||||
}
|
||||
void Reflect(Writer& visitor, unsigned long& value) {
|
||||
visitor.UInt64(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, unsigned long &value) { visitor.UInt64(value); }
|
||||
|
||||
void Reflect(Reader& visitor, long long& value) {
|
||||
void Reflect(Reader &visitor, long long &value) {
|
||||
if (!visitor.IsInt64())
|
||||
throw std::invalid_argument("long long");
|
||||
value = visitor.GetInt64();
|
||||
}
|
||||
void Reflect(Writer& visitor, long long& value) {
|
||||
visitor.Int64(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, long long &value) { visitor.Int64(value); }
|
||||
|
||||
void Reflect(Reader& visitor, unsigned long long& value) {
|
||||
void Reflect(Reader &visitor, unsigned long long &value) {
|
||||
if (!visitor.IsUInt64())
|
||||
throw std::invalid_argument("unsigned long long");
|
||||
value = visitor.GetUInt64();
|
||||
}
|
||||
void Reflect(Writer& visitor, unsigned long long& value) {
|
||||
void Reflect(Writer &visitor, unsigned long long &value) {
|
||||
visitor.UInt64(value);
|
||||
}
|
||||
|
||||
void Reflect(Reader& visitor, double& value) {
|
||||
void Reflect(Reader &visitor, double &value) {
|
||||
if (!visitor.IsDouble())
|
||||
throw std::invalid_argument("double");
|
||||
value = visitor.GetDouble();
|
||||
}
|
||||
void Reflect(Writer& visitor, double& value) {
|
||||
visitor.Double(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, double &value) { visitor.Double(value); }
|
||||
|
||||
void Reflect(Reader& visitor, bool& value) {
|
||||
void Reflect(Reader &visitor, bool &value) {
|
||||
if (!visitor.IsBool())
|
||||
throw std::invalid_argument("bool");
|
||||
value = visitor.GetBool();
|
||||
}
|
||||
void Reflect(Writer& visitor, bool& value) {
|
||||
visitor.Bool(value);
|
||||
}
|
||||
void Reflect(Writer &visitor, bool &value) { visitor.Bool(value); }
|
||||
|
||||
void Reflect(Reader& visitor, std::string& value) {
|
||||
void Reflect(Reader &visitor, std::string &value) {
|
||||
if (!visitor.IsString())
|
||||
throw std::invalid_argument("std::string");
|
||||
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());
|
||||
}
|
||||
|
||||
void Reflect(Reader&, std::string_view&) {
|
||||
assert(0);
|
||||
}
|
||||
void Reflect(Writer& visitor, std::string_view& data) {
|
||||
void Reflect(Reader &, std::string_view &) { assert(0); }
|
||||
void Reflect(Writer &visitor, std::string_view &data) {
|
||||
if (data.empty())
|
||||
visitor.String("");
|
||||
else
|
||||
visitor.String(&data[0], (rapidjson::SizeType)data.size());
|
||||
}
|
||||
|
||||
void Reflect(Reader& vis, const char*& v) {
|
||||
const char* str = vis.GetString();
|
||||
void Reflect(Reader &vis, const char *&v) {
|
||||
const char *str = vis.GetString();
|
||||
v = ccls::Intern(str);
|
||||
}
|
||||
void Reflect(Writer& vis, const char*& v) {
|
||||
vis.String(v);
|
||||
}
|
||||
void Reflect(Writer &vis, const char *&v) { vis.String(v); }
|
||||
|
||||
void Reflect(Reader& visitor, JsonNull& value) {
|
||||
void Reflect(Reader &visitor, JsonNull &value) {
|
||||
assert(visitor.Format() == SerializeFormat::Json);
|
||||
visitor.GetNull();
|
||||
}
|
||||
|
||||
void Reflect(Writer& visitor, JsonNull& value) {
|
||||
visitor.Null();
|
||||
}
|
||||
void Reflect(Writer &visitor, JsonNull &value) { visitor.Null(); }
|
||||
|
||||
// std::unordered_map
|
||||
template <typename V>
|
||||
void Reflect(Reader& visitor, std::unordered_map<Usr, V>& map) {
|
||||
visitor.IterArray([&](Reader& entry) {
|
||||
void Reflect(Reader &visitor, std::unordered_map<Usr, V> &map) {
|
||||
visitor.IterArray([&](Reader &entry) {
|
||||
V val;
|
||||
Reflect(entry, val);
|
||||
auto usr = val.usr;
|
||||
@ -162,20 +134,20 @@ void Reflect(Reader& visitor, std::unordered_map<Usr, V>& map) {
|
||||
});
|
||||
}
|
||||
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::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());
|
||||
for (auto& it : xs)
|
||||
for (auto &it : xs)
|
||||
Reflect(visitor, it.second);
|
||||
visitor.EndArray();
|
||||
}
|
||||
|
||||
// Used by IndexFile::dependencies. Timestamps are emitted for Binary.
|
||||
void Reflect(Reader& visitor, StringMap<int64_t>& map) {
|
||||
visitor.IterArray([&](Reader& entry) {
|
||||
std::string name;
|
||||
void Reflect(Reader &visitor, StringMap<int64_t> &map) {
|
||||
visitor.IterArray([&](Reader &entry) {
|
||||
std::string name;
|
||||
Reflect(entry, name);
|
||||
if (visitor.Format() == SerializeFormat::Binary)
|
||||
Reflect(entry, map[name]);
|
||||
@ -183,9 +155,9 @@ void Reflect(Reader& visitor, StringMap<int64_t>& map) {
|
||||
map[name] = 0;
|
||||
});
|
||||
}
|
||||
void Reflect(Writer& visitor, StringMap<int64_t>& map) {
|
||||
void Reflect(Writer &visitor, StringMap<int64_t> &map) {
|
||||
visitor.StartArray(map.size());
|
||||
for (auto& it : map) {
|
||||
for (auto &it : map) {
|
||||
std::string key = it.first();
|
||||
Reflect(visitor, key);
|
||||
if (visitor.Format() == SerializeFormat::Binary)
|
||||
@ -195,13 +167,13 @@ void Reflect(Writer& visitor, StringMap<int64_t>& map) {
|
||||
}
|
||||
|
||||
// TODO: Move this to indexer.cc
|
||||
void Reflect(Reader& visitor, IndexInclude& value) {
|
||||
void Reflect(Reader &visitor, IndexInclude &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(line);
|
||||
REFLECT_MEMBER(resolved_path);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
void Reflect(Writer& visitor, IndexInclude& value) {
|
||||
void Reflect(Writer &visitor, IndexInclude &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(line);
|
||||
if (gTestOutputMode) {
|
||||
@ -216,13 +188,13 @@ void Reflect(Writer& visitor, IndexInclude& value) {
|
||||
}
|
||||
|
||||
template <typename Def>
|
||||
void ReflectHoverAndComments(Reader& visitor, Def& def) {
|
||||
void ReflectHoverAndComments(Reader &visitor, Def &def) {
|
||||
ReflectMember(visitor, "hover", def.hover);
|
||||
ReflectMember(visitor, "comments", def.comments);
|
||||
}
|
||||
|
||||
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.
|
||||
if (!gTestOutputMode || def.hover[0])
|
||||
ReflectMember(visitor, "hover", def.hover);
|
||||
@ -230,12 +202,12 @@ void ReflectHoverAndComments(Writer& visitor, Def& def) {
|
||||
ReflectMember(visitor, "comments", def.comments);
|
||||
}
|
||||
|
||||
template <typename Def>
|
||||
void ReflectShortName(Reader& visitor, Def& def) {
|
||||
template <typename Def> void ReflectShortName(Reader &visitor, Def &def) {
|
||||
if (gTestOutputMode) {
|
||||
std::string 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);
|
||||
def.short_name_size = short_name.size();
|
||||
} else {
|
||||
@ -244,8 +216,7 @@ void ReflectShortName(Reader& visitor, Def& def) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Def>
|
||||
void ReflectShortName(Writer& visitor, Def& def) {
|
||||
template <typename Def> void ReflectShortName(Writer &visitor, Def &def) {
|
||||
if (gTestOutputMode) {
|
||||
std::string_view short_name(def.detailed_name + def.short_name_offset,
|
||||
def.short_name_size);
|
||||
@ -256,8 +227,7 @@ void ReflectShortName(Writer& visitor, Def& def) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexType& value) {
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexType &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("usr", value.usr);
|
||||
REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
|
||||
@ -279,8 +249,7 @@ void Reflect(TVisitor& visitor, IndexType& value) {
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexFunc& value) {
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFunc &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("usr", value.usr);
|
||||
REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
|
||||
@ -300,8 +269,7 @@ void Reflect(TVisitor& visitor, IndexFunc& value) {
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexVar& value) {
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexVar &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("usr", value.usr);
|
||||
REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
|
||||
@ -319,12 +287,11 @@ void Reflect(TVisitor& visitor, IndexVar& value) {
|
||||
}
|
||||
|
||||
// IndexFile
|
||||
bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
|
||||
bool ReflectMemberStart(Writer &visitor, IndexFile &value) {
|
||||
visitor.StartObject();
|
||||
return true;
|
||||
}
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexFile& value) {
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFile &value) {
|
||||
REFLECT_MEMBER_START();
|
||||
if (!gTestOutputMode) {
|
||||
REFLECT_MEMBER(last_write_time);
|
||||
@ -342,19 +309,19 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
void Reflect(Reader& visitor, SerializeFormat& value) {
|
||||
void Reflect(Reader &visitor, SerializeFormat &value) {
|
||||
std::string fmt = visitor.GetString();
|
||||
value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json;
|
||||
}
|
||||
|
||||
void Reflect(Writer& visitor, SerializeFormat& value) {
|
||||
void Reflect(Writer &visitor, SerializeFormat &value) {
|
||||
switch (value) {
|
||||
case SerializeFormat::Binary:
|
||||
visitor.String("binary");
|
||||
break;
|
||||
case SerializeFormat::Json:
|
||||
visitor.String("json");
|
||||
break;
|
||||
case SerializeFormat::Binary:
|
||||
visitor.String("binary");
|
||||
break;
|
||||
case SerializeFormat::Json:
|
||||
visitor.String("json");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,8 +330,9 @@ static BumpPtrAllocator Alloc;
|
||||
static DenseSet<StringRef> Strings;
|
||||
static std::mutex AllocMutex;
|
||||
|
||||
const char* Intern(const std::string& str) {
|
||||
if (str.empty()) return "";
|
||||
const char *Intern(const std::string &str) {
|
||||
if (str.empty())
|
||||
return "";
|
||||
StringRef Str(str.data(), str.size() + 1);
|
||||
std::lock_guard lock(AllocMutex);
|
||||
auto R = Strings.insert(Str);
|
||||
@ -373,100 +341,98 @@ const char* Intern(const std::string& str) {
|
||||
return R.first->data();
|
||||
}
|
||||
|
||||
std::string Serialize(SerializeFormat format, IndexFile& file) {
|
||||
std::string Serialize(SerializeFormat format, IndexFile &file) {
|
||||
switch (format) {
|
||||
case SerializeFormat::Binary: {
|
||||
BinaryWriter writer;
|
||||
int major = IndexFile::kMajorVersion;
|
||||
int minor = IndexFile::kMinorVersion;
|
||||
Reflect(writer, major);
|
||||
Reflect(writer, minor);
|
||||
Reflect(writer, file);
|
||||
return writer.Take();
|
||||
}
|
||||
case SerializeFormat::Json: {
|
||||
rapidjson::StringBuffer output;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||
writer.SetFormatOptions(
|
||||
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
||||
writer.SetIndent(' ', 2);
|
||||
JsonWriter json_writer(&writer);
|
||||
if (!gTestOutputMode) {
|
||||
std::string version = std::to_string(IndexFile::kMajorVersion);
|
||||
for (char c : version)
|
||||
output.Put(c);
|
||||
output.Put('\n');
|
||||
}
|
||||
Reflect(json_writer, file);
|
||||
return output.GetString();
|
||||
case SerializeFormat::Binary: {
|
||||
BinaryWriter writer;
|
||||
int major = IndexFile::kMajorVersion;
|
||||
int minor = IndexFile::kMinorVersion;
|
||||
Reflect(writer, major);
|
||||
Reflect(writer, minor);
|
||||
Reflect(writer, file);
|
||||
return writer.Take();
|
||||
}
|
||||
case SerializeFormat::Json: {
|
||||
rapidjson::StringBuffer output;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||
writer.SetFormatOptions(
|
||||
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
||||
writer.SetIndent(' ', 2);
|
||||
JsonWriter json_writer(&writer);
|
||||
if (!gTestOutputMode) {
|
||||
std::string version = std::to_string(IndexFile::kMajorVersion);
|
||||
for (char c : version)
|
||||
output.Put(c);
|
||||
output.Put('\n');
|
||||
}
|
||||
Reflect(json_writer, file);
|
||||
return output.GetString();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::unique_ptr<IndexFile> Deserialize(
|
||||
SerializeFormat format,
|
||||
const std::string& path,
|
||||
const std::string& serialized_index_content,
|
||||
const std::string& file_content,
|
||||
std::optional<int> expected_version) {
|
||||
std::unique_ptr<IndexFile>
|
||||
Deserialize(SerializeFormat format, const std::string &path,
|
||||
const std::string &serialized_index_content,
|
||||
const std::string &file_content,
|
||||
std::optional<int> expected_version) {
|
||||
if (serialized_index_content.empty())
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<IndexFile> file;
|
||||
switch (format) {
|
||||
case SerializeFormat::Binary: {
|
||||
try {
|
||||
int major, minor;
|
||||
if (serialized_index_content.size() < 8)
|
||||
throw std::invalid_argument("Invalid");
|
||||
BinaryReader reader(serialized_index_content);
|
||||
Reflect(reader, major);
|
||||
Reflect(reader, minor);
|
||||
if (major != IndexFile::kMajorVersion ||
|
||||
minor != IndexFile::kMinorVersion)
|
||||
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;
|
||||
|
||||
case SerializeFormat::Binary: {
|
||||
try {
|
||||
int major, minor;
|
||||
if (serialized_index_content.size() < 8)
|
||||
throw std::invalid_argument("Invalid");
|
||||
BinaryReader reader(serialized_index_content);
|
||||
Reflect(reader, major);
|
||||
Reflect(reader, minor);
|
||||
if (major != IndexFile::kMajorVersion ||
|
||||
minor != IndexFile::kMinorVersion)
|
||||
throw std::invalid_argument("Invalid version");
|
||||
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;
|
||||
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_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.
|
||||
file->path = path;
|
||||
return file;
|
||||
}
|
||||
}
|
||||
} // namespace ccls
|
||||
|
226
src/serializer.h
226
src/serializer.h
@ -21,7 +21,7 @@ struct JsonNull {};
|
||||
struct mandatory_optional_tag {};
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
public:
|
||||
virtual ~Reader() {}
|
||||
virtual SerializeFormat Format() const = 0;
|
||||
|
||||
@ -41,17 +41,17 @@ class Reader {
|
||||
virtual int64_t GetInt64() = 0;
|
||||
virtual uint64_t GetUInt64() = 0;
|
||||
virtual double GetDouble() = 0;
|
||||
virtual const char* GetString() = 0;
|
||||
virtual const char *GetString() = 0;
|
||||
|
||||
virtual bool HasMember(const char* x) = 0;
|
||||
virtual std::unique_ptr<Reader> operator[](const char* x) = 0;
|
||||
virtual bool HasMember(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 Member(const char* name, std::function<void()> fn) = 0;
|
||||
virtual void IterArray(std::function<void(Reader &)> fn) = 0;
|
||||
virtual void Member(const char *name, std::function<void()> fn) = 0;
|
||||
};
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
public:
|
||||
virtual ~Writer() {}
|
||||
virtual SerializeFormat Format() const = 0;
|
||||
|
||||
@ -63,13 +63,13 @@ class Writer {
|
||||
virtual void UInt32(uint32_t x) = 0;
|
||||
virtual void UInt64(uint64_t x) = 0;
|
||||
virtual void Double(double 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) = 0;
|
||||
virtual void String(const char *x, size_t len) = 0;
|
||||
virtual void StartArray(size_t) = 0;
|
||||
virtual void EndArray() = 0;
|
||||
virtual void StartObject() = 0;
|
||||
virtual void EndObject() = 0;
|
||||
virtual void Key(const char* name) = 0;
|
||||
virtual void Key(const char *name) = 0;
|
||||
};
|
||||
|
||||
struct IndexFile;
|
||||
@ -77,48 +77,45 @@ struct IndexFile;
|
||||
#define REFLECT_MEMBER_START() ReflectMemberStart(visitor)
|
||||
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor);
|
||||
#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{})
|
||||
#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>)
|
||||
#define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \
|
||||
LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \
|
||||
as_type value0; \
|
||||
::Reflect(visitor, value0); \
|
||||
value = static_cast<type>(value0); \
|
||||
} \
|
||||
LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer& visitor, type& value) { \
|
||||
auto value0 = static_cast<as_type>(value); \
|
||||
::Reflect(visitor, value0); \
|
||||
#define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \
|
||||
LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader &visitor, type &value) { \
|
||||
as_type value0; \
|
||||
::Reflect(visitor, value0); \
|
||||
value = static_cast<type>(value0); \
|
||||
} \
|
||||
LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer &visitor, type &value) { \
|
||||
auto value0 = static_cast<as_type>(value); \
|
||||
::Reflect(visitor, value0); \
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
|
||||
template <typename TVisitor> \
|
||||
void Reflect(TVisitor& visitor, type& value) { \
|
||||
REFLECT_MEMBER_START(); \
|
||||
REFLECT_MEMBER_END(); \
|
||||
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
|
||||
REFLECT_MEMBER_START(); \
|
||||
REFLECT_MEMBER_END(); \
|
||||
}
|
||||
|
||||
#define MAKE_REFLECT_STRUCT(type, ...) \
|
||||
template <typename TVisitor> \
|
||||
void Reflect(TVisitor& visitor, type& value) { \
|
||||
REFLECT_MEMBER_START(); \
|
||||
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
|
||||
REFLECT_MEMBER_END(); \
|
||||
#define MAKE_REFLECT_STRUCT(type, ...) \
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
|
||||
REFLECT_MEMBER_START(); \
|
||||
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
|
||||
REFLECT_MEMBER_END(); \
|
||||
}
|
||||
|
||||
#define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...) \
|
||||
template <typename TVisitor> \
|
||||
void Reflect(TVisitor& visitor, type& value) { \
|
||||
REFLECT_MEMBER_START(); \
|
||||
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__) \
|
||||
REFLECT_MEMBER_END(); \
|
||||
#define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...) \
|
||||
template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
|
||||
REFLECT_MEMBER_START(); \
|
||||
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__) \
|
||||
REFLECT_MEMBER_END(); \
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@ -131,71 +128,70 @@ struct IndexFile;
|
||||
|
||||
// Reflects the struct so it is serialized as an array instead of an object.
|
||||
// This currently only supports writers.
|
||||
#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \
|
||||
inline void Reflect(Writer& visitor, type& value) { \
|
||||
visitor.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \
|
||||
MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \
|
||||
visitor.EndArray(); \
|
||||
#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \
|
||||
inline void Reflect(Writer &visitor, type &value) { \
|
||||
visitor.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \
|
||||
MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \
|
||||
visitor.EndArray(); \
|
||||
}
|
||||
|
||||
//// Elementary types
|
||||
|
||||
void Reflect(Reader& visitor, uint8_t& value);
|
||||
void Reflect(Writer& visitor, uint8_t& value);
|
||||
void Reflect(Reader &visitor, uint8_t &value);
|
||||
void Reflect(Writer &visitor, uint8_t &value);
|
||||
|
||||
void Reflect(Reader& visitor, short& value);
|
||||
void Reflect(Writer& visitor, short& value);
|
||||
void Reflect(Reader &visitor, short &value);
|
||||
void Reflect(Writer &visitor, short &value);
|
||||
|
||||
void Reflect(Reader& visitor, unsigned short& value);
|
||||
void Reflect(Writer& visitor, unsigned short& value);
|
||||
void Reflect(Reader &visitor, unsigned short &value);
|
||||
void Reflect(Writer &visitor, unsigned short &value);
|
||||
|
||||
void Reflect(Reader& visitor, int& value);
|
||||
void Reflect(Writer& visitor, int& value);
|
||||
void Reflect(Reader &visitor, int &value);
|
||||
void Reflect(Writer &visitor, int &value);
|
||||
|
||||
void Reflect(Reader& visitor, unsigned& value);
|
||||
void Reflect(Writer& visitor, unsigned& value);
|
||||
void Reflect(Reader &visitor, unsigned &value);
|
||||
void Reflect(Writer &visitor, unsigned &value);
|
||||
|
||||
void Reflect(Reader& visitor, long& value);
|
||||
void Reflect(Writer& visitor, long& value);
|
||||
void Reflect(Reader &visitor, long &value);
|
||||
void Reflect(Writer &visitor, long &value);
|
||||
|
||||
void Reflect(Reader& visitor, unsigned long& value);
|
||||
void Reflect(Writer& visitor, unsigned long& value);
|
||||
void Reflect(Reader &visitor, unsigned long &value);
|
||||
void Reflect(Writer &visitor, unsigned long &value);
|
||||
|
||||
void Reflect(Reader& visitor, long long& value);
|
||||
void Reflect(Writer& visitor, long long& value);
|
||||
void Reflect(Reader &visitor, long long &value);
|
||||
void Reflect(Writer &visitor, long long &value);
|
||||
|
||||
void Reflect(Reader& visitor, unsigned long long& value);
|
||||
void Reflect(Writer& visitor, unsigned long long& value);
|
||||
void Reflect(Reader &visitor, unsigned long long &value);
|
||||
void Reflect(Writer &visitor, unsigned long long &value);
|
||||
|
||||
void Reflect(Reader& visitor, double& value);
|
||||
void Reflect(Writer& visitor, double& value);
|
||||
void Reflect(Reader &visitor, double &value);
|
||||
void Reflect(Writer &visitor, double &value);
|
||||
|
||||
void Reflect(Reader& visitor, bool& value);
|
||||
void Reflect(Writer& visitor, bool& value);
|
||||
void Reflect(Reader &visitor, bool &value);
|
||||
void Reflect(Writer &visitor, bool &value);
|
||||
|
||||
void Reflect(Reader& visitor, std::string& value);
|
||||
void Reflect(Writer& visitor, std::string& value);
|
||||
void Reflect(Reader &visitor, std::string &value);
|
||||
void Reflect(Writer &visitor, std::string &value);
|
||||
|
||||
void Reflect(Reader& visitor, std::string_view& view);
|
||||
void Reflect(Writer& visitor, std::string_view& view);
|
||||
void Reflect(Reader &visitor, std::string_view &view);
|
||||
void Reflect(Writer &visitor, std::string_view &view);
|
||||
|
||||
void Reflect(Reader& vis, const char*& v);
|
||||
void Reflect(Writer& vis, const char*& v);
|
||||
void Reflect(Reader &vis, const char *&v);
|
||||
void Reflect(Writer &vis, const char *&v);
|
||||
|
||||
void Reflect(Reader& visitor, JsonNull& value);
|
||||
void Reflect(Writer& visitor, JsonNull& value);
|
||||
void Reflect(Reader &visitor, JsonNull &value);
|
||||
void Reflect(Writer &visitor, JsonNull &value);
|
||||
|
||||
void Reflect(Reader& visitor, SerializeFormat& value);
|
||||
void Reflect(Writer& visitor, SerializeFormat& value);
|
||||
void Reflect(Reader &visitor, SerializeFormat &value);
|
||||
void Reflect(Writer &visitor, SerializeFormat &value);
|
||||
|
||||
//// Type constructors
|
||||
|
||||
// ReflectMember std::optional<T> is used to represent TypeScript optional properties
|
||||
// (in `key: value` context).
|
||||
// Reflect std::optional<T> is used for a different purpose, whether an object is
|
||||
// nullable (possibly in `value` context).
|
||||
template <typename T>
|
||||
void Reflect(Reader& visitor, std::optional<T>& value) {
|
||||
// ReflectMember std::optional<T> is used to represent TypeScript optional
|
||||
// properties (in `key: value` context). Reflect std::optional<T> is used for a
|
||||
// different purpose, whether an object is nullable (possibly in `value`
|
||||
// context).
|
||||
template <typename T> void Reflect(Reader &visitor, std::optional<T> &value) {
|
||||
if (visitor.IsNull()) {
|
||||
visitor.GetNull();
|
||||
return;
|
||||
@ -204,8 +200,7 @@ void Reflect(Reader& visitor, std::optional<T>& value) {
|
||||
Reflect(visitor, real_value);
|
||||
value = std::move(real_value);
|
||||
}
|
||||
template <typename T>
|
||||
void Reflect(Writer& visitor, std::optional<T>& value) {
|
||||
template <typename T> void Reflect(Writer &visitor, std::optional<T> &value) {
|
||||
if (value) {
|
||||
if (visitor.Format() != SerializeFormat::Json)
|
||||
visitor.UInt8(1);
|
||||
@ -215,8 +210,7 @@ void Reflect(Writer& visitor, std::optional<T>& value) {
|
||||
}
|
||||
|
||||
// The same as std::optional
|
||||
template <typename T>
|
||||
void Reflect(Reader& visitor, Maybe<T>& value) {
|
||||
template <typename T> void Reflect(Reader &visitor, Maybe<T> &value) {
|
||||
if (visitor.IsNull()) {
|
||||
visitor.GetNull();
|
||||
return;
|
||||
@ -225,8 +219,7 @@ void Reflect(Reader& visitor, Maybe<T>& value) {
|
||||
Reflect(visitor, real_value);
|
||||
value = std::move(real_value);
|
||||
}
|
||||
template <typename T>
|
||||
void Reflect(Writer& visitor, Maybe<T>& value) {
|
||||
template <typename T> void Reflect(Writer &visitor, Maybe<T> &value) {
|
||||
if (value) {
|
||||
if (visitor.Format() != SerializeFormat::Json)
|
||||
visitor.UInt8(1);
|
||||
@ -236,7 +229,7 @@ void Reflect(Writer& visitor, Maybe<T>& value) {
|
||||
}
|
||||
|
||||
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,
|
||||
// We omit both key and value if value is std::nullopt (null) for JsonWriter
|
||||
// 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
|
||||
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) {
|
||||
visitor.Key(name);
|
||||
Reflect(visitor, value);
|
||||
@ -256,21 +249,19 @@ void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReflectMember(Writer& visitor,
|
||||
const char* name,
|
||||
T& value,
|
||||
void ReflectMember(Writer &visitor, const char *name, T &value,
|
||||
mandatory_optional_tag) {
|
||||
visitor.Key(name);
|
||||
Reflect(visitor, value);
|
||||
}
|
||||
|
||||
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("R", [&]() { Reflect(vis, v.second); });
|
||||
}
|
||||
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();
|
||||
ReflectMember(vis, "L", v.first);
|
||||
ReflectMember(vis, "R", v.second);
|
||||
@ -278,43 +269,35 @@ void Reflect(Writer& vis, std::pair<L, R>& v) {
|
||||
}
|
||||
|
||||
// std::vector
|
||||
template <typename T>
|
||||
void Reflect(Reader& visitor, std::vector<T>& values) {
|
||||
visitor.IterArray([&](Reader& entry) {
|
||||
template <typename T> void Reflect(Reader &visitor, std::vector<T> &values) {
|
||||
visitor.IterArray([&](Reader &entry) {
|
||||
T entry_value;
|
||||
Reflect(entry, entry_value);
|
||||
values.push_back(std::move(entry_value));
|
||||
});
|
||||
}
|
||||
template <typename T>
|
||||
void Reflect(Writer& visitor, std::vector<T>& values) {
|
||||
template <typename T> void Reflect(Writer &visitor, std::vector<T> &values) {
|
||||
visitor.StartArray(values.size());
|
||||
for (auto& value : values)
|
||||
for (auto &value : values)
|
||||
Reflect(visitor, value);
|
||||
visitor.EndArray();
|
||||
}
|
||||
|
||||
// ReflectMember
|
||||
|
||||
inline bool ReflectMemberStart(Reader& vis) {
|
||||
return false;
|
||||
}
|
||||
inline bool ReflectMemberStart(Writer& vis) {
|
||||
inline bool ReflectMemberStart(Reader &vis) { return false; }
|
||||
inline bool ReflectMemberStart(Writer &vis) {
|
||||
vis.StartObject();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void ReflectMemberEnd(Reader& vis) {}
|
||||
inline void ReflectMemberEnd(Writer& vis) {
|
||||
vis.EndObject();
|
||||
}
|
||||
inline void ReflectMemberEnd(Reader &vis) {}
|
||||
inline void ReflectMemberEnd(Writer &vis) { vis.EndObject(); }
|
||||
|
||||
template <typename T>
|
||||
void ReflectMember(Reader& vis, const char* name, T& v) {
|
||||
template <typename T> void ReflectMember(Reader &vis, const char *name, T &v) {
|
||||
vis.Member(name, [&]() { Reflect(vis, v); });
|
||||
}
|
||||
template <typename T>
|
||||
void ReflectMember(Writer& vis, const char* name, T& v) {
|
||||
template <typename T> void ReflectMember(Writer &vis, const char *name, T &v) {
|
||||
vis.Key(name);
|
||||
Reflect(vis, v);
|
||||
}
|
||||
@ -322,12 +305,11 @@ void ReflectMember(Writer& vis, const char* name, T& v) {
|
||||
// API
|
||||
|
||||
namespace ccls {
|
||||
const char* Intern(const std::string& str);
|
||||
std::string Serialize(SerializeFormat format, IndexFile& file);
|
||||
std::unique_ptr<IndexFile> Deserialize(
|
||||
SerializeFormat format,
|
||||
const std::string& path,
|
||||
const std::string& serialized_index_content,
|
||||
const std::string& file_content,
|
||||
std::optional<int> expected_version);
|
||||
}
|
||||
const char *Intern(const std::string &str);
|
||||
std::string Serialize(SerializeFormat format, IndexFile &file);
|
||||
std::unique_ptr<IndexFile>
|
||||
Deserialize(SerializeFormat format, const std::string &path,
|
||||
const std::string &serialized_index_content,
|
||||
const std::string &file_content,
|
||||
std::optional<int> expected_version);
|
||||
} // namespace ccls
|
||||
|
@ -5,17 +5,16 @@
|
||||
#include <assert.h>
|
||||
|
||||
class BinaryReader : public Reader {
|
||||
const char* p_;
|
||||
const char *p_;
|
||||
|
||||
template <typename T>
|
||||
T Get() {
|
||||
auto ret = *reinterpret_cast<const T*>(p_);
|
||||
template <typename T> T Get() {
|
||||
auto ret = *reinterpret_cast<const T *>(p_);
|
||||
p_ += sizeof(T);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t VarUInt() {
|
||||
auto x = *reinterpret_cast<const uint8_t*>(p_++);
|
||||
auto x = *reinterpret_cast<const uint8_t *>(p_++);
|
||||
if (x < 253)
|
||||
return x;
|
||||
if (x == 253)
|
||||
@ -29,11 +28,9 @@ class BinaryReader : public Reader {
|
||||
return int64_t(x >> 1 ^ -(x & 1));
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
BinaryReader(std::string_view buf) : p_(buf.data()) {}
|
||||
SerializeFormat Format() const override {
|
||||
return SerializeFormat::Binary;
|
||||
}
|
||||
SerializeFormat Format() const override { return SerializeFormat::Binary; }
|
||||
|
||||
bool IsBool() override { return true; }
|
||||
// Abuse how the function is called in serializer.h
|
||||
@ -52,35 +49,32 @@ class BinaryReader : public Reader {
|
||||
uint32_t GetUInt32() override { return VarUInt(); }
|
||||
uint64_t GetUInt64() override { return VarUInt(); }
|
||||
double GetDouble() override { return Get<double>(); }
|
||||
const char* GetString() override {
|
||||
const char* ret = p_;
|
||||
const char *GetString() override {
|
||||
const char *ret = p_;
|
||||
while (*p_)
|
||||
p_++;
|
||||
p_++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HasMember(const char* x) override { return true; }
|
||||
std::unique_ptr<Reader> operator[](const char* x) override { return {}; }
|
||||
bool HasMember(const char *x) override { return true; }
|
||||
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--)
|
||||
fn(*this);
|
||||
}
|
||||
|
||||
void Member(const char*, std::function<void()> fn) override {
|
||||
fn();
|
||||
}
|
||||
void Member(const char *, std::function<void()> fn) override { fn(); }
|
||||
};
|
||||
|
||||
class BinaryWriter : public Writer {
|
||||
std::string buf_;
|
||||
|
||||
template <typename T>
|
||||
void Pack(T x) {
|
||||
template <typename T> void Pack(T x) {
|
||||
auto i = buf_.size();
|
||||
buf_.resize(i + sizeof(x));
|
||||
*reinterpret_cast<T*>(buf_.data() + i) = x;
|
||||
*reinterpret_cast<T *>(buf_.data() + i) = x;
|
||||
}
|
||||
|
||||
void VarUInt(uint64_t n) {
|
||||
@ -97,14 +91,10 @@ class BinaryWriter : public Writer {
|
||||
Pack<uint64_t>(n);
|
||||
}
|
||||
}
|
||||
void VarInt(int64_t n) {
|
||||
VarUInt(uint64_t(n) << 1 ^ n >> 63);
|
||||
}
|
||||
void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); }
|
||||
|
||||
public:
|
||||
SerializeFormat Format() const override {
|
||||
return SerializeFormat::Binary;
|
||||
}
|
||||
public:
|
||||
SerializeFormat Format() const override { return SerializeFormat::Binary; }
|
||||
std::string Take() { return std::move(buf_); }
|
||||
|
||||
void Null() override { Pack(uint8_t(0)); }
|
||||
@ -115,8 +105,8 @@ class BinaryWriter : public Writer {
|
||||
void UInt32(uint32_t x) override { VarUInt(x); }
|
||||
void UInt64(uint64_t x) override { VarUInt(x); }
|
||||
void Double(double x) override { Pack(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) override { String(x, strlen(x)); }
|
||||
void String(const char *x, size_t len) override {
|
||||
auto i = buf_.size();
|
||||
buf_.resize(i + len + 1);
|
||||
memcpy(buf_.data() + i, x, len);
|
||||
@ -125,5 +115,5 @@ class BinaryWriter : public Writer {
|
||||
void EndArray() override {}
|
||||
void StartObject() override {}
|
||||
void EndObject() override {}
|
||||
void Key(const char* name) override {}
|
||||
void Key(const char *name) override {}
|
||||
};
|
||||
|
@ -6,11 +6,11 @@
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
||||
class JsonReader : public Reader {
|
||||
rapidjson::GenericValue<rapidjson::UTF8<>>* m_;
|
||||
std::vector<const char*> path_;
|
||||
rapidjson::GenericValue<rapidjson::UTF8<>> *m_;
|
||||
std::vector<const char *> path_;
|
||||
|
||||
public:
|
||||
JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>>* m) : m_(m) {}
|
||||
public:
|
||||
JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>> *m) : m_(m) {}
|
||||
SerializeFormat Format() const override { return SerializeFormat::Json; }
|
||||
|
||||
bool IsBool() override { return m_->IsBool(); }
|
||||
@ -29,20 +29,20 @@ class JsonReader : public Reader {
|
||||
uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); }
|
||||
uint64_t GetUInt64() override { return m_->GetUint64(); }
|
||||
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); }
|
||||
std::unique_ptr<Reader> operator[](const char* x) override {
|
||||
auto& sub = (*m_)[x];
|
||||
bool HasMember(const char *x) override { return m_->HasMember(x); }
|
||||
std::unique_ptr<Reader> operator[](const char *x) override {
|
||||
auto &sub = (*m_)[x];
|
||||
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())
|
||||
throw std::invalid_argument("array");
|
||||
// Use "0" to indicate any element for now.
|
||||
path_.push_back("0");
|
||||
for (auto& entry : m_->GetArray()) {
|
||||
for (auto &entry : m_->GetArray()) {
|
||||
auto saved = m_;
|
||||
m_ = &entry;
|
||||
fn(*this);
|
||||
@ -51,7 +51,7 @@ class JsonReader : public Reader {
|
||||
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);
|
||||
auto it = m_->FindMember(name);
|
||||
if (it != m_->MemberEnd()) {
|
||||
@ -65,7 +65,7 @@ class JsonReader : public Reader {
|
||||
|
||||
std::string GetPath() const {
|
||||
std::string ret;
|
||||
for (auto& t : path_) {
|
||||
for (auto &t : path_) {
|
||||
ret += '/';
|
||||
ret += t;
|
||||
}
|
||||
@ -75,10 +75,10 @@ class JsonReader : public Reader {
|
||||
};
|
||||
|
||||
class JsonWriter : public Writer {
|
||||
rapidjson::Writer<rapidjson::StringBuffer>* m_;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> *m_;
|
||||
|
||||
public:
|
||||
JsonWriter(rapidjson::Writer<rapidjson::StringBuffer>* m) : m_(m) {}
|
||||
public:
|
||||
JsonWriter(rapidjson::Writer<rapidjson::StringBuffer> *m) : m_(m) {}
|
||||
SerializeFormat Format() const override { return SerializeFormat::Json; }
|
||||
|
||||
void Null() override { m_->Null(); }
|
||||
@ -89,11 +89,11 @@ class JsonWriter : public Writer {
|
||||
void UInt32(uint32_t x) override { m_->Uint64(x); }
|
||||
void UInt64(uint64_t x) override { m_->Uint64(x); }
|
||||
void Double(double x) override { m_->Double(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) override { m_->String(x); }
|
||||
void String(const char *x, size_t len) override { m_->String(x, len); }
|
||||
void StartArray(size_t) override { m_->StartArray(); }
|
||||
void EndArray() override { m_->EndArray(); }
|
||||
void StartObject() override { m_->StartObject(); }
|
||||
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/writer.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fstream>
|
||||
|
||||
// The 'diff' utility is available and we can use dprintf(3).
|
||||
#if _POSIX_C_SOURCE >= 200809L
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
extern bool gTestOutputMode;
|
||||
|
||||
std::string ToString(const rapidjson::Document& document) {
|
||||
std::string ToString(const rapidjson::Document &document) {
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
writer.SetFormatOptions(
|
||||
@ -45,18 +45,18 @@ struct TextReplacer {
|
||||
|
||||
std::vector<Replacement> replacements;
|
||||
|
||||
std::string Apply(const std::string& content) {
|
||||
std::string Apply(const std::string &content) {
|
||||
std::string result = content;
|
||||
|
||||
for (const Replacement& replacement : replacements) {
|
||||
for (const Replacement &replacement : replacements) {
|
||||
while (true) {
|
||||
size_t idx = result.find(replacement.from);
|
||||
if (idx == std::string::npos)
|
||||
break;
|
||||
|
||||
result.replace(result.begin() + idx,
|
||||
result.begin() + idx + replacement.from.size(),
|
||||
replacement.to);
|
||||
result.begin() + idx + replacement.from.size(),
|
||||
replacement.to);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,11 +65,10 @@ struct TextReplacer {
|
||||
};
|
||||
|
||||
void ParseTestExpectation(
|
||||
const std::string& filename,
|
||||
const std::vector<std::string>& lines_with_endings,
|
||||
TextReplacer* replacer,
|
||||
std::vector<std::string>* flags,
|
||||
std::unordered_map<std::string, std::string>* output_sections) {
|
||||
const std::string &filename,
|
||||
const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
|
||||
std::vector<std::string> *flags,
|
||||
std::unordered_map<std::string, std::string> *output_sections) {
|
||||
// Scan for EXTRA_FLAGS:
|
||||
{
|
||||
bool in_output = false;
|
||||
@ -129,9 +128,9 @@ void ParseTestExpectation(
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTestExpectation(const std::string& filename,
|
||||
const std::string& expectation,
|
||||
const std::string& actual) {
|
||||
void UpdateTestExpectation(const std::string &filename,
|
||||
const std::string &expectation,
|
||||
const std::string &actual) {
|
||||
// Read the entire file into a string.
|
||||
std::ifstream in(filename);
|
||||
std::string str;
|
||||
@ -148,10 +147,8 @@ void UpdateTestExpectation(const std::string& filename,
|
||||
WriteToFile(filename, str);
|
||||
}
|
||||
|
||||
void DiffDocuments(std::string path,
|
||||
std::string path_section,
|
||||
rapidjson::Document& expected,
|
||||
rapidjson::Document& actual) {
|
||||
void DiffDocuments(std::string path, std::string path_section,
|
||||
rapidjson::Document &expected, rapidjson::Document &actual) {
|
||||
std::string joined_actual_output = ToString(actual);
|
||||
std::string joined_expected_output = ToString(expected);
|
||||
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());
|
||||
}
|
||||
|
||||
void VerifySerializeToFrom(IndexFile* file) {
|
||||
void VerifySerializeToFrom(IndexFile *file) {
|
||||
std::string expected = file->ToString();
|
||||
std::string serialized = ccls::Serialize(SerializeFormat::Json, *file);
|
||||
std::unique_ptr<IndexFile> result =
|
||||
@ -199,14 +196,14 @@ void VerifySerializeToFrom(IndexFile* file) {
|
||||
std::string actual = result->ToString();
|
||||
if (expected != actual) {
|
||||
fprintf(stderr, "Serialization failure\n");
|
||||
//assert(false);
|
||||
// assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
std::string FindExpectedOutputForFilename(
|
||||
std::string filename,
|
||||
const std::unordered_map<std::string, std::string>& expected) {
|
||||
for (const auto& entry : expected) {
|
||||
const std::unordered_map<std::string, std::string> &expected) {
|
||||
for (const auto &entry : expected) {
|
||||
if (EndsWith(entry.first, filename))
|
||||
return entry.second;
|
||||
}
|
||||
@ -217,17 +214,17 @@ std::string FindExpectedOutputForFilename(
|
||||
return "{}";
|
||||
}
|
||||
|
||||
IndexFile* FindDbForPathEnding(
|
||||
const std::string& path,
|
||||
const std::vector<std::unique_ptr<IndexFile>>& dbs) {
|
||||
for (auto& db : dbs) {
|
||||
IndexFile *
|
||||
FindDbForPathEnding(const std::string &path,
|
||||
const std::vector<std::unique_ptr<IndexFile>> &dbs) {
|
||||
for (auto &db : dbs) {
|
||||
if (EndsWith(db->path, path))
|
||||
return db.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RunIndexTests(const std::string& filter_path, bool enable_update) {
|
||||
bool RunIndexTests(const std::string &filter_path, bool enable_update) {
|
||||
gTestOutputMode = true;
|
||||
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);
|
||||
GetFilesInFolder(
|
||||
"index_tests", true /*recursive*/, true /*add_folder_to_path*/,
|
||||
[&](const std::string& path) {
|
||||
[&](const std::string &path) {
|
||||
bool is_fail_allowed = false;
|
||||
|
||||
if (EndsWithAny(path, {".m", ".mm"})) {
|
||||
@ -291,13 +288,13 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
|
||||
VFS vfs;
|
||||
auto dbs = ccls::idx::Index(&vfs, "", path, flags, {});
|
||||
|
||||
for (const auto& entry : all_expected_output) {
|
||||
const std::string& expected_path = entry.first;
|
||||
for (const auto &entry : all_expected_output) {
|
||||
const std::string &expected_path = entry.first;
|
||||
std::string expected_output = text_replacer.Apply(entry.second);
|
||||
|
||||
// FIXME: promote to utils, find and remove duplicates (ie,
|
||||
// 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('/');
|
||||
if (last_index == std::string::npos)
|
||||
return path;
|
||||
@ -305,10 +302,10 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
|
||||
};
|
||||
|
||||
// Get output from index operation.
|
||||
IndexFile* db = FindDbForPathEnding(expected_path, dbs);
|
||||
IndexFile *db = FindDbForPathEnding(expected_path, dbs);
|
||||
if (db && !db->diagnostics_.empty()) {
|
||||
printf("For %s\n", path.c_str());
|
||||
for (const lsDiagnostic& diagnostic : db->diagnostics_) {
|
||||
for (const lsDiagnostic &diagnostic : db->diagnostics_) {
|
||||
printf(" ");
|
||||
if (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);
|
||||
puts("\n");
|
||||
if (enable_update) {
|
||||
printf(
|
||||
"[Enter to continue - type u to update test, a to update "
|
||||
"all]");
|
||||
printf("[Enter to continue - type u to update test, a to update "
|
||||
"all]");
|
||||
char c = 'u';
|
||||
if (!update_all) {
|
||||
c = getchar();
|
||||
|
@ -2,4 +2,4 @@
|
||||
|
||||
#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
|
||||
// argument.
|
||||
namespace std {
|
||||
template <typename Lockable>
|
||||
void lock(Lockable& l) {
|
||||
l.lock();
|
||||
}
|
||||
} // namespace std
|
||||
template <typename Lockable> void lock(Lockable &l) { l.lock(); }
|
||||
} // namespace std
|
||||
|
||||
template <typename... Queue>
|
||||
struct MultiQueueLock {
|
||||
template <typename... Queue> struct MultiQueueLock {
|
||||
MultiQueueLock(Queue... lockable) : tuple_{lockable...} { lock(); }
|
||||
~MultiQueueLock() { unlock(); }
|
||||
void lock() { lock_impl(typename std::index_sequence_for<Queue...>{}); }
|
||||
void unlock() { unlock_impl(typename std::index_sequence_for<Queue...>{}); }
|
||||
|
||||
private:
|
||||
template <size_t... Is>
|
||||
void lock_impl(std::index_sequence<Is...>) {
|
||||
private:
|
||||
template <size_t... Is> void lock_impl(std::index_sequence<Is...>) {
|
||||
std::lock(std::get<Is>(tuple_)->mutex_...);
|
||||
}
|
||||
|
||||
template <size_t... Is>
|
||||
void unlock_impl(std::index_sequence<Is...>) {
|
||||
template <size_t... Is> void unlock_impl(std::index_sequence<Is...>) {
|
||||
(void)std::initializer_list<int>{
|
||||
(std::get<Is>(tuple_)->mutex_.unlock(), 0)...};
|
||||
}
|
||||
@ -49,16 +43,15 @@ struct MultiQueueLock {
|
||||
struct MultiQueueWaiter {
|
||||
std::condition_variable_any cv;
|
||||
|
||||
static bool HasState(std::initializer_list<BaseThreadQueue*> queues) {
|
||||
for (BaseThreadQueue* queue : queues) {
|
||||
static bool HasState(std::initializer_list<BaseThreadQueue *> queues) {
|
||||
for (BaseThreadQueue *queue : queues) {
|
||||
if (!queue->IsEmpty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename... BaseThreadQueue>
|
||||
void Wait(BaseThreadQueue... queues) {
|
||||
template <typename... BaseThreadQueue> void Wait(BaseThreadQueue... queues) {
|
||||
MultiQueueLock<BaseThreadQueue...> l(queues...);
|
||||
while (!HasState({queues...}))
|
||||
cv.wait(l);
|
||||
@ -66,21 +59,19 @@ struct MultiQueueWaiter {
|
||||
};
|
||||
|
||||
// A threadsafe-queue. http://stackoverflow.com/a/16075550
|
||||
template <class T>
|
||||
struct ThreadedQueue : public BaseThreadQueue {
|
||||
public:
|
||||
template <class T> struct ThreadedQueue : public BaseThreadQueue {
|
||||
public:
|
||||
ThreadedQueue() {
|
||||
owned_waiter_ = std::make_unique<MultiQueueWaiter>();
|
||||
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.
|
||||
size_t Size() const { return total_count_; }
|
||||
|
||||
// Add an element to the queue.
|
||||
template <void (std::deque<T>::*push)(T&&)>
|
||||
void Push(T&& t, bool priority) {
|
||||
template <void (std::deque<T>::*push)(T &&)> void Push(T &&t, bool priority) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (priority)
|
||||
(priority_.*push)(std::move(t));
|
||||
@ -90,7 +81,7 @@ struct ThreadedQueue : public BaseThreadQueue {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -123,7 +114,7 @@ struct ThreadedQueue : public BaseThreadQueue {
|
||||
waiter_->cv.wait(lock,
|
||||
[&]() { return !priority_.empty() || !queue_.empty(); });
|
||||
|
||||
auto execute = [&](std::deque<T>* q) {
|
||||
auto execute = [&](std::deque<T> *q) {
|
||||
auto val = std::move(q->front());
|
||||
q->pop_front();
|
||||
--total_count_;
|
||||
@ -138,7 +129,7 @@ struct ThreadedQueue : public BaseThreadQueue {
|
||||
// value if the queue is empty.
|
||||
std::optional<T> TryPopFront() {
|
||||
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());
|
||||
q->pop_front();
|
||||
--total_count_;
|
||||
@ -151,21 +142,20 @@ struct ThreadedQueue : public BaseThreadQueue {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void Iterate(Fn fn) {
|
||||
template <typename Fn> void Iterate(Fn fn) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
for (auto& entry : priority_)
|
||||
for (auto &entry : priority_)
|
||||
fn(entry);
|
||||
for (auto& entry : queue_)
|
||||
for (auto &entry : queue_)
|
||||
fn(entry);
|
||||
}
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
private:
|
||||
private:
|
||||
std::atomic<int> total_count_{0};
|
||||
std::deque<T> priority_;
|
||||
std::deque<T> queue_;
|
||||
MultiQueueWaiter* waiter_;
|
||||
MultiQueueWaiter *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 <algorithm>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string.h>
|
||||
#include <unordered_map>
|
||||
using namespace std::placeholders;
|
||||
|
||||
void TrimInPlace(std::string& s) {
|
||||
void TrimInPlace(std::string &s) {
|
||||
auto f = [](char c) { return !isspace(c); };
|
||||
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());
|
||||
@ -34,7 +34,8 @@ uint64_t HashUsr(std::string_view s) {
|
||||
// k is an arbitrary key. Don't change it.
|
||||
const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -52,20 +53,20 @@ bool StartsWith(std::string_view s, std::string_view prefix) {
|
||||
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));
|
||||
}
|
||||
|
||||
bool FindAnyPartial(const std::string& value,
|
||||
const std::vector<std::string>& values) {
|
||||
bool FindAnyPartial(const std::string &value,
|
||||
const std::vector<std::string> &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;
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str,
|
||||
const std::string& delimiter) {
|
||||
std::vector<std::string> SplitString(const std::string &str,
|
||||
const std::string &delimiter) {
|
||||
// http://stackoverflow.com/a/13172514
|
||||
std::vector<std::string> strings;
|
||||
|
||||
@ -82,10 +83,10 @@ std::vector<std::string> SplitString(const std::string& str,
|
||||
return strings;
|
||||
}
|
||||
|
||||
std::string LowerPathIfInsensitive(const std::string& path) {
|
||||
std::string LowerPathIfInsensitive(const std::string &path) {
|
||||
#if defined(_WIN32)
|
||||
std::string ret = path;
|
||||
for (char& c : ret)
|
||||
for (char &c : ret)
|
||||
c = tolower(c);
|
||||
return ret;
|
||||
#else
|
||||
@ -93,14 +94,14 @@ std::string LowerPathIfInsensitive(const std::string& path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnsureEndsInSlash(std::string& path) {
|
||||
void EnsureEndsInSlash(std::string &path) {
|
||||
if (path.empty() || path[path.size() - 1] != '/')
|
||||
path += '/';
|
||||
}
|
||||
|
||||
std::string EscapeFileName(std::string path) {
|
||||
bool slash = path.size() && path.back() == '/';
|
||||
for (char& c : path)
|
||||
for (char &c : path)
|
||||
if (c == '\\' || c == '/' || c == ':')
|
||||
c = '@';
|
||||
if (slash)
|
||||
@ -108,11 +109,12 @@ std::string EscapeFileName(std::string path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
std::optional<std::string> ReadContent(const std::string& filename) {
|
||||
std::optional<std::string> ReadContent(const std::string &filename) {
|
||||
char buf[4096];
|
||||
std::string ret;
|
||||
FILE* f = fopen(filename.c_str(), "rb");
|
||||
if (!f) return {};
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
if (!f)
|
||||
return {};
|
||||
size_t n;
|
||||
while ((n = fread(buf, 1, sizeof buf, f)) > 0)
|
||||
ret.append(buf, n);
|
||||
@ -120,8 +122,8 @@ std::optional<std::string> ReadContent(const std::string& filename) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WriteToFile(const std::string& filename, const std::string& content) {
|
||||
FILE* f = fopen(filename.c_str(), "wb");
|
||||
void WriteToFile(const std::string &filename, const std::string &content) {
|
||||
FILE *f = fopen(filename.c_str(), "wb");
|
||||
if (!f ||
|
||||
(content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) {
|
||||
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);
|
||||
}
|
||||
|
||||
std::optional<int64_t> LastWriteTime(const std::string& filename) {
|
||||
std::optional<int64_t> LastWriteTime(const std::string &filename) {
|
||||
sys::fs::file_status Status;
|
||||
if (sys::fs::status(filename, Status))
|
||||
return {};
|
||||
@ -139,8 +141,7 @@ std::optional<int64_t> LastWriteTime(const std::string& filename) {
|
||||
|
||||
// Find discontinous |search| in |content|.
|
||||
// Return |found| and the count of skipped chars before found.
|
||||
int ReverseSubseqMatch(std::string_view pat,
|
||||
std::string_view text,
|
||||
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
|
||||
int case_sensitivity) {
|
||||
if (case_sensitivity == 1)
|
||||
case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
|
||||
@ -155,6 +156,4 @@ int ReverseSubseqMatch(std::string_view pat,
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string GetDefaultResourceDirectory() {
|
||||
return DEFAULT_RESOURCE_DIRECTORY;
|
||||
}
|
||||
std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; }
|
||||
|
59
src/utils.h
59
src/utils.h
@ -13,7 +13,7 @@ namespace llvm {
|
||||
class StringRef;
|
||||
}
|
||||
|
||||
void TrimInPlace(std::string& s);
|
||||
void TrimInPlace(std::string &s);
|
||||
std::string Trim(std::string 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|.
|
||||
bool StartsWith(std::string_view value, std::string_view start);
|
||||
bool EndsWith(std::string_view value, std::string_view ending);
|
||||
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss);
|
||||
bool FindAnyPartial(const std::string& value,
|
||||
const std::vector<std::string>& values);
|
||||
bool EndsWithAny(std::string_view s, const std::vector<std::string> &ss);
|
||||
bool FindAnyPartial(const std::string &value,
|
||||
const std::vector<std::string> &values);
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str,
|
||||
const std::string& delimiter);
|
||||
std::vector<std::string> SplitString(const std::string &str,
|
||||
const std::string &delimiter);
|
||||
|
||||
std::string LowerPathIfInsensitive(const std::string& path);
|
||||
std::string LowerPathIfInsensitive(const std::string &path);
|
||||
|
||||
template <typename TValues, typename TMap>
|
||||
std::string StringJoinMap(const TValues& values,
|
||||
const TMap& map,
|
||||
const std::string& sep = ", ") {
|
||||
std::string StringJoinMap(const TValues &values, const TMap &map,
|
||||
const std::string &sep = ", ") {
|
||||
std::string result;
|
||||
bool first = true;
|
||||
for (auto& entry : values) {
|
||||
for (auto &entry : values) {
|
||||
if (!first)
|
||||
result += sep;
|
||||
first = false;
|
||||
@ -47,24 +46,23 @@ std::string StringJoinMap(const TValues& values,
|
||||
}
|
||||
|
||||
template <typename TValues>
|
||||
std::string StringJoin(const TValues& values, const std::string& sep = ", ") {
|
||||
return StringJoinMap(values, [](const std::string& entry) { return entry; },
|
||||
std::string StringJoin(const TValues &values, const std::string &sep = ", ") {
|
||||
return StringJoinMap(values, [](const std::string &entry) { return entry; },
|
||||
sep);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// e.g. foo/bar.c => foo_bar.c
|
||||
std::string EscapeFileName(std::string path);
|
||||
|
||||
std::optional<std::string> ReadContent(const std::string& filename);
|
||||
void WriteToFile(const std::string& filename, const std::string& content);
|
||||
std::optional<int64_t> LastWriteTime(const std::string& filename);
|
||||
std::optional<std::string> ReadContent(const std::string &filename);
|
||||
void WriteToFile(const std::string &filename, const std::string &content);
|
||||
std::optional<int64_t> LastWriteTime(const std::string &filename);
|
||||
|
||||
int ReverseSubseqMatch(std::string_view pat,
|
||||
std::string_view text,
|
||||
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
|
||||
int case_sensitivity);
|
||||
|
||||
// http://stackoverflow.com/a/38140932
|
||||
@ -76,25 +74,24 @@ int ReverseSubseqMatch(std::string_view pat,
|
||||
// };
|
||||
// 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>
|
||||
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;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
hash_combine(seed, rest...);
|
||||
}
|
||||
|
||||
#define MAKE_HASHABLE(type, ...) \
|
||||
namespace std { \
|
||||
template <> \
|
||||
struct hash<type> { \
|
||||
std::size_t operator()(const type& t) const { \
|
||||
std::size_t ret = 0; \
|
||||
hash_combine(ret, __VA_ARGS__); \
|
||||
return ret; \
|
||||
} \
|
||||
}; \
|
||||
#define MAKE_HASHABLE(type, ...) \
|
||||
namespace std { \
|
||||
template <> struct hash<type> { \
|
||||
std::size_t operator()(const type &t) const { \
|
||||
std::size_t ret = 0; \
|
||||
hash_combine(ret, __VA_ARGS__); \
|
||||
return ret; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
std::string GetDefaultResourceDirectory();
|
||||
|
@ -17,7 +17,7 @@ constexpr int kMaxDiff = 20;
|
||||
// |kMaxColumnAlignSize|.
|
||||
constexpr int kMaxColumnAlignSize = 200;
|
||||
|
||||
lsPosition GetPositionForOffset(const std::string& content, int offset) {
|
||||
lsPosition GetPositionForOffset(const std::string &content, int offset) {
|
||||
if (offset >= content.size())
|
||||
offset = (int)content.size() - 1;
|
||||
|
||||
@ -32,7 +32,7 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
|
||||
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::istringstream lines(content);
|
||||
std::string line;
|
||||
@ -45,7 +45,7 @@ std::vector<std::string> ToLines(const std::string& content) {
|
||||
// Myers' O(ND) diff algorithm.
|
||||
// Costs: insertion=1, deletion=1, no substitution.
|
||||
// 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);
|
||||
static int v_static[2 * kMaxColumnAlignSize + 2];
|
||||
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)
|
||||
return std::min(abs(la - lb), threshold + 1);
|
||||
|
||||
int* v = v_static + lb;
|
||||
int *v = v_static + lb;
|
||||
v[1] = 0;
|
||||
for (int di = 0; di <= threshold; di++) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ std::vector<int> EditDistanceVector(std::string a, std::string b) {
|
||||
|
||||
// Find matching position of |a[column]| in |b|.
|
||||
// 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;
|
||||
while (head < (int)a.size() && head < (int)b.size() && a[head] == b[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].
|
||||
// By symmetry, this can also be used to find matching index line of a buffer
|
||||
// line.
|
||||
std::optional<int> FindMatchingLine(const std::vector<std::string>& index_lines,
|
||||
const std::vector<int>& index_to_buffer,
|
||||
int line,
|
||||
int* column,
|
||||
const std::vector<std::string>& buffer_lines,
|
||||
bool is_end) {
|
||||
std::optional<int>
|
||||
FindMatchingLine(const std::vector<std::string> &index_lines,
|
||||
const std::vector<int> &index_to_buffer, int line, int *column,
|
||||
const std::vector<std::string> &buffer_lines, bool is_end) {
|
||||
// If this is a confident mapping, returns.
|
||||
if (index_to_buffer[line] >= 0) {
|
||||
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
|
||||
// match (least edit distance).
|
||||
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++) {
|
||||
int dist = MyersDiff(needle, buffer_lines[i], kMaxDiff);
|
||||
if (dist < best_dist) {
|
||||
@ -193,17 +191,17 @@ std::optional<int> FindMatchingLine(const std::vector<std::string>& index_lines,
|
||||
return best;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
WorkingFile::WorkingFile(const std::string& filename,
|
||||
const std::string& buffer_content)
|
||||
WorkingFile::WorkingFile(const std::string &filename,
|
||||
const std::string &buffer_content)
|
||||
: filename(filename), buffer_content(buffer_content) {
|
||||
OnBufferContentUpdated();
|
||||
|
||||
// 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_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.
|
||||
int i = 0;
|
||||
for (auto& line : index_lines) {
|
||||
for (auto &line : index_lines) {
|
||||
uint64_t h = HashUsr(line);
|
||||
auto it = hash_to_unique.find(h);
|
||||
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.
|
||||
i = 0;
|
||||
hash_to_unique.clear();
|
||||
for (auto& line : buffer_lines) {
|
||||
for (auto &line : buffer_lines) {
|
||||
uint64_t h = HashUsr(line);
|
||||
auto it = hash_to_unique.find(h);
|
||||
if (it == hash_to_unique.end()) {
|
||||
@ -300,9 +298,8 @@ void WorkingFile::ComputeLineMapping() {
|
||||
buffer_to_index[index_to_buffer[i]] = i;
|
||||
}
|
||||
|
||||
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line,
|
||||
int* column,
|
||||
bool is_end) {
|
||||
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
|
||||
bool is_end) {
|
||||
if (line < 0 || line >= (int)index_lines.size()) {
|
||||
LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, "
|
||||
<< index_lines.size() << ")) in " << filename;
|
||||
@ -315,9 +312,8 @@ std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line,
|
||||
buffer_lines, is_end);
|
||||
}
|
||||
|
||||
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line,
|
||||
int* column,
|
||||
bool is_end) {
|
||||
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, int *column,
|
||||
bool is_end) {
|
||||
// See GetBufferLineFromIndexLine for additional comments.
|
||||
if (line < 0 || line >= (int)buffer_lines.size())
|
||||
return std::nullopt;
|
||||
@ -329,9 +325,8 @@ std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line,
|
||||
}
|
||||
|
||||
std::string WorkingFile::FindClosestCallNameInBuffer(
|
||||
lsPosition position,
|
||||
int* active_parameter,
|
||||
lsPosition* completion_position) const {
|
||||
lsPosition position, int *active_parameter,
|
||||
lsPosition *completion_position) const {
|
||||
*active_parameter = 0;
|
||||
|
||||
int offset = GetOffsetForPosition(position, buffer_content);
|
||||
@ -378,10 +373,8 @@ std::string WorkingFile::FindClosestCallNameInBuffer(
|
||||
}
|
||||
|
||||
lsPosition WorkingFile::FindStableCompletionSource(
|
||||
lsPosition position,
|
||||
bool* is_global_completion,
|
||||
std::string* existing_completion,
|
||||
lsPosition* replace_end_pos) const {
|
||||
lsPosition position, bool *is_global_completion,
|
||||
std::string *existing_completion, lsPosition *replace_end_pos) const {
|
||||
*is_global_completion = true;
|
||||
|
||||
int start_offset = GetOffsetForPosition(position, buffer_content);
|
||||
@ -410,7 +403,8 @@ lsPosition WorkingFile::FindStableCompletionSource(
|
||||
*replace_end_pos = position;
|
||||
for (int i = start_offset; i < buffer_content.size(); 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.
|
||||
replace_end_pos->character++;
|
||||
}
|
||||
@ -419,41 +413,41 @@ lsPosition WorkingFile::FindStableCompletionSource(
|
||||
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);
|
||||
return GetFileByFilenameNoLock(filename);
|
||||
}
|
||||
|
||||
WorkingFile* WorkingFiles::GetFileByFilenameNoLock(
|
||||
const std::string& filename) {
|
||||
for (auto& file : files) {
|
||||
WorkingFile *
|
||||
WorkingFiles::GetFileByFilenameNoLock(const std::string &filename) {
|
||||
for (auto &file : files) {
|
||||
if (file->filename == filename)
|
||||
return file.get();
|
||||
}
|
||||
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);
|
||||
action();
|
||||
}
|
||||
|
||||
void WorkingFiles::DoActionOnFile(
|
||||
const std::string& filename,
|
||||
const std::function<void(WorkingFile* file)>& action) {
|
||||
const std::string &filename,
|
||||
const std::function<void(WorkingFile *file)> &action) {
|
||||
std::lock_guard<std::mutex> lock(files_mutex);
|
||||
WorkingFile* file = GetFileByFilenameNoLock(filename);
|
||||
WorkingFile *file = GetFileByFilenameNoLock(filename);
|
||||
action(file);
|
||||
}
|
||||
|
||||
WorkingFile* WorkingFiles::OnOpen(const lsTextDocumentItem& open) {
|
||||
WorkingFile *WorkingFiles::OnOpen(const lsTextDocumentItem &open) {
|
||||
std::lock_guard<std::mutex> lock(files_mutex);
|
||||
|
||||
std::string filename = open.uri.GetPath();
|
||||
std::string content = open.text;
|
||||
|
||||
// The file may already be open.
|
||||
if (WorkingFile* file = GetFileByFilenameNoLock(filename)) {
|
||||
if (WorkingFile *file = GetFileByFilenameNoLock(filename)) {
|
||||
file->version = open.version;
|
||||
file->buffer_content = content;
|
||||
file->OnBufferContentUpdated();
|
||||
@ -464,11 +458,11 @@ WorkingFile* WorkingFiles::OnOpen(const lsTextDocumentItem& open) {
|
||||
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::string filename = change.textDocument.uri.GetPath();
|
||||
WorkingFile* file = GetFileByFilenameNoLock(filename);
|
||||
WorkingFile *file = GetFileByFilenameNoLock(filename);
|
||||
if (!file) {
|
||||
LOG_S(WARNING) << "Could not change " << filename
|
||||
<< " because it was not open";
|
||||
@ -479,7 +473,7 @@ void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) {
|
||||
if (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.
|
||||
// See https://github.com/Microsoft/language-server-protocol/issues/9.
|
||||
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::string filename = close.uri.GetPath();
|
||||
@ -516,13 +510,13 @@ void WorkingFiles::OnClose(const lsTextDocumentIdentifier& close) {
|
||||
<< " because it was not open";
|
||||
}
|
||||
|
||||
WorkingFiles::Snapshot WorkingFiles::AsSnapshot(
|
||||
const std::vector<std::string>& filter_paths) {
|
||||
WorkingFiles::Snapshot
|
||||
WorkingFiles::AsSnapshot(const std::vector<std::string> &filter_paths) {
|
||||
std::lock_guard<std::mutex> lock(files_mutex);
|
||||
|
||||
Snapshot result;
|
||||
result.files.reserve(files.size());
|
||||
for (const auto& file : files) {
|
||||
for (const auto &file : files) {
|
||||
if (filter_paths.empty() || FindAnyPartial(file->filename, filter_paths))
|
||||
result.files.push_back({file->filename, file->buffer_content});
|
||||
}
|
||||
|
@ -29,10 +29,10 @@ struct WorkingFile {
|
||||
// lock!
|
||||
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.
|
||||
void SetIndexContent(const std::string& index_content);
|
||||
void SetIndexContent(const std::string &index_content);
|
||||
// This should be called whenever |buffer_content| has changed.
|
||||
void OnBufferContentUpdated();
|
||||
|
||||
@ -40,10 +40,12 @@ struct WorkingFile {
|
||||
// Also resolves |column| if not NULL.
|
||||
// When resolving a range, use is_end = false for begin() and is_end =
|
||||
// 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|.
|
||||
// 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
|
||||
// lex_utils.h/cc
|
||||
@ -53,10 +55,9 @@ struct WorkingFile {
|
||||
//
|
||||
// |completion_position| will be point to a good code completion location to
|
||||
// for fetching signatures.
|
||||
std::string FindClosestCallNameInBuffer(
|
||||
lsPosition position,
|
||||
int* active_parameter,
|
||||
lsPosition* completion_position = nullptr) const;
|
||||
std::string
|
||||
FindClosestCallNameInBuffer(lsPosition position, int *active_parameter,
|
||||
lsPosition *completion_position = nullptr) const;
|
||||
|
||||
// Returns a relatively stable completion position (it jumps back until there
|
||||
// is a non-alphanumeric character).
|
||||
@ -66,11 +67,11 @@ struct WorkingFile {
|
||||
// The out param |existing_completion| is set to any existing completion
|
||||
// content the user has entered.
|
||||
lsPosition FindStableCompletionSource(lsPosition position,
|
||||
bool* is_global_completion,
|
||||
std::string* existing_completion,
|
||||
lsPosition* replace_end_pos) const;
|
||||
bool *is_global_completion,
|
||||
std::string *existing_completion,
|
||||
lsPosition *replace_end_pos) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
// Compute index_to_buffer and buffer_to_index.
|
||||
void ComputeLineMapping();
|
||||
};
|
||||
@ -90,29 +91,29 @@ struct WorkingFiles {
|
||||
//
|
||||
|
||||
// Find the file with the given filename.
|
||||
WorkingFile* GetFileByFilename(const std::string& filename);
|
||||
WorkingFile* GetFileByFilenameNoLock(const std::string& filename);
|
||||
WorkingFile *GetFileByFilename(const std::string &filename);
|
||||
WorkingFile *GetFileByFilenameNoLock(const std::string &filename);
|
||||
|
||||
// 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
|
||||
// lock.
|
||||
void DoActionOnFile(const std::string& filename,
|
||||
const std::function<void(WorkingFile* file)>& action);
|
||||
void DoActionOnFile(const std::string &filename,
|
||||
const std::function<void(WorkingFile *file)> &action);
|
||||
|
||||
WorkingFile* OnOpen(const lsTextDocumentItem& open);
|
||||
void OnChange(const lsTextDocumentDidChangeParams& change);
|
||||
void OnClose(const lsTextDocumentIdentifier& close);
|
||||
WorkingFile *OnOpen(const lsTextDocumentItem &open);
|
||||
void OnChange(const lsTextDocumentDidChangeParams &change);
|
||||
void OnClose(const lsTextDocumentIdentifier &close);
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// invalidated if we resize 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);
|
||||
|
Loading…
Reference in New Issue
Block a user